diff options
author | Jeremy Allison <jra@samba.org> | 2004-07-07 22:46:51 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 10:52:09 -0500 |
commit | 1c5867502a47371e24519ffeb4165c69cab63482 (patch) | |
tree | cb02e1b714da10cbdfede8ec23b0c19b266bd7f4 /source3/passdb | |
parent | b42a10a8ef770b5d26fa703482ab477ad082fd16 (diff) | |
download | samba-1c5867502a47371e24519ffeb4165c69cab63482.tar.gz samba-1c5867502a47371e24519ffeb4165c69cab63482.tar.bz2 samba-1c5867502a47371e24519ffeb4165c69cab63482.zip |
r1388: Adding password history code for ldap backend, based on a patch from
"Jianliang Lu" <j.lu@tiesse.com>. Multi-string attribute changed to
linearised pstring due to ordering issues. A few other changes to
fix race conditions. I will add the tdb backend code next. This code
compiles but has not yet been tested with password history policy
set to greater than zero. Targeted for 3.0.6.
Jeremy.
(This used to be commit dd54b2a3c45e202e504ad69d170eb798da4e6fc9)
Diffstat (limited to 'source3/passdb')
-rw-r--r-- | source3/passdb/pdb_get_set.c | 90 | ||||
-rw-r--r-- | source3/passdb/pdb_ldap.c | 72 | ||||
-rw-r--r-- | source3/passdb/pdb_tdb.c | 1 |
3 files changed, 151 insertions, 12 deletions
diff --git a/source3/passdb/pdb_get_set.c b/source3/passdb/pdb_get_set.c index e69dac524f..4abb951d7b 100644 --- a/source3/passdb/pdb_get_set.c +++ b/source3/passdb/pdb_get_set.c @@ -150,6 +150,19 @@ const uint8* pdb_get_lanman_passwd (const SAM_ACCOUNT *sampass) return (NULL); } +const uint8* pdb_get_pw_history (const SAM_ACCOUNT *sampass, uint32 *current_hist_len) +{ + if (sampass) { + SMB_ASSERT((!sampass->private.nt_pw_his.data) + || ((sampass->private.nt_pw_his.length % NT_HASH_LEN) == 0)); + *current_hist_len = sampass->private.nt_pw_his.length / NT_HASH_LEN; + return ((uint8*)sampass->private.nt_pw_his.data); + } else { + *current_hist_len = 0; + return (NULL); + } +} + /* Return the plaintext password if known. Most of the time it isn't, so don't assume anything magic about this function. @@ -982,6 +995,30 @@ BOOL pdb_set_lanman_passwd (SAM_ACCOUNT *sampass, const uint8 pwd[LM_HASH_LEN], } /********************************************************************* + Set the user's password history hash. historyLen is the number of NT_HASH_LEN + entries to store in the history - this must match the size of the uint8 array + in pwd. +********************************************************************/ + +BOOL pdb_set_pw_history (SAM_ACCOUNT *sampass, const uint8 *pwd, uint32 historyLen, enum pdb_value_state flag) +{ + if (!sampass) + return False; + + if (historyLen && pwd){ + sampass->private.nt_pw_his = data_blob_talloc(sampass->mem_ctx, pwd, historyLen*NT_HASH_LEN); + if (!sampass->private.nt_pw_his.length) { + DEBUG(0, ("pdb_set_pw_history: data_blob_talloc() failed!\n")); + return False; + } + } else { + sampass->private.nt_pw_his = data_blob_talloc(sampass->mem_ctx, NULL, 0); + } + + return pdb_set_init_flags(sampass, PDB_PWHISTORY, flag); +} + +/********************************************************************* Set the user's plaintext password only (base procedure, see helper below) ********************************************************************/ @@ -1133,12 +1170,20 @@ BOOL pdb_set_pass_changed_now (SAM_ACCOUNT *sampass) BOOL pdb_set_plaintext_passwd (SAM_ACCOUNT *sampass, const char *plaintext) { - uchar new_lanman_p16[16]; - uchar new_nt_p16[16]; + uchar new_lanman_p16[LM_HASH_LEN]; + uchar new_nt_p16[NT_HASH_LEN]; + uchar current_ntpw_copy[NT_HASH_LEN]; + uchar *current_ntpw = NULL; if (!sampass || !plaintext) return False; - + + /* Store the current password for history purposes. */ + current_ntpw = (uint8 *)pdb_get_nt_passwd(sampass); + if (current_ntpw) { + memcpy (current_ntpw_copy, current_ntpw, NT_HASH_LEN); + } + /* Calculate the MD4 hash (NT compatible) of the password */ E_md4hash(plaintext, new_nt_p16); @@ -1164,6 +1209,45 @@ BOOL pdb_set_plaintext_passwd (SAM_ACCOUNT *sampass, const char *plaintext) if (!pdb_set_pass_changed_now (sampass)) return False; + /* Store the password history. */ + if (pdb_get_acct_ctrl(sampass) & ACB_NORMAL) { + uchar *pwhistory; + uint32 pwHistLen; + account_policy_get(AP_PASSWORD_HISTORY, &pwHistLen); + if (pwHistLen != 0){ + uint32 current_history_len; + /* We need to make sure we don't have a race condition here - the + account policy history length can change between when the pw_history + was first loaded into the SAM_ACCOUNT struct and now.... JRA. */ + pwhistory = (uchar *)pdb_get_pw_history(sampass, ¤t_history_len); + + if (current_history_len != pwHistLen) { + /* After closing and reopening SAM_ACCOUNT the history + values will sync up. We can't do this here. */ + + /* current_history_len > pwHistLen is not a problem - we + have more history than we need. */ + + if (current_history_len < pwHistLen) { + /* We only have room for current_history_len entries. */ + pwHistLen = current_history_len; + } + } + if (pwhistory && current_ntpw && pwHistLen){ + if (pwHistLen > 1) { + memmove(&pwhistory[NT_HASH_LEN], pwhistory, (pwHistLen -1)*NT_HASH_LEN ); + } + memcpy(pwhistory, current_ntpw_copy, NT_HASH_LEN); + pdb_set_pw_history(sampass, pwhistory, pwHistLen, PDB_CHANGED); + } else { + DEBUG (10,("pdb_get_set.c: pdb_set_plaintext_passwd: pwhistory was NULL!\n")); + } + } else { + /* Set the history length to zero. */ + pdb_set_pw_history(sampass, NULL, 0, PDB_CHANGED); + } + } + return True; } diff --git a/source3/passdb/pdb_ldap.c b/source3/passdb/pdb_ldap.c index d2ee9a2d9d..fed92cea56 100644 --- a/source3/passdb/pdb_ldap.c +++ b/source3/passdb/pdb_ldap.c @@ -81,8 +81,6 @@ #define SAM_ACCOUNT struct sam_passwd #endif -#define MODIFY_TIMESTAMP_STRING "modifyTimestamp" - #include "smbldap.h" struct ldapsam_privates { @@ -301,7 +299,9 @@ static NTSTATUS ldapsam_delete_entry(struct ldapsam_privates *ldap_state, really exist. */ for (attrib = attrs; *attrib != NULL; attrib++) { - if (StrCaseCmp(*attrib, name) == 0) { + if ((StrCaseCmp(*attrib, name) == 0) && + !(StrCaseCmp(*attrib, + get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_MOD_TIMESTAMP)))) { DEBUG(10, ("ldapsam_delete_entry: deleting attribute %s\n", name)); smbldap_set_mod(&mods, LDAP_MOD_DELETE, name, NULL); } @@ -400,8 +400,9 @@ static time_t ldapsam_get_entry_timestamp( pstring temp; struct tm tm; - if (!smbldap_get_single_pstring(ldap_state->smbldap_state->ldap_struct, - entry, MODIFY_TIMESTAMP_STRING, temp)) + if (!smbldap_get_single_pstring(ldap_state->smbldap_state->ldap_struct, entry, + get_userattr_key2string(ldap_state->schema_ver,LDAP_ATTR_MOD_TIMESTAMP), + temp)) return (time_t) 0; strptime(temp, "%Y%m%d%H%M%SZ", &tm); @@ -448,6 +449,7 @@ static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state, uint8 hours[MAX_HOURS_LEN]; pstring temp; LOGIN_CACHE *cache_entry = NULL; + int pwHistLen; /* * do a little initialization @@ -694,6 +696,37 @@ static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state, ZERO_STRUCT(smbntpwd); } + account_policy_get(AP_PASSWORD_HISTORY, &pwHistLen); + if (pwHistLen > 0){ + uint8 *pwhist = NULL; + int i; + + if ((pwhist = malloc(NT_HASH_LEN * pwHistLen)) == NULL){ + DEBUG(0, ("init_sam_from_ldap: malloc failed!\n")); + return False; + } + memset(pwhist, '\0', NT_HASH_LEN * pwHistLen); + + if (!smbldap_get_single_pstring (ldap_state->smbldap_state->ldap_struct, entry, + get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_HISTORY), temp)) { + /* leave as default - zeros */ + } else { + for (i = 0; i < pwHistLen; i++){ + if (!pdb_gethexpwd(&temp[i*32], smbntpwd)) { + break; + } + memset(&temp[i*32], '\0', 32); + memcpy(&pwhist[i*NT_HASH_LEN], smbntpwd, NT_HASH_LEN); + ZERO_STRUCT(smbntpwd); + } + } + if (!pdb_set_pw_history(sampass, pwhist, pwHistLen, PDB_SET)){ + SAFE_FREE(pwhist); + return False; + } + SAFE_FREE(pwhist); + } + if (!smbldap_get_single_pstring (ldap_state->smbldap_state->ldap_struct, entry, get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_ACB_INFO), temp)) { acct_ctrl |= ACB_NORMAL; @@ -781,7 +814,7 @@ static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state, } /********************************************************************** - Initialize SAM_ACCOUNT from an LDAP query. + Initialize the ldap db from a SAM_ACCOUNT. Called on update. (Based on init_buffer_from_sam in pdb_tdb.c) *********************************************************************/ @@ -985,6 +1018,29 @@ static BOOL init_ldap_from_sam (struct ldapsam_privates *ldap_state, } } + if (need_update(sampass, PDB_PWHISTORY)) { + int pwHistLen = 0; + account_policy_get(AP_PASSWORD_HISTORY, &pwHistLen); + if (pwHistLen == 0) { + /* Remove any password history from the LDAP store. */ + pstrcpy(temp, "00000000000000000000000000000000"); + } else { + int i, currHistLen = 0; + const uint8 *pwhist = pdb_get_pw_history(sampass, &currHistLen); + if (pwhist != NULL) { + /* We can only store (sizeof(pstring)-1)/32 password history entries. */ + pwHistLen = MIN(pwHistLen, ((sizeof(temp)-1)/32)); + for (i=0; i< pwHistLen && i < currHistLen; i++) { + pdb_sethexpwd (&temp[i*32], &pwhist[i*NT_HASH_LEN], 0); + DEBUG(100, ("temp=%s\n", temp)); + } + } + } + smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods, + get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_HISTORY), + temp); + } + if (need_update(sampass, PDB_PASSLASTSET)) { slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_last_set_time(sampass)); smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods, @@ -1162,7 +1218,7 @@ static NTSTATUS ldapsam_getsampwnam(struct pdb_methods *my_methods, SAM_ACCOUNT int rc; attr_list = get_userattr_list( ldap_state->schema_ver ); - append_attr(&attr_list, MODIFY_TIMESTAMP_STRING); + append_attr(&attr_list, get_userattr_key2string(ldap_state->schema_ver,LDAP_ATTR_MOD_TIMESTAMP)); rc = ldapsam_search_suffix_by_name(ldap_state, sname, &result, attr_list); free_attr_list( attr_list ); @@ -1208,7 +1264,7 @@ static int ldapsam_get_ldap_user_by_sid(struct ldapsam_privates *ldap_state, switch ( ldap_state->schema_ver ) { case SCHEMAVER_SAMBASAMACCOUNT: attr_list = get_userattr_list(ldap_state->schema_ver); - append_attr(&attr_list, MODIFY_TIMESTAMP_STRING); + append_attr(&attr_list, get_userattr_key2string(ldap_state->schema_ver,LDAP_ATTR_MOD_TIMESTAMP)); rc = ldapsam_search_suffix_by_sid(ldap_state, sid, result, attr_list); free_attr_list( attr_list ); diff --git a/source3/passdb/pdb_tdb.c b/source3/passdb/pdb_tdb.c index 9bfb10c400..2cf7c55049 100644 --- a/source3/passdb/pdb_tdb.c +++ b/source3/passdb/pdb_tdb.c @@ -746,4 +746,3 @@ NTSTATUS pdb_tdbsam_init(void) { return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam); } - |