diff options
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/chgpasswd.c | 85 |
1 files changed, 75 insertions, 10 deletions
diff --git a/source3/smbd/chgpasswd.c b/source3/smbd/chgpasswd.c index ca13a167fb..a1b90c8fed 100644 --- a/source3/smbd/chgpasswd.c +++ b/source3/smbd/chgpasswd.c @@ -933,6 +933,65 @@ static NTSTATUS check_oem_password(const char *user, } /*********************************************************** + This routine takes the given password and checks it against + the password history. Returns True if this password has been + found in the history list. +************************************************************/ + +static BOOL check_passwd_history(SAM_ACCOUNT *sampass, const char *plaintext) +{ + uchar new_nt_p16[NT_HASH_LEN]; + uchar zero_nt_pw[NT_HASH_LEN]; + const uint8 *nt_pw; + const uint8 *pwhistory; + BOOL found = False; + int i, pwHisLen, curr_pwHisLen; + + account_policy_get(AP_PASSWORD_HISTORY, &pwHisLen); + if (pwHisLen == 0) { + return False; + } + + pwhistory = pdb_get_pw_history(sampass, &curr_pwHisLen); + if (!pwhistory || curr_pwHisLen == 0) { + return False; + } + + /* Only examine the minimum of the current history len and + the stored history len. Avoids race conditions. */ + pwHisLen = MIN(pwHisLen,curr_pwHisLen); + + nt_pw = pdb_get_nt_passwd(sampass); + + E_md4hash(plaintext, new_nt_p16); + + if (!memcmp(nt_pw, new_nt_p16, NT_HASH_LEN)) { + DEBUG(10,("check_passwd_history: proposed new password for user %s is the same as the current password !\n", + pdb_get_username(sampass) )); + return True; + } + + dump_data(100, new_nt_p16, NT_HASH_LEN); + dump_data(100, pwhistory, NT_HASH_LEN*pwHisLen); + + memset(zero_nt_pw, '\0', NT_HASH_LEN); + for (i=0; i<pwHisLen; i++) { + if (!memcmp(&pwhistory[i*NT_HASH_LEN], zero_nt_pw, NT_HASH_LEN)) { + /* Ignore zero entries. */ + continue; + } + if (!memcmp(&pwhistory[i*NT_HASH_LEN], new_nt_p16, NT_HASH_LEN)) { + DEBUG(1,("check_passwd_history: proposed new password for user %s found in history list !\n", + pdb_get_username(sampass) )); + found = True; + break; + } + } + + return found; +} + +/*********************************************************** Code to change the oem password. Changes both the lanman and NT hashes. Old_passwd is almost always NULL. NOTE this function is designed to be called as root. Check the old password @@ -941,20 +1000,21 @@ static NTSTATUS check_oem_password(const char *user, NTSTATUS change_oem_password(SAM_ACCOUNT *hnd, char *old_passwd, char *new_passwd, BOOL as_root) { - struct passwd *pass; - BOOL ret; uint32 min_len; + struct passwd *pass = NULL; + const char *username = pdb_get_username(hnd); + time_t can_change_time = pdb_get_pass_can_change_time(hnd); - if (time(NULL) < pdb_get_pass_can_change_time(hnd)) { + if ((can_change_time != 0) && (time(NULL) < can_change_time)) { DEBUG(1, ("user %s cannot change password now, must wait until %s\n", - pdb_get_username(hnd), http_timestring(pdb_get_pass_can_change_time(hnd)))); - return NT_STATUS_PASSWORD_RESTRICTION; + username, http_timestring(can_change_time))); + return NT_STATUS_ACCOUNT_RESTRICTION; } if (account_policy_get(AP_MIN_PASSWORD_LEN, &min_len) && (strlen(new_passwd) < min_len)) { DEBUG(1, ("user %s cannot change password - password too short\n", - pdb_get_username(hnd))); + username)); DEBUGADD(1, (" account policy min password len = %d\n", min_len)); return NT_STATUS_PASSWORD_RESTRICTION; /* return NT_STATUS_PWD_TOO_SHORT; */ @@ -965,14 +1025,19 @@ NTSTATUS change_oem_password(SAM_ACCOUNT *hnd, char *old_passwd, char *new_passw if (strlen(new_passwd) < lp_min_passwd_length()) { /* too short, must be at least MINPASSWDLENGTH */ DEBUG(1, ("Password Change: user %s, New password is shorter than minimum password length = %d\n", - pdb_get_username(hnd), lp_min_passwd_length())); + username, lp_min_passwd_length())); return NT_STATUS_PASSWORD_RESTRICTION; /* return NT_STATUS_PWD_TOO_SHORT; */ } - pass = Get_Pwnam(pdb_get_username(hnd)); + if (check_passwd_history(hnd,new_passwd)) { + return NT_STATUS_PASSWORD_RESTRICTION; + } + + pass = Get_Pwnam(username); if (!pass) { - DEBUG(1, ("check_oem_password: Username does not exist in system !?!\n")); + DEBUG(1, ("check_oem_password: Username %s does not exist in system !?!\n", username)); + return NT_STATUS_ACCESS_DENIED; } /* @@ -988,7 +1053,7 @@ NTSTATUS change_oem_password(SAM_ACCOUNT *hnd, char *old_passwd, char *new_passw */ if(lp_unix_password_sync() && - !chgpasswd(pdb_get_username(hnd), pass, old_passwd, new_passwd, as_root)) { + !chgpasswd(username, pass, old_passwd, new_passwd, as_root)) { return NT_STATUS_ACCESS_DENIED; } |