Implementation of Password Policy on Samba3.0 a22, and other patches...

Jianliang Lu j.lu at tiesse.com
Tue May 6 16:19:29 GMT 2003


Implementation of password policy on Samba3.0 alpha22

Copyright (C) Jianliang Lu 	2003. 
Written by Jianliang Lu  <j.lu at tiesse.com> <luj at libero.it>

This program is free software; you can redistribute it and/or modify
it under the terms of GNU General Public License version 2 as
published by the Free Software Foundation.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICOLAR PURPOSE. See the GNU 
General Public License for more details.


Following are the descriptions of the implementations of password 
policy on Samba 3.0 alpha22 with LDAP backend. The patches are 
attached in the end.


 - Password policy for "Minimum Password Age":
   The period of time a password must be kept before the user can change 
   it. Do not allow immediate changes if a password history value will 
   be entered. The "Minimum Password Age" must be less than the 
   "Maximum Password Age".

   To set the "Minimum Password Age" you can use:
      pdbedit -P ""minimum password age" -V value
      where value are expressed in seconds.

   The pacth was made in passdb/pdb_get_set.c

 - Password policy for "bad Password Attempt lockout"
   The number of incorrect logon attempts that will cause the account to 
   be locked, except the members of "Domain Admins".   
   To set the "bad Password Attempt lockout":
      pdbedit -P "bad lockout attempt" -V value.

   To implement this function I have to extend the samba.schema of LDAP 
   that include a new integer SINGLE-VALUE attribute 'badPwAttempt'. 
   The implementations were mainly made in passdb/pdb_ldap.c

 - Password policy for "Password History", or "Password Uniqueness":
   The number of new passwords that must be used by a user before an old 
   password can be reused. For uniqueness to be effective, immediate 
   changes should not be allowed by the "Minimum Password Age" parameter.
   To set "Password History":
      pdbedit -P "password history" -V value

   To implement this function, a new ASCII string MULTIVALUE attribute 
   'pwHistory' was added in the samba.schema. The implementations were 
   mainly made in passdb/pdb_ldap.c
	
 - Set and reset the "Password must change time"
   If selected, users must change (their own) passwords before they logon. 
   If cleared, users can logon without change their passwords.
   To select or clear:
      pdbedit -A value -u user, where value = 1 to select, 0 to clear.
      or:
      smbldap-usermod.pl -A value user

 - Set and reset the "Password can change time"
   If selected, users cannot change (their own) passwords (if the 
   "Password must change time" is not selected). If cleared, users can 
   change their own passwords.
   To select or clear:
      pdbedit -B value -u user, where value = 1 to select, 0 to clear.
      or:
      smbldap-usermod.pl -B value user

 - Reset the "bad Password attempt count"
   Clear the "bad Password Attempt lockout" count.
   To reset the count:
      pdbedit -z -u user

 - Logon time:
   The user's recent successful logon time. The patch was made in 
   auth/auth_sam.c. 
   To see the user's logon time:
      pdbedit -u user -v
      or
      smbldap-usershow.pl user



Jianliang Lu
TieSse s.p.a.
Via Jervis, 60.  10015 Ivrea (To) - Italy
j.lu at tiesse.com
luj at libero.it
-------------- next part --------------
--- /source/auth/auth_sam.c	Mon Feb 17 16:31:06 2003
+++ /source/auth/auth_sam.c.fix	Tue May  6 11:14:55 2003
@@ -326,6 +326,12 @@
 		return NT_STATUS_ACCOUNT_DISABLED;
 	}
 
+	/* Quit if the account was locked out. */
+	if (acct_ctrl & ACB_AUTOLOCK) {
+		DEBUG(1,("Account for user '%s' was locked out.\n", pdb_get_username(sampass)));
+		return NT_STATUS_ACCOUNT_LOCKED_OUT;
+	}
+
 	/* Test account expire time */
 	
 	kickoff_time = pdb_get_kickoff_time(sampass);
@@ -414,6 +420,9 @@
 	NTSTATUS nt_status;
 	uint8 user_sess_key[16];
 	const uint8* lm_hash;
+	uint32 account_policy_lockout, badpwattempt;
+	GROUP_MAP map;
+	pstring grname;
 
 	if (!user_info || !auth_context) {
 		return NT_STATUS_UNSUCCESSFUL;
@@ -448,10 +457,51 @@
 	nt_status = sam_password_ok(auth_context, mem_ctx, sampass, user_info, user_sess_key);
 
 	if (!NT_STATUS_IS_OK(nt_status)) {
+		if (NT_STATUS_EQUAL(nt_status,NT_STATUS_WRONG_PASSWORD) && pdb_get_acct_ctrl(sampass) &ACB_NORMAL) {     	
+			badpwattempt = (uint32)pdb_get_bad_pw_attempt(sampass) + 1;
+			if (!pdb_set_bad_pw_attempt(sampass, badpwattempt, PDB_CHANGED))
+					DEBUG(1, ("Failed to set 'badPwAttempt' for user % s. \n", 
+								 user_info->internal_username.str));
+		 	account_policy_get(AP_BAD_ATTEMPT_LOCKOUT, &account_policy_lockout);
+			if (!pdb_getgrnam(&map, "Domain Admins", MAPPING_WITHOUT_PRIV))
+				DEBUG(1, ("auth_sam.c: Failed to get groupmap for Domain Admins"));
+			pstrcpy(grname, gidtoname(map.gid));
+/*
+			if ((badpwattempt >= account_policy_lockout) && !user_in_list(user_info->internal_username.str, lp_admin_users(-1), NULL, 0) && !user_in_group_list(user_info->internal_username.str, gidtoname(map.gid), NULL, 0))
+*/
+			if (account_policy_lockout && (badpwattempt >= account_policy_lockout) && !user_in_group_list(user_info->internal_username.str, grname, NULL, 0))
+				if (!pdb_set_acct_ctrl (sampass, 
+										pdb_get_acct_ctrl(sampass) |ACB_AUTOLOCK, 
+										PDB_CHANGED)) {
+					DEBUG(1, ("Failed to set 'disabled' flag for user % s. \n", 
+								 user_info->internal_username.str));
+			    }
+
+			become_root();
+			if (!pdb_update_sam_account(sampass)) {
+		    	DEBUG(1, ("Failed to modify entry for user % s.\n", 
+							 user_info->internal_username.str));
+			unbecome_root();
+            }
+		}
 		pdb_free_sam(&sampass);
 		return nt_status;
 	}
 
+	if (pdb_get_acct_ctrl(sampass) &ACB_NORMAL){
+		if (!pdb_set_bad_pw_attempt(sampass, 0, PDB_CHANGED))
+				DEBUG(1, ("Failed to set 'badPwAttempt' for user % s. \n", 
+							 user_info->internal_username.str));
+		if (!pdb_set_logon_time(sampass, time(NULL), PDB_CHANGED))
+	   	     DEBUG(1, ("auth_sam.c : pdb_set_logon_time fialed!\n"));
+
+		become_root();
+		if(!pdb_update_sam_account(sampass)) 
+	   		 	DEBUG(1, ("Failed to modify entry for user % s.\n", 
+						 user_info->internal_username.str));
+		unbecome_root();
+	}
+
 	if (!NT_STATUS_IS_OK(nt_status = make_server_info_sam(server_info, sampass))) {		
 		DEBUG(0,("check_sam_security: make_server_info_sam() failed with '%s'\n", nt_errstr(nt_status)));
 		return nt_status;
-------------- next part --------------
--- /source/passdb/passdb.c	Mon Feb 24 16:12:31 2003
+++ /source/passdb/passdb.c.fix	Tue May  6 11:14:55 2003
@@ -60,6 +60,7 @@
 	memset(user->private.hours, 0xff, user->private.hours_len); /* available at all hours */
 	user->private.unknown_5 = 0x00000000; /* don't know */
 	user->private.unknown_6 = 0x000004ec; /* don't know */
+	user->private.bad_pw_attempt = 0; /* bad password attemp count */
 
 	/* Some parts of samba strlen their pdb_get...() returns, 
 	   so this keeps the interface unchanged for now. */
@@ -1127,6 +1128,11 @@
 	}	
 
 	if (local_flags & LOCAL_ADD_USER) {
+		if (!pdb_set_pass_must_change_time (sam_pass, 0, PDB_CHANGED)) {
+			slprintf(err_str, err_str_len-1, "Failed to set must change time for user %s.\n", user_name);
+			pdb_free_sam(&sam_pass);
+			return False;
+		}
 		if (pdb_add_sam_account(sam_pass)) {
 			slprintf(msg_str, msg_str_len-1, "Added user %s.\n", user_name);
 			pdb_free_sam(&sam_pass);
-------------- next part --------------
--- /source/passdb/pdb_get_set.c	Thu Jan  9 20:05:59 2003
+++ /source/passdb/pdb_get_set.c.fix	Tue May  6 11:14:55 2003
@@ -131,6 +131,15 @@
 		return (NULL);
 }
 
+const uint8* pdb_get_pw_history (const SAM_ACCOUNT *sampass)
+{
+	if (sampass) {
+		return ((uint8*)sampass->private.nt_pw_his);
+	}
+	else
+		return (NULL);
+}
+
 const uint8* pdb_get_lanman_passwd (const SAM_ACCOUNT *sampass)
 {
 	if (sampass) {
@@ -172,6 +181,14 @@
 		return (NULL);
 }	
 
+uint32 pdb_get_bad_pw_attempt (const SAM_ACCOUNT *sampass)
+{
+	if (sampass)
+		return (sampass->private.bad_pw_attempt);
+	else
+		return (-1);
+}
+
 /**
  * Get flags showing what is initalised in the SAM_ACCOUNT
  * @param sampass the SAM_ACCOUNT in question
@@ -964,6 +981,31 @@
 	return pdb_set_init_flags(sampass, PDB_NTPASSWD, flag);
 }
 
+
+/*********************************************************************
+ Set the user's password history hash.
+ ********************************************************************/
+
+BOOL pdb_set_pw_history (SAM_ACCOUNT *sampass, const uint8 * pwd, int historyLen, enum pdb_value_state flag)
+{
+	if (!sampass)
+		return False;
+	
+	if (historyLen > 0){
+		if (pwd){
+			sampass->private.nt_pw_his = (uint *) talloc_memdup(sampass->mem_ctx, pwd, historyLen*16);
+			if (!sampass->private.nt_pw_his) {
+				DEBUG(0, ("pdb_set_nt_pw_his: talloc_memdup() failed!\n"));
+				return False;
+			}
+		}else {
+			sampass->private.nt_pw_his = NULL;
+		}
+	}
+
+	return pdb_set_init_flags(sampass, PDB_PWHISTORY, flag);
+}
+
 /*********************************************************************
  Set the user's LM hash.
  ********************************************************************/
@@ -1038,6 +1080,16 @@
 	return pdb_set_init_flags(sampass, PDB_UNKNOWN6, flag);
 }
 
+BOOL pdb_set_bad_pw_attempt (SAM_ACCOUNT *sampass, uint32 badpwattempt, enum pdb_value_state flag)
+{
+	if (!sampass)
+		return False;
+
+	sampass->private.bad_pw_attempt = badpwattempt;
+
+	return pdb_set_init_flags(sampass, PDB_BADPWATTEMPT, flag);
+}
+
 BOOL pdb_set_hours (SAM_ACCOUNT *sampass, const uint8 *hours, enum pdb_value_state flag)
 {
 	if (!sampass)
@@ -1064,6 +1116,7 @@
 BOOL pdb_set_pass_changed_now (SAM_ACCOUNT *sampass)
 {
 	uint32 expire;
+	uint32 min_age;
 
 	if (!sampass)
 		return False;
@@ -1071,17 +1124,29 @@
 	if (!pdb_set_pass_last_set_time (sampass, time(NULL), PDB_CHANGED))
 		return False;
 
-	if (!account_policy_get(AP_MAX_PASSWORD_AGE, &expire) 
-	    || (expire==(uint32)-1)) {
-		if (!pdb_set_pass_must_change_time (sampass, get_time_t_max(), PDB_CHANGED))
-			return False;
-	} else {
-		if (!pdb_set_pass_must_change_time (sampass, 
-						    pdb_get_pass_last_set_time(sampass)
-						    + expire, PDB_CHANGED))
-			return False;
-	}
+	if (pdb_get_acct_ctrl(sampass)&(ACB_NORMAL)){ 
+		if (!account_policy_get(AP_MAX_PASSWORD_AGE, &expire) 
+		    || (expire==(uint32)-1)) {
+			if (!pdb_set_pass_must_change_time (sampass, get_time_t_max(), PDB_CHANGED))
+				return False;
+		} else {
+			if (!pdb_set_pass_must_change_time (sampass, 
+							    pdb_get_pass_last_set_time(sampass)
+							    + expire, PDB_CHANGED))
+				return False;
+		}
 	
+		if (!account_policy_get(AP_MIN_PASSWORD_AGE, &min_age) 
+		    || (min_age==(uint32)-1)) {
+			if (!pdb_set_pass_can_change_time (sampass, 0, PDB_CHANGED))
+				return False;
+		} else {
+			if (!pdb_set_pass_can_change_time (sampass, 
+							    pdb_get_pass_last_set_time(sampass)
+							    + min_age, PDB_CHANGED))
+				return False;
+		}
+	}
 	return True;
 }
 
@@ -1094,10 +1159,19 @@
 {
 	uchar new_lanman_p16[16];
 	uchar new_nt_p16[16];
+	uchar *pwhistory;
+	uchar nt_pw[16];
+	uchar * ntpw;
+	int pwHistLen;
+
 
 	if (!sampass || !plaintext)
 		return False;
-	
+
+	ntpw = pdb_get_nt_passwd(sampass);
+	if (ntpw)
+		memcpy ((uchar *)nt_pw, (uchar *)ntpw, 16);
+
 	nt_lm_owf_gen (plaintext, new_nt_p16, new_lanman_p16);
 
 	if (!pdb_set_nt_passwd (sampass, new_nt_p16, PDB_CHANGED)) 
@@ -1112,5 +1186,19 @@
 	if (!pdb_set_pass_changed_now (sampass))
 		return False;
 
+	if (pdb_get_acct_ctrl(sampass) & ACB_NORMAL) { 
+		account_policy_get(AP_PASSWORD_HISTORY, &pwHistLen);
+			if (pwHistLen > 0){
+			pwhistory = pdb_get_pw_history (sampass);
+			if (pwhistory){
+				memmove((uchar *) (pwhistory + 16), pwhistory, (pwHistLen -1)*16 );
+				memcpy((uchar *)pwhistory, (uchar *)nt_pw, 16);
+				pdb_set_pw_history (sampass, pwhistory, pwHistLen, PDB_CHANGED);
+			}
+			else {
+				DEBUG (100,("pdb_get_set.c: pdb_set_plaintext_passwd: pwhistory was NULL!\n"));
+			}
+		}
+	}
 	return True;
 }
-------------- next part --------------
--- /source/passdb/pdb_ldap.c	Thu Mar 13 12:27:01 2003
+++ /source/passdb/pdb_ldap.c.fix	Tue May  6 11:14:55 2003
@@ -149,11 +149,11 @@
 			     "logoffTime", "kickoffTime", "cn",
 			     "pwdCanChange", "pwdMustChange",
 			     "displayName", "homeDrive",
-			     "smbHome", "scriptPath",
+			     "smbHome", "scriptPath", "badPwAttempt",
 			     "profilePath", "description",
 			     "userWorkstations", "rid",
 			     "primaryGroupID", "lmPassword",
-			     "ntPassword", "acctFlags",
+			     "ntPassword", "acctFlags", "pwHistory",
 			     "domain", "objectClass", 
 			     "uidNumber", "gidNumber", 
 			     "homeDirectory", NULL };
@@ -770,6 +770,31 @@
 	return True;
 }
 
+/*******************************************************************
+search an attribute and return the value found.
+******************************************************************/
+static BOOL get_single_attribute_multivalue (LDAP * ldap_struct, LDAPMessage * entry,
+				  const char *attribute, char *value, int len, int * count)
+{
+	char **values;
+	int i;
+
+	if ((values = ldap_get_values (ldap_struct, entry, attribute)) == NULL) {
+		value = NULL;
+		DEBUG (10, ("get_single_attribute_multivalue: [%s] = [<does not exist>]\n", attribute));
+		return False;
+	}
+	
+	for (i = 0; (values[i] != NULL) && (i < len); i++)
+		pstrcpy((char *) (value + i*sizeof(pstring)), values[i]);
+	*count = i;
+	ldap_value_free(values);
+#ifdef DEBUG_PASSWORDS
+	DEBUG (100, ("get_single_attribute_multivalue: [%s] = [%s]\n", attribute, value));
+#endif	
+	return True;
+}
+
 /************************************************************************
 Routine to manage the LDAPMod structure array
 manage memory used by the array, by each struct, and values
@@ -927,7 +952,8 @@
 			workstations;
 	struct passwd	*pw;
 	uint32 		user_rid, 
-			group_rid;
+			group_rid,
+			badpwattempt;
 	uint8 		smblmpwd[LM_HASH_LEN],
 			smbntpwd[NT_HASH_LEN];
 	uint16 		acct_ctrl = 0, 
@@ -937,7 +963,9 @@
 	pstring temp;
 	uid_t		uid = -1;
 	gid_t 		gid = getegid();
-
+    char    *temp1;
+	uint8   *pwhist;
+	int     i, pwcount, pwHistLen;
 
 	/*
 	 * do a little initialization
@@ -980,6 +1008,7 @@
 	get_single_attribute(ldap_state->ldap_struct, entry, "rid", temp);
 	user_rid = (uint32)atol(temp);
 
+
 	pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
 
 	if (!get_single_attribute(ldap_state->ldap_struct, entry, "primaryGroupID", temp)) {
@@ -1037,6 +1066,12 @@
 		pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
 	}
 
+	if (!get_single_attribute(ldap_state->ldap_struct, entry, "badPwAttempt", temp)) {
+		/* leave as default */
+	} else {
+		badpwattempt = (uint32)atol(temp);
+		pdb_set_bad_pw_attempt(sampass, badpwattempt, PDB_SET);
+	}
 	if (!get_single_attribute(ldap_state->ldap_struct, entry, "logonTime", temp)) {
 		/* leave as default */
 	} else {
@@ -1166,6 +1201,32 @@
 		ZERO_STRUCT(smbntpwd);
 	}
 
+	account_policy_get(AP_PASSWORD_HISTORY, &pwHistLen);
+	if (pwHistLen > 0){
+		if ((temp1 = (char  *) malloc(sizeof(pstring) * pwHistLen)) == NULL) {
+			DEBUG(0, ("pdb_ldap.c: init_sam_from_ldap: malloc failed!\n"));
+			return False;
+		}
+		if ((pwhist = (uint8 *) malloc(16 * pwHistLen)) == NULL){
+			DEBUG(0, ("pdb_ldap.c: init_sam_from_ldap: malloc failed!\n"));
+			return False;
+		}
+		memset((uint8 *) pwhist, 0, 16*pwHistLen);
+		if (!get_single_attribute_multivalue (ldap_state->ldap_struct, entry, "pwHistory", temp1, pwHistLen, &pwcount)) {
+			/* leave as default */
+		} else {
+			for (i = 0; (i < pwHistLen) && (i < pwcount); i++){
+				pdb_gethexpwd((char *)(temp1 + i*sizeof(pstring)), smbntpwd);
+				memcpy((unsigned char *) (pwhist + i*16), smbntpwd, 16);
+				ZERO_STRUCT(smbntpwd);
+			}
+		}
+		if (!pdb_set_pw_history(sampass, pwhist, pwHistLen, PDB_SET))
+			return False;
+		SAFE_FREE (temp1);
+		SAFE_FREE (pwhist);
+	}
+
 	if (!get_single_attribute (ldap_state->ldap_struct, entry, "acctFlags", temp)) {
 		acct_ctrl |= ACB_NORMAL;
 	} else {
@@ -1210,6 +1271,8 @@
 {
 	pstring temp;
 	uint32 rid;
+	uint8 * temp1;
+	int	i, pwHistLen;
 
 	if (mods == NULL || sampass == NULL) {
 		DEBUG(0, ("init_ldap_from_sam: NULL parameters found!\n"));
@@ -1309,6 +1372,11 @@
 		make_a_mod(mods, ldap_op, "logonTime", temp);
 	}
 
+	if (need_ldap_mod(pdb_add, sampass, PDB_BADPWATTEMPT)) {
+		slprintf(temp, sizeof(temp) - 1, "%i", pdb_get_bad_pw_attempt(sampass));
+		make_a_mod(mods, ldap_op, "badPwAttempt", temp);
+	}
+
 	if (need_ldap_mod(pdb_add, sampass, PDB_LOGOFFTIME)) {
 		slprintf(temp, sizeof(temp) - 1, "%li", pdb_get_logoff_time(sampass));
 		make_a_mod(mods, ldap_op, "logoffTime", temp);
@@ -1342,6 +1410,18 @@
 			pdb_sethexpwd (temp, pdb_get_nt_passwd(sampass), pdb_get_acct_ctrl(sampass));
 			make_a_mod (mods, ldap_op, "ntPassword", temp);
 		}
+
+		if (need_ldap_mod(pdb_add, sampass, PDB_PWHISTORY)) {
+			account_policy_get(AP_PASSWORD_HISTORY, &pwHistLen);
+			temp1 = (uint8 *) pdb_get_pw_history(sampass);
+			if (temp1 != NULL)
+				for (i=0; i< pwHistLen; i++){
+					pdb_sethexpwd (temp, (uint8 *)(temp1 + i*16), 0);
+					if (!strncmp(temp,"0000000000",10))
+						break;
+					make_a_mod (mods, ldap_op, "pwHistory", temp);
+				}
+		}
 		
 		if (need_ldap_mod(pdb_add, sampass, PDB_PASSLASTSET)) {
 			slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_last_set_time(sampass));
-------------- next part --------------
--- /source/utils/pdbedit.c	Fri Feb 14 23:34:38 2003
+++ /source/utils/pdbedit.c.fix	Tue May  6 11:14:55 2003
@@ -47,6 +47,9 @@
 #define BIT_RESERV_7	0x00800000
 #define BIT_IMPORT	0x01000000
 #define BIT_EXPORT	0x02000000
+#define BIT_BADPWRESET	0x04000000
+#define BIT_PWCANCHG	0x08000000
+#define BIT_PWMUSTCHG	0x10000000
 
 #define MASK_ALWAYS_GOOD	0x0000001F
 #define MASK_USER_GOOD		0x00401F00
@@ -136,6 +139,7 @@
 		tmp = pdb_get_pass_must_change_time(sam_pwent);
 		printf ("Password must change: %s\n", tmp ? http_timestring(tmp) : "0");
 		
+		printf ("Bad Password Attempt: %d\n", pdb_get_bad_pw_attempt(sam_pwent));
 	} else if (smbpwdstyle) {
 		if (IS_SAM_UNIX_USER(sam_pwent)) {
 			char lm_passwd[33];
@@ -227,6 +231,7 @@
 	return 0;
 }
 
+
 /*********************************************************
  Set User Info
 **********************************************************/
@@ -234,10 +239,12 @@
 static int set_user_info (struct pdb_context *in, const char *username, 
 			  const char *fullname, const char *homedir, 
 			  const char *drive, const char *script, 
-			  const char *profile, const char *account_control)
+			  const char *profile, const char *account_control, 
+			  const BOOL badpw, const long pwchg, const long pwmust)
 {
 	SAM_ACCOUNT *sam_pwent=NULL;
 	BOOL ret;
+	long winmagic = 2147483647;
 	
 	pdb_init_sam(&sam_pwent);
 	
@@ -275,6 +282,29 @@
 				  (pdb_get_acct_ctrl(sam_pwent) & not_settable) | newflag,
 				  PDB_CHANGED);
 	}
+
+	switch (pwchg) {
+		case 0:
+			pdb_set_pass_can_change_time(sam_pwent, winmagic, PDB_CHANGED);
+			break;
+		case 1:
+			pdb_set_pass_can_change_time(sam_pwent, 0, PDB_CHANGED);
+			break;
+		default:
+	}
+
+	switch (pwmust) {
+		case 0:
+			pdb_set_pass_must_change_time(sam_pwent, winmagic, PDB_CHANGED);   
+			break;
+		case 1:
+			pdb_set_pass_must_change_time(sam_pwent, 0, PDB_CHANGED);   
+			break;
+		default:
+	}
+
+	if (badpw)
+		pdb_set_bad_pw_attempt(sam_pwent, 0, PDB_CHANGED);   
 	
 	if (NT_STATUS_IS_OK(in->pdb_update_sam_account (in, sam_pwent)))
 		print_user_info (in, username, True, False);
@@ -482,6 +512,11 @@
 	static char *account_policy = NULL;
 	static long int account_policy_value = 0;
 	BOOL account_policy_value_set = False;
+	static long pw_canchg = 2147483647;
+	static long pw_mustchg = 2147483647; 
+	static BOOL badpw_reset = False;
+	BOOL pw_canchg_set = False;
+	BOOL pw_mustchg_set = False;
 
 	struct pdb_context *bin;
 	struct pdb_context *bout;
@@ -508,6 +543,9 @@
 		{"account-policy",	'P', POPT_ARG_STRING, &account_policy, 0,"value of an account policy (like maximum password age)",NULL},
 		{"value",       'V', POPT_ARG_LONG, &account_policy_value, 'V',"set the account policy to this value", NULL},
 		{"account-control",	'c', POPT_ARG_STRING, &account_control, 0, "Values of account control", NULL},
+		{"pwcanchg", 'A', POPT_ARG_LONG, &pw_canchg, 'A', "can change password ? 0 if no, 1 if yes", NULL},
+		{"pwmustchg", 'B', POPT_ARG_LONG, &pw_mustchg, 'B', "must change password ? 0 if no, 1 if yes", NULL},
+		{"badpwreset", 'z', POPT_ARG_NONE, &badpw_reset, 0, "reset bad password count", NULL},
 		{ NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_debug },
 		{ NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_configfile },
 		{0,0,0,0}
@@ -523,6 +561,13 @@
 		case 'V':
 			account_policy_value_set = True;
 			break;
+		case 'A':
+			fprintf(stderr, "A set.\n");
+			pw_canchg_set = True;
+			break;
+		case 'B':
+			pw_mustchg_set = True;
+			break;
 		}
 	}
 
@@ -557,7 +602,10 @@
 			(account_policy ? BIT_ACCPOLICY : 0) +
 			(account_policy_value_set ? BIT_ACCPOLVAL : 0) +
 			(backend_in ? BIT_IMPORT : 0) +
-			(backend_out ? BIT_EXPORT : 0);
+			(backend_out ? BIT_EXPORT : 0) +
+			(pw_canchg_set ? BIT_PWCANCHG : 0) +
+			(pw_mustchg_set ? BIT_PWMUSTCHG : 0) +
+			(badpw_reset ? BIT_BADPWRESET : 0);
 
 	if (setparms & BIT_BACKEND) {
 		if (!NT_STATUS_IS_OK(make_pdb_context_string(&bdef, backend))) {
@@ -647,6 +695,11 @@
 	/* mask out users options */
 	checkparms &= ~MASK_USER_GOOD;
 	
+	if ((checkparms & BIT_BADPWRESET) || (checkparms & BIT_PWCANCHG) || (checkparms & BIT_PWMUSTCHG)){
+		checkparms |= BIT_MODIFY;
+		checkparms &= ~(BIT_BADPWRESET + BIT_PWCANCHG + BIT_PWMUSTCHG);
+	}
+
 	/* account operation */
 	if ((checkparms & BIT_CREATE) || (checkparms & BIT_MODIFY) || (checkparms & BIT_DELETE)) {
 		/* check use of -u option */
@@ -681,7 +734,8 @@
 					      home_dir,
 					      home_drive,
 					      logon_script,
-					      profile_path, account_control);
+					      profile_path, account_control,
+						  badpw_reset, pw_canchg, pw_mustchg);
 		}
 	}
 
-------------- next part --------------
--- /source/include/smb.h	Thu Feb 27 22:21:08 2003
+++ /source/include/smb.h.fix	Tue May  6 11:14:55 2003
@@ -613,6 +613,8 @@
 	PDB_UNKNOWN6,
 	PDB_LMPASSWD,
 	PDB_NTPASSWD,
+	PDB_BADPWATTEMPT,
+	PDB_PWHISTORY,
 
 	/* this must be the last element */
 	PDB_COUNT,
@@ -665,7 +667,7 @@
 		const char * workstations; /* login from workstations string */
 		const char * unknown_str ; /* don't know what this is, yet. */
 		const char * munged_dial ; /* munged path name and dial-back tel number */
-		
+
 		uid_t uid;          /* this is a unix uid_t */
 		gid_t gid;          /* this is a unix gid_t */
 		DOM_SID user_sid;    /* Primary User SID */
@@ -684,6 +686,8 @@
 		
 		uint32 unknown_5; /* 0x0002 0000 */
 		uint32 unknown_6; /* 0x0000 04ec */
+		uint32 bad_pw_attempt; /* count of bad password attempt */
+		uint8 *nt_pw_his; /* password history */
 	} private;
 
 	/* Lets see if the remaining code can get the hint that you
-------------- next part --------------
--- //source/rpc_server/srv_samr_util.c	Mon Jan  6 16:40:38 2003
+++ //source/rpc_server/srv_samr_util.c.fix	Tue May  6 11:14:55 2003
@@ -182,6 +182,9 @@
 	
 	DEBUG(10,("INFO_21 ACCT_CTRL: %08X -> %08X\n",pdb_get_acct_ctrl(to),from->acb_info));
 	if (from->acb_info != pdb_get_acct_ctrl(to)) {
+		if ((pdb_get_acct_ctrl(to) & ACB_AUTOLOCK) && !(from->acb_info & ACB_AUTOLOCK))
+			pdb_set_bad_pw_attempt(to, 0, PDB_CHANGED);
+
 		pdb_set_acct_ctrl(to, from->acb_info, PDB_CHANGED);
 	}
 
@@ -383,7 +386,7 @@
 	}
 	
 	DEBUG(10,("INFO_23 ACCT_CTRL: %08X -> %08X\n",pdb_get_acct_ctrl(to),from->acb_info));
-	if (from->acb_info != pdb_get_acct_ctrl(to)) {
+	if ((from->acb_info != pdb_get_acct_ctrl(to)) && (from->acb_info)) {
 		pdb_set_acct_ctrl(to, from->acb_info, PDB_CHANGED);
 	}
 
-------------- next part --------------
--- /examples/LDAP/samba.schema	Mon Jan  6 17:39:40 2003
+++ /examples/LDAP/samba.schema.fix	Tue May  6 11:14:55 2003
@@ -64,6 +64,11 @@
 	EQUALITY integerMatch
 	SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
 
+attributetype ( 1.3.6.1.4.1.7165.2.1.19 NAME 'badPwAttempt'
+	DESC 'NT badPwAttempt'
+	EQUALITY integerMatch
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
 ##
 ## string settings
 ##
@@ -110,6 +115,11 @@
 	EQUALITY integerMatch
 	SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
 
+attributetype ( 1.3.6.1.4.1.7165.2.1.20 NAME 'pwHistory'
+	DESC 'NT Passwd'
+	EQUALITY caseIgnoreIA5Match
+	SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} )
+
 ##
 ## The smbPasswordEntry objectclass has been depreciated in favor of the
 ## sambaAccount objectclass
@@ -134,19 +144,19 @@
 objectclass ( 1.3.6.1.4.1.7165.2.2.3 NAME 'sambaAccount' SUP top AUXILIARY
 	DESC 'Samba Auxilary Account'
 	MUST ( uid $ rid ) 
-	MAY  ( cn $ lmPassword $ ntPassword $ pwdLastSet $ logonTime $
+	MAY  ( cn $ lmPassword $ ntPassword $ pwdLastSet $ logonTime $ badPwAttempt $
                logoffTime $ kickoffTime $ pwdCanChange $ pwdMustChange $ acctFlags $ 
                displayName $ smbHome $ homeDrive $ scriptPath $ profilePath $
-               description $ userWorkstations $ primaryGroupID $ domain ))
+               pwHistory $ description $ userWorkstations $ primaryGroupID $ domain ))
 
 ##
 ## Used for Winbind experimentation
 ##
-#objectclass ( 1.3.6.1.4.1.7165.1.2.2.3 NAME 'uidPool' SUP top AUXILIARY
-#	DESC 'Pool for allocating UNIX uids'
-#	MUST ( uidNumber $ cn ) )
-
-#objectclass ( 1.3.6.1.4.1.7165.1.2.2.4 NAME 'gidPool' SUP top AUXILIARY
-#	DESC 'Pool for allocating UNIX gids'
-#	MUST ( gidNumber $ cn ) )
+objectclass ( 1.3.6.1.4.1.7165.1.2.2.3 NAME 'uidPool' SUP top AUXILIARY
+	DESC 'Pool for allocating UNIX uids'
+	MUST ( uidNumber $ cn ) )
+
+objectclass ( 1.3.6.1.4.1.7165.1.2.2.4 NAME 'gidPool' SUP top AUXILIARY
+	DESC 'Pool for allocating UNIX gids'
+	MUST ( gidNumber $ cn ) )
 


More information about the samba-technical mailing list