Commit 1c586750 authored by Jeremy Allison's avatar Jeremy Allison Committed by Gerald (Jerry) Carter
Browse files

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)
parent b42a10a8
Loading
Loading
Loading
Loading
+75 −10
Original line number Diff line number Diff line
@@ -932,6 +932,65 @@ static NTSTATUS check_oem_password(const char *user,
	return NT_STATUS_WRONG_PASSWORD;
}

/***********************************************************
 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.
@@ -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;
	}

Loading