On Wed, 2012-07-11 at 16:40 +0300, Alexander Bokovoy wrote: > On Wed, 11 Jul 2012, Simo Sorce wrote: > >On Wed, 2012-07-11 at 15:41 +0300, Alexander Bokovoy wrote: > >> If users don't have RC4-HMAC key and don't have ipaNTHash set, they > >> can't log in into smbd anyway until they change their password. > > > >Yes the point is that you may have users you do not want to give a > >password to. No need to keep retrying to generate a hash. > > > >> >My idea was that when the ipa trust-add operation is run we execute a > >> >magicregen op for the user that run it. Then we can run a process that > >> >adds ipaNThash via magicregen for all users we want it to. > >> So we get to the same issue of a task run against potentially unbound > >> number of users, including replication interaction. > >> > >> Instead, a scheme with ipasam-based generator would mean we: > >> 1. Fetch the user attributes from LDAP > >> 2. Notice ipaNTHash is missing and not disabled > >> 3. Issue ipaNTHash update request if (2) is true. > >> > >> Maybe we can turn off ipaNTHash from your pre-mod code if there is no > >> RC4-HMAC key and ipaNTHash wasn't set? Password change op will get that > >> overriden, of course. Then we can rely on it in (2) above. > > > >Not sure what you mean by 'turn off ipaNTHash from your pre-mod code'. > Set ipaNTHash value to '0', for example. I.e. not 16 bytes and not > missing. > > > >> If we decide to use it in ipasam, extended operation will be simpliest > >> thing -- contrary to other approaches which would require two LDAP > >> requests. It also allows to return the key in the same go. > > > >True, but it is still required only once per user, in normal course of > >action you should always get the ipaNTHash back. Even in the race > >condition case the worst that can happen is that you fail auth once. > >Given it is not that critical as it can happen only once per user I am > >not sure it is worth optimizing for this case and create a whole new > >extended operation for it. > As per discussion with Simo on IRC, NACK for current approach with > LDAP_MOD_REPLACE, NACK for extended operation as well. > > Please replace LDAP_MOD_REPLACE with LDAP_MOD_ADD detection. smbldap > code in smbd uses LDAP_MOD_DELETE/LDAP_MOD_ADD combination as > replacement of LDAP_MOD_REPLACE to avoid some nasty bugs with Novell > Directory so we have to live with this approach.
Attached patch that changes REPLACE -> ADD > >It still doesn't give you much, there are 2 cases: > > > >1) For users that are supposed to have the ipaNTHash, you will go > >through this operation *once* in the lifetime of a pre-existing user > >(new users get ipaNTHash immediately). > > > >2) For users that will never get the ipaNTHash will simply never have > >it, you only keep repeating this operation and then fail authentication > >as you won't get back a valid hash, I do not think optimizing this > >failure case is worth a full extop. > My point was to get pre-mod code to set ipaNTHash to invalid (non-16 > byte) value to signify that they are 'disabled' for NTLM operations. > This way I can get ipaNTHash on user fetch but can locally detect that > the user is without password and therefore avoid the whole process. Do you still want to do this ? We could store the value 'DISABLED' instead of the hash, but then I'd have to change the password plugin to respect it. If you want that I think we need to open a new bug and treat it as a separate feature. Simo. -- Simo Sorce * Red Hat, Inc * New York
>From 84ef09a1193ff42fc301fb71354055c5039f51a5 Mon Sep 17 00:00:00 2001 From: Simo Sorce <sso...@redhat.com> Date: Fri, 6 Jul 2012 16:18:29 -0400 Subject: [PATCH] Add special modify op to regen ipaNTHash The NT Hash is the same thing as the RC4-HMAC key, so we add a function to extract it from krb5 keys if they are available to avoid forcing a password change when configuring trust relationships. --- .../ipa-pwd-extop/ipapwd_prepost.c | 147 +++++++++++++++++++- 1 file changed, 144 insertions(+), 3 deletions(-) diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_prepost.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_prepost.c index deae6477772f82edcc4674a1c9580661c3dae94b..24fa52eb9ac92004576ccdba4f576162c358770d 100644 --- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_prepost.c +++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_prepost.c @@ -41,7 +41,12 @@ # include <config.h> #endif -#define _XOPEN_SOURCE /* strptime needs this */ +/* strptime needs _XOPEN_SOURCE and endian.h needs __USE_BSD + * _GNU_SOURCE imply both, and we use it elsewhere, so use this */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + #include <stdio.h> #include <string.h> #include <strings.h> @@ -53,6 +58,7 @@ #include <dirsrv/slapi-plugin.h> #include <lber.h> #include <time.h> +#include <endian.h> #include "ipapwd.h" #include "util.h" @@ -379,6 +385,12 @@ done: return 0; } +#define NTHASH_REGEN_VAL "MagicRegen" +#define NTHASH_REGEN_LEN sizeof(NTHASH_REGEN_VAL) +static int ipapwd_regen_nthash(Slapi_PBlock *pb, Slapi_Mods *smods, + char *dn, struct slapi_entry *entry, + struct ipapwd_krbcfg *krbcfg); + /* PRE MOD Operation: * Gets the clean text password (fail the operation if the password came * pre-hashed, unless this is a replicated operation). @@ -407,6 +419,7 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb) int has_krb_keys = 0; int has_history = 0; int gen_krb_keys = 0; + int is_magic_regen = 0; int ret, rc; LOG_TRACE( "=>\n"); @@ -447,6 +460,27 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb) default: break; } + } else if (slapi_attr_types_equivalent(lmod->mod_type, "ipaNTHash")) { + /* check op filtering out LDAP_MOD_BVALUES */ + switch (lmod->mod_op & 0x0f) { + case LDAP_MOD_REPLACE: + if (!lmod->mod_bvalues || + !lmod->mod_bvalues[0]) { + rc = LDAP_OPERATIONS_ERROR; + goto done; + } + bv = lmod->mod_bvalues[0]; + if ((bv->bv_len >= NTHASH_REGEN_LEN -1) && + (bv->bv_len <= NTHASH_REGEN_LEN) && + (strncmp(NTHASH_REGEN_VAL, + bv->bv_val, bv->bv_len) == 0)) { + is_magic_regen = 1; + /* make sure the database will later ignore this mod */ + slapi_mods_remove(smods); + } + default: + break; + } } else if (slapi_attr_types_equivalent(lmod->mod_type, "unhashed#user#password")) { /* we check for unahsehd password here so that we are sure to @@ -472,8 +506,9 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb) lmod = slapi_mods_get_next_mod(smods); } - /* If userPassword is not modified we are done here */ - if (! is_pwd_op) { + /* If userPassword is not modified check if this is a request to generate + * NT hashes otherwise we are done here */ + if (!is_pwd_op && !is_magic_regen) { rc = LDAP_SUCCESS; goto done; } @@ -522,6 +557,22 @@ static int ipapwd_pre_mod(Slapi_PBlock *pb) goto done; } + if (!is_pwd_op) { + /* This may be a magic op to ask us to generate the NT hashes */ + if (is_magic_regen) { + /* Make sense to call only if this entry has krb keys to source + * the nthash from */ + if (is_krb) { + rc = ipapwd_regen_nthash(pb, smods, dn, e, krbcfg); + } else { + rc = LDAP_UNWILLING_TO_PERFORM; + } + } else { + rc = LDAP_OPERATIONS_ERROR; + } + goto done; + } + /* run through the mods again and adjust flags if operations affect them */ lmod = slapi_mods_get_first_mod(smods); while (lmod) { @@ -831,6 +882,96 @@ done: return 0; } +static int ipapwd_regen_nthash(Slapi_PBlock *pb, Slapi_Mods *smods, + char *dn, struct slapi_entry *entry, + struct ipapwd_krbcfg *krbcfg) +{ + Slapi_Attr *attr; + Slapi_Value *value; + const struct berval *val; + struct berval *ntvals[2] = { NULL, NULL }; + struct berval bval; + krb5_key_data *keys; + int num_keys; + int mkvno; + int ret; + int i; + + ret = slapi_entry_attr_find(entry, "ipaNTHash", &attr); + if (ret == 0) { + /* We refuse to regen if there is already a value */ + return LDAP_CONSTRAINT_VIOLATION; + } + + /* ok let's see if we can find the RC4 hash in the keys */ + ret = slapi_entry_attr_find(entry, "krbPrincipalKey", &attr); + if (ret) { + return LDAP_UNWILLING_TO_PERFORM; + } + + ret = slapi_attr_first_value(attr, &value); + if (ret) { + return LDAP_OPERATIONS_ERROR; + } + + val = slapi_value_get_berval(value); + if (!val) { + return LDAP_OPERATIONS_ERROR; + } + + ret = ber_decode_krb5_key_data((struct berval *)val, + &mkvno, &num_keys, &keys); + if (ret) { + return LDAP_OPERATIONS_ERROR; + } + + ret = LDAP_UNWILLING_TO_PERFORM; + + for (i = 0; i < num_keys; i++) { + char nthash[16]; + krb5_enc_data cipher; + krb5_data plain; + krb5_int16 t; + + if (keys[i].key_data_type[0] != ENCTYPE_ARCFOUR_HMAC) { + continue; + } + + memcpy(&t, keys[i].key_data_contents[0], 2); + plain.length = le16toh(t); + if (plain.length != 16) { + continue; + } + plain.data = nthash; + + memset(&cipher, 0, sizeof(krb5_enc_data)); + cipher.enctype = krbcfg->kmkey->enctype; + cipher.ciphertext.length = keys[i].key_data_length[0] - 2; + cipher.ciphertext.data = ((char *)keys[i].key_data_contents[0]) + 2; + + ret = krb5_c_decrypt(krbcfg->krbctx, krbcfg->kmkey, + 0, NULL, &cipher, &plain); + if (ret) { + ret = LDAP_OPERATIONS_ERROR; + break; + } + + bval.bv_val = nthash; + bval.bv_len = 16; + ntvals[0] = &bval; + + slapi_mods_add_modbvps(smods, LDAP_MOD_REPLACE, + "ipaNTHash", ntvals); + + ret = LDAP_SUCCESS; + break; + } + + ipa_krb5_free_key_data(keys, num_keys); + + return ret; +} + static int ipapwd_post_op(Slapi_PBlock *pb) { void *op; -- 1.7.10.4
_______________________________________________ Freeipa-devel mailing list Freeipa-devel@redhat.com https://www.redhat.com/mailman/listinfo/freeipa-devel