summaryrefslogtreecommitdiffstats
path: root/source/smbd/chgpasswd.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/smbd/chgpasswd.c')
-rw-r--r--source/smbd/chgpasswd.c85
1 files changed, 75 insertions, 10 deletions
diff --git a/source/smbd/chgpasswd.c b/source/smbd/chgpasswd.c
index ca13a167fb0..a1b90c8fed4 100644
--- a/source/smbd/chgpasswd.c
+++ b/source/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;
}