Passowrd policy patch on Samba-3.0.2 for LDAP backend
Jianliang Lu
j.lu at tiesse.com
Tue Feb 17 11:25:07 GMT 2004
I've finished the work on password policy (LDAP backend), that comprised
bad password lockout and password history.
Three attributes were added in samba.schema for sambaSAMAccount object:
"sambaBadPwdCount" and "sambaBadPwdTime" for bad password lockout, and
a multi-value attribute "sambaPwdHistory" for password history (Uniqueness).
During the logon process, the autolock flag is updated if the "lockout
duration" time is reached. Also, the sambaBadPwdCount is reset as well when
the "reset count minutes" is reached. When the passord check results wrong
password then the sambaBadPwdCount is incremented and the account will be
lockout if the "bad lockout attempt" is reached.
The autolock flag is also checked and updated when a SAMR_QUERY_USERINFO is
called and the level of query is 10, 12, 20 or 21, while the sambaBadPwdCount
and the sambaBadPwdTime is updated only for the query level 21.
Autolock and sambaBadPwdCount are updated when you would show the user
using pdbedit -u user -v. You can reset the sambaBadPwdCount using
pdbedit -u user -z.
When user would change his password, the new password is checked against
passwords in history list, which the length is "password histroy". The new
password is accepted only if the check results that no password in history
list is matched the new one.
Jianliang Lu
PATCH:
--------------------
--- ./examples/LDAP/samba.schema.orig Wed Feb 11 09:43:56 2004
+++ ./examples/LDAP/samba.schema Wed Feb 11 09:44:26 2004
@@ -202,6 +202,15 @@
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.50 NAME 'sambaBadPwdCount'
+ DESC 'NT bad password attempt count'
+ 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.51 NAME 'sambaBadPwdTime'
+ DESC 'Timestamp of the last bad password attempt update'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
##
## string settings
@@ -241,6 +250,10 @@
EQUALITY caseExactMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )
+attributetype ( 1.3.6.1.4.1.7165.2.1.52 NAME 'sambaPwdHistory'
+ DESC 'MD4 hash of the unicode password'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} )
##
## SID, of any type
##
@@ -313,7 +326,8 @@
sambaPwdCanChange $ sambaPwdMustChange $ sambaAcctFlags $
displayName $ sambaHomePath $ sambaHomeDrive $
sambaLogonScript $
sambaProfilePath $ description $ sambaUserWorkstations $
- sambaPrimaryGroupSID $ sambaDomainName $ sambaMungedDial))
+ sambaPrimaryGroupSID $ sambaDomainName $ sambaMungedDial $
+ sambaBadPwdCount $ sambaBadPwdTime $ sambaPwdHistory))
##
## Group mapping info
--- ./source/auth/auth_sam.c.orig Wed Feb 11 09:35:05 2004
+++ ./source/auth/auth_sam.c Wed Feb 11 09:35:24 2004
@@ -74,10 +74,12 @@
SAM_ACCOUNT *sampass,
const auth_usersupplied_info *user_info)
{
- uint16 acct_ctrl = pdb_get_acct_ctrl(sampass);
+ uint16 acct_ctrl;
char *workstation_list;
time_t kickoff_time;
+ acct_ctrl = pdb_get_acct_ctrl(sampass);
+
DEBUG(4,("sam_account_ok: Checking SMB password for user %
s\n",pdb_get_username(sampass)));
/* Quit if the account was disabled. */
@@ -86,12 +88,6 @@
return NT_STATUS_ACCOUNT_DISABLED;
}
- /* Quit if the account was locked out. */
- if (acct_ctrl & ACB_AUTOLOCK) {
- DEBUG(1,("sam_account_ok: 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);
@@ -177,8 +173,11 @@
SAM_ACCOUNT *sampass=NULL;
BOOL ret;
NTSTATUS nt_status;
+ GROUP_MAP map;
+ pstring grname;
DATA_BLOB user_sess_key = data_blob(NULL, 0);
DATA_BLOB lm_sess_key = data_blob(NULL, 0);
+ BOOL updated=False, updated1=False;
if (!user_info || !auth_context) {
return NT_STATUS_UNSUCCESSFUL;
@@ -202,14 +201,58 @@
return NT_STATUS_NO_SUCH_USER;
}
+ if (pdb_get_acct_ctrl(sampass) & ACB_NORMAL)
+ pdb_update_autolock_flag(sampass, &updated);
+
+ /* Quit if the account was locked out. */
+ if (pdb_get_acct_ctrl(sampass) & ACB_AUTOLOCK) {
+ DEBUG(3,("check_sam_security: Account for user %s was locked
out.\n", pdb_get_username(sampass)));
+ return NT_STATUS_ACCOUNT_LOCKED_OUT;
+ }
+
+
nt_status = sam_password_ok(auth_context, mem_ctx, sampass,
user_info, &user_sess_key, &lm_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) {
+
+ if (!pdb_getgrnam(&map, "Domain Admins"))
+ DEBUG(1, ("auth_sam.c: Failed to get groupmap for Domain
Admins"));
+ else
+ pstrcpy(grname, gidtoname(map.gid));
+ if(!user_in_group_list(user_info-
>internal_username.str,grname,NULL,0)){
+ pdb_increment_bad_password_count(sampass);
+ updated1 = True;
+ }
+ } else {
+ if (!pdb_update_bad_password_count(sampass,
&updated1))
+ DEBUG(2,
("pdb_update_bad_password_count failed.\n"));
+ }
+ if (updated || updated1){
+ become_root();
+ if(!pdb_update_sam_account(sampass))
+ DEBUG(1, ("Failed to modify entry.\n"));
+ unbecome_root();
+ }
pdb_free_sam(&sampass);
return nt_status;
}
+ if ((pdb_get_acct_ctrl(sampass) & ACB_NORMAL) &&
+
(pdb_get_bad_password_count(sampass) > 0)){
+ pdb_set_bad_password_count(sampass, 0, PDB_CHANGED);
+ pdb_set_bad_password_time(sampass, 0, PDB_CHANGED);
+ updated1 = True;
+ }
+
+ if (updated || updated1){
+ become_root();
+ if(!pdb_update_sam_account(sampass))
+ DEBUG(1, ("Failed to modify entry.\n"));
+ unbecome_root();
+ }
+
nt_status = sam_account_ok(mem_ctx, sampass, user_info);
if (!NT_STATUS_IS_OK(nt_status)) {
--- ./source/include/passdb.h.orig Wed Feb 11 09:38:22 2004
+++ ./source/include/passdb.h Wed Feb 11 09:38:52 2004
@@ -50,6 +50,7 @@
PDB_GROUPSID,
PDB_ACCTCTRL,
PDB_PASSLASTSET,
+ PDB_BAD_PASSWORD_TIME,
PDB_UNIXHOMEDIR,
PDB_ACCTDESC,
PDB_WORKSTATIONS,
@@ -62,6 +63,7 @@
PDB_UNKNOWN6,
PDB_LMPASSWD,
PDB_NTPASSWD,
+ PDB_PWHISTORY,
PDB_BACKEND_PRIVATE_DATA,
/* this must be the last element */
@@ -108,6 +110,7 @@
time_t pass_last_set_time; /* password last set time */
time_t pass_can_change_time; /* password can change time */
time_t pass_must_change_time; /* password must change time */
+ time_t bad_password_time; /* last bad password
attempt time */
const char * username; /* UNIX username string */
const char * domain; /* Windows Domain name */
@@ -122,6 +125,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 */
+ const uint8 * nt_pw_his; /* nt hashed password history */
DOM_SID user_sid; /* Primary User SID */
DOM_SID group_sid; /* Primary Group SID */
--- ./source/include/smbldap.h.orig Wed Feb 11 09:40:15 2004
+++ ./source/include/smbldap.h Wed Feb 11 09:40:28 2004
@@ -91,6 +91,8 @@
#define LDAP_ATTR_BAD_PASSWORD_COUNT 35
#define LDAP_ATTR_LOGON_COUNT 36
#define LDAP_ATTR_MUNGED_DIAL 37
+#define LDAP_ATTR_BAD_PASSWORD_TIME 38
+#define LDAP_ATTR_PWD_HISTORY 39
typedef struct _attrib_map_entry {
int attrib;
--- ./source/lib/smbldap.c.orig Wed Feb 11 09:39:28 2004
+++ ./source/lib/smbldap.c Wed Feb 11 09:39:52 2004
@@ -98,6 +98,9 @@
{ LDAP_ATTR_OBJCLASS, "objectClass" },
{ LDAP_ATTR_ACB_INFO, "sambaAcctFlags" },
{ LDAP_ATTR_MUNGED_DIAL, "sambaMungedDial" },
+ { LDAP_ATTR_BAD_PASSWORD_COUNT, "sambaBadPwdCount" },
+ { LDAP_ATTR_BAD_PASSWORD_TIME, "sambaBadPwdTime" },
+ { LDAP_ATTR_PWD_HISTORY, "sambaPwdHistory" },
{ LDAP_ATTR_LIST_END, NULL }
};
@@ -313,6 +316,44 @@
ldap_value_free(values);
#ifdef DEBUG_PASSWORDS
DEBUG (100, ("smbldap_get_single_attribute: [%s] = [%s]\n",
attribute, value));
+#endif
+ return True;
+}
+
+/*******************************************************************
+ Search an attribute and return the value found.
+******************************************************************/
+
+BOOL smbldap_get_single_attribute_multivalue (LDAP * ldap_struct,
LDAPMessage * entry,
+ const char *attribute, char *value, int
len, int * count)
+{
+ char **values;
+ int i;
+
+ if ( !attribute )
+ return False;
+
+ value[0] = '\0';
+
+ if ((values = ldap_get_values (ldap_struct, entry, attribute)) ==
NULL) {
+ DEBUG (10, ("smbldap_get_single_attribute_multivalue: [%s] =
[<does not exist>]\n", attribute));
+
+ return False;
+ }
+
+ for (i = 0; (values[i] != NULL) && (i < len); i++){
+ if (convert_string(CH_UTF8, CH_UNIX,values[i], -1,(value +
i*sizeof(pstring)), sizeof(pstring)) == (size_t)-1) {
+ DEBUG(1, ("smbldap_get_single_attribute_multivalue:
string conversion of [%s] = [%s] failed!\n",
+ attribute, values[i]));
+ ldap_value_free(values);
+ return False;
+ }
+ }
+
+ *count = i;
+ ldap_value_free(values);
+#ifdef DEBUG_PASSWORDS
+ DEBUG (100, ("smbldap_get_single_attribute: [%s] = [%s]\n",
attribute, value));
#endif
return True;
}
--- ./source/passdb/passdb.c.orig Wed Feb 11 09:37:39 2004
+++ ./source/passdb/passdb.c Wed Feb 11 09:38:00 2004
@@ -79,6 +79,7 @@
user->private.logoff_time =
user->private.kickoff_time =
user->private.pass_must_change_time = get_time_t_max();
+ user->private.bad_password_time = (time_t)0;
user->private.unknown_3 = 0x00ffffff; /* don't know */
user->private.logon_divs = 168; /* hours per week */
user->private.hours_len = 21; /* 21 times 8 bits = 168 */
@@ -1765,3 +1766,107 @@
}
+/*********************************************************************
+ Update the bad password count checking the AP_RESET_COUNT_TIME
+ ********************************************************************/
+
+BOOL pdb_update_bad_password_count(SAM_ACCOUNT *sampass, BOOL *updated)
+{
+ time_t LastBadPassword;
+ uint16 BadPasswordCount;
+ uint32 resettime;
+
+ BadPasswordCount = pdb_get_bad_password_count(sampass);
+ if(BadPasswordCount > 0){
+ if (!account_policy_get(AP_RESET_COUNT_TIME, &resettime)) {
+ DEBUG(0, ("account_policy_get failed.\n"));
+ return False;
+ } else {
+ LastBadPassword = pdb_get_bad_password_time
(sampass);
+ DEBUG(10, ("LastBadPassword=%d, resettime=%
d.\n", LastBadPassword, resettime));
+ if ((resettime < 0xffffffff) && (time(NULL) >
(LastBadPassword + resettime*60))){
+ pdb_set_bad_password_count(sampass,
0, PDB_CHANGED);
+ pdb_set_bad_password_time(sampass, 0,
PDB_CHANGED);
+ *updated =True;
+ }
+ }
+ }
+ return True;
+}
+
+/*********************************************************************
+ Update the ACB_AUTOLOCK flag checking the AP_LOCK_ACCOUNT_DURATION
+ ********************************************************************/
+
+BOOL pdb_update_autolock_flag(SAM_ACCOUNT *sampass, BOOL *updated)
+{
+ uint32 duration;
+ time_t LastBadPassword;
+
+ if (!sampass)
+ return False;
+
+ if (pdb_get_acct_ctrl(sampass) & ACB_AUTOLOCK)
+ if (!account_policy_get(AP_LOCK_ACCOUNT_DURATION, &duration))
{
+ DEBUG(0, ("pdb_update_autolock_flag:
account_policy_get failed.\n"));
+ return False;
+ } else {
+ LastBadPassword = pdb_get_bad_password_time
(sampass);
+ DEBUG(10, ("LastBadPassword=%d, duration=%
d.\n",LastBadPassword,duration*60 ));
+ if ((duration < 0xffffffff) && (time(NULL) >
(LastBadPassword + duration*60))){
+ DEBUG(10, ("LastBadPassword=%d,
duration=%d.\n",LastBadPassword,duration*60 ));
+ pdb_set_acct_ctrl (sampass,
+
pdb_get_acct_ctrl(sampass) & ~ACB_AUTOLOCK,
+ PDB_CHANGED);
+ pdb_set_bad_password_count(sampass,
0, PDB_CHANGED);
+ pdb_set_bad_password_time(sampass, 0,
PDB_CHANGED);
+
+ *updated =True;
+ }
+ }
+
+ return True;
+}
+
+/*********************************************************************
+ Increment the bad_password_count
+ ********************************************************************/
+
+BOOL pdb_increment_bad_password_count(SAM_ACCOUNT *sampass)
+{
+ uint32 resettime;
+ uint32 account_policy_lockout;
+ time_t LastBadPassword;
+
+ if (!sampass)
+ return False;
+
+ if (!account_policy_get(AP_RESET_COUNT_TIME, &resettime)) {
+ DEBUG(0, ("account_policy_get failed.\n"));
+ return False;
+ } else {
+ LastBadPassword = pdb_get_bad_password_time(sampass);
+ DEBUG(10, ("LastBadPassword=%d, resettime=%d.\n",
LastBadPassword, resettime));
+ if (time(NULL) > (LastBadPassword + resettime*60)){
+ pdb_set_bad_password_count(sampass, 1,
PDB_CHANGED);
+ }else
+ pdb_set_bad_password_count(sampass,
+
pdb_get_bad_password_count(sampass)+1,
+
PDB_CHANGED);
+ pdb_set_bad_password_time(sampass, time(NULL),
PDB_CHANGED);
+ if (!account_policy_get
(AP_BAD_ATTEMPT_LOCKOUT,&account_policy_lockout)) {
+ DEBUG(0, ("account_policy_get failed.\n"));
+ return False;
+ } else {
+ if (account_policy_lockout &&
+ (pdb_get_bad_password_count(sampass)
>= account_policy_lockout))
+ if (!pdb_set_acct_ctrl (sampass,
+
pdb_get_acct_ctrl(sampass) |ACB_AUTOLOCK,
+
PDB_CHANGED)) {
+ DEBUG(1,
("pdb_increment_bad_password_count:failed to set 'autolock' flag. \n"));
+ return False;
+ }
+ }
+ return True;
+ }
+}
--- ./source/passdb/pdb_get_set.c.orig Tue Feb 10 16:46:12 2004
+++ ./source/passdb/pdb_get_set.c Wed Feb 11 09:50:54 2004
@@ -96,6 +96,14 @@
return (-1);
}
+time_t pdb_get_bad_password_time (const SAM_ACCOUNT *sampass)
+{
+ if (sampass)
+ return (sampass->private.bad_password_time);
+ else
+ return (-1);
+}
+
uint16 pdb_get_logon_divs (const SAM_ACCOUNT *sampass)
{
if (sampass)
@@ -131,6 +139,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) {
@@ -420,6 +437,16 @@
return pdb_set_init_flags(sampass, PDB_PASSLASTSET, flag);
}
+BOOL pdb_set_bad_password_time (SAM_ACCOUNT *sampass, time_t mytime, enum
pdb_value_state flag)
+{
+ if (!sampass)
+ return False;
+
+ sampass->private.bad_password_time = mytime;
+
+ return pdb_set_init_flags(sampass, PDB_BAD_PASSWORD_TIME, flag);
+}
+
BOOL pdb_set_hours_len (SAM_ACCOUNT *sampass, uint32 len, enum
pdb_value_state flag)
{
if (!sampass)
@@ -943,6 +970,31 @@
}
/*********************************************************************
+ 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 = (uint8 *) talloc_memdup
(sampass->mem_ctx, pwd, historyLen*16);
+
+ if (!sampass->private.nt_pw_his) {
+ DEBUG(0, ("pdb_set_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.
********************************************************************/
@@ -1116,10 +1168,18 @@
{
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 = (uint8 *)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))
@@ -1134,5 +1194,20 @@
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 = (uint8 *)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;
}
+
--- ./source/passdb/pdb_ldap.c.orig Tue Feb 10 16:46:12 2004
+++ ./source/passdb/pdb_ldap.c Wed Feb 11 10:18:02 2004
@@ -405,7 +405,8 @@
kickoff_time,
pass_last_set_time,
pass_can_change_time,
- pass_must_change_time;
+ pass_must_change_time,
+ bad_password_time;
pstring username,
domain,
nt_username,
@@ -427,6 +428,9 @@
uint32 hours_len;
uint8 hours[MAX_HOURS_LEN];
pstring temp;
+ uint8 *pwhist;
+ int i, pwcount, pwHistLen;
+ char *temp1;
/*
* do a little initialization
@@ -695,6 +699,37 @@
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;
+ }
+ memset(temp1, 0, sizeof(pstring)*pwHistLen);
+ 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 (!smbldap_get_single_attribute_multivalue (ldap_state-
>smbldap_state->ldap_struct, entry, get_userattr_key2string(ldap_state-
>schema_ver, LDAP_ATTR_PWD_HISTORY), 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)){
+ SAFE_FREE (temp1);
+ SAFE_FREE (pwhist);
+ return False;
+ }
+ SAFE_FREE (temp1);
+ SAFE_FREE (pwhist);
+ }
+
+
if (!smbldap_get_single_attribute (ldap_state->smbldap_state-
>ldap_struct, entry,
get_userattr_key2string(ldap_state->schema_ver,
LDAP_ATTR_ACB_INFO), temp)) {
acct_ctrl |= ACB_NORMAL;
@@ -722,6 +757,14 @@
pdb_set_bad_password_count(sampass, bad_password_count,
PDB_SET);
}
+ if (!smbldap_get_single_attribute(ldap_state->smbldap_state-
>ldap_struct, entry,
+ get_userattr_key2string(ldap_state->schema_ver,
LDAP_ATTR_BAD_PASSWORD_TIME), temp)) {
+ /* leave as default */
+ } else {
+ bad_password_time = (time_t) atol(temp);
+ pdb_set_bad_password_time(sampass, bad_password_time,
PDB_SET);
+ }
+
if (!smbldap_get_single_attribute(ldap_state->smbldap_state-
>ldap_struct, entry,
get_userattr_key2string(ldap_state->schema_ver,
LDAP_ATTR_LOGON_COUNT), temp)) {
/* leave as default */
@@ -750,6 +793,8 @@
{
pstring temp;
uint32 rid;
+ uint8 * temp1;
+ int pwHistLen, i;
if (mods == NULL || sampass == NULL) {
DEBUG(0, ("init_ldap_from_sam: NULL parameters found!\n"));
@@ -909,6 +954,16 @@
smbldap_make_mod(ldap_state->smbldap_state->ldap_struct,
existing, mods,
get_userattr_key2string(ldap_state->schema_ver,
LDAP_ATTR_PWD_MUST_CHANGE), temp);
+ slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_bad_password_time
(sampass));
+ if (need_update(sampass, PDB_BAD_PASSWORD_TIME))
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct,
existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver,
LDAP_ATTR_BAD_PASSWORD_TIME), temp);
+
+ slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_bad_password_count
(sampass));
+ if (need_update(sampass, PDB_BAD_PASSWORD_COUNT))
+ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct,
existing, mods,
+ get_userattr_key2string(ldap_state->schema_ver,
LDAP_ATTR_BAD_PASSWORD_COUNT), temp);
+
if ((pdb_get_acct_ctrl(sampass)&
(ACB_WSTRUST|ACB_SVRTRUST|ACB_DOMTRUST))
|| (lp_ldap_passwd_sync()!=LDAP_PASSWD_SYNC_ONLY)) {
@@ -941,6 +996,26 @@
}
}
+
+ if (need_update(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);
+ DEBUG(10, ("LUJ: temp1=%s, temp=%
s\n", temp1, temp));
+ if (!strncmp(temp,"0000000000",10))
+ break;
+ smbldap_set_mod
(mods,LDAP_MOD_REPLACE, get_userattr_key2string(ldap_state-
>schema_ver,LDAP_ATTR_PWD_HISTORY),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,
--- ./source/rpc_server/srv_samr_nt.c.orig Wed Feb 11 09:41:01 2004
+++ ./source/rpc_server/srv_samr_nt.c Wed Feb 11 09:41:15 2004
@@ -1656,6 +1656,7 @@
SAM_ACCOUNT *smbpass=NULL;
BOOL ret;
NTSTATUS nt_status;
+ BOOL updated=False;
nt_status = pdb_init_sam_talloc(mem_ctx, &smbpass);
@@ -1674,6 +1675,16 @@
DEBUG(3,("User:[%s]\n", pdb_get_username(smbpass) ));
+ pdb_update_autolock_flag(smbpass, &updated);
+
+ if (updated){
+ become_root();
+ if(!pdb_update_sam_account(smbpass))
+ DEBUG(1, ("Failed to modify entry.\n"));
+ unbecome_root();
+ }
+
+
ZERO_STRUCTP(id10);
init_sam_user_info10(id10, pdb_get_acct_ctrl(smbpass) );
@@ -1693,6 +1704,7 @@
SAM_ACCOUNT *smbpass=NULL;
BOOL ret;
NTSTATUS nt_status;
+ BOOL updated=False;
if (!p->ntlmssp_auth_validated)
return NT_STATUS_ACCESS_DENIED;
@@ -1720,6 +1732,15 @@
DEBUG(3,("User:[%s] 0x%x\n", pdb_get_username(smbpass),
pdb_get_acct_ctrl(smbpass) ));
+ pdb_update_autolock_flag(smbpass, &updated);
+
+ if (updated){
+ become_root();
+ if(!pdb_update_sam_account(smbpass))
+ DEBUG(1, ("Failed to modify entry.\n"));
+ unbecome_root();
+ }
+
if ( pdb_get_acct_ctrl(smbpass) & ACB_DISABLED) {
pdb_free_sam(&smbpass);
return NT_STATUS_ACCOUNT_DISABLED;
@@ -1741,6 +1762,7 @@
{
SAM_ACCOUNT *sampass=NULL;
BOOL ret;
+ BOOL updated=False;
pdb_init_sam_talloc(mem_ctx, &sampass);
@@ -1757,6 +1779,15 @@
DEBUG(3,("User:[%s]\n", pdb_get_username(sampass) ));
+ pdb_update_autolock_flag(sampass, &updated);
+
+ if (updated){
+ become_root();
+ if(!pdb_update_sam_account(sampass))
+ DEBUG(1, ("Failed to modify entry.\n"));
+ unbecome_root();
+ }
+
ZERO_STRUCTP(id20);
init_sam_user_info20A(id20, sampass);
@@ -1775,6 +1806,7 @@
SAM_ACCOUNT *sampass=NULL;
BOOL ret;
NTSTATUS nt_status;
+ BOOL updated=False, updated1=False;
nt_status = pdb_init_sam_talloc(mem_ctx, &sampass);
if (!NT_STATUS_IS_OK(nt_status)) {
@@ -1794,6 +1826,16 @@
DEBUG(3,("User:[%s]\n", pdb_get_username(sampass) ));
+ pdb_update_autolock_flag(sampass, &updated);
+ pdb_update_bad_password_count(sampass, &updated1);
+
+ if (updated || updated1){
+ become_root();
+ if(!pdb_update_sam_account(sampass))
+ DEBUG(1, ("Failed to modify entry.\n"));
+ unbecome_root();
+ }
+
ZERO_STRUCTP(id21);
nt_status = init_sam_user_info21A(id21, sampass, domain_sid);
--- ./source/smbd/chgpasswd.c.orig Wed Feb 11 09:42:31 2004
+++ ./source/smbd/chgpasswd.c Wed Feb 11 09:36:48 2004
@@ -723,6 +723,7 @@
if (!NT_STATUS_IS_OK(nt_status))
return nt_status;
+
/* We've already checked the old password here.... */
become_root();
nt_status = change_oem_password(sampass, NULL, new_passwd, True);
@@ -901,6 +902,45 @@
}
/***********************************************************
+ This routine takes the given password and checks it against
+ the password history.
+************************************************************/
+static BOOL check_passwd_history(SAM_ACCOUNT *sampass, const char *plaintext)
+{
+ uchar new_lanman_p16[16];
+ uchar new_nt_p16[16];
+ uint8 *nt_pw;
+ uint8 *pwhistory;
+ BOOL found = False;
+ int i, pwHisLen;
+
+ account_policy_get(AP_PASSWORD_HISTORY, &pwHisLen);
+ if (pwHisLen == 0)
+ return False;
+
+
+ pwhistory = (uint8 *) pdb_get_pw_history (sampass);
+
+ if (!pwhistory)
+ return False;
+
+ nt_pw = (uint8*) pdb_get_nt_passwd(sampass);
+
+ nt_lm_owf_gen (plaintext, new_nt_p16, new_lanman_p16);
+
+ if (!memcmp(nt_pw, new_nt_p16, 16))
+ return True;
+
+ for (i=0; i<pwHisLen; i++){
+ if (!memcmp((uint8 *) (pwhistory + i*16), new_nt_p16, 16))
+ found = True;
+ }
+
+ 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
@@ -936,6 +976,9 @@
/* return NT_STATUS_PWD_TOO_SHORT; */
}
+ if (check_passwd_history(hnd,new_passwd))
+ return NT_STATUS_PASSWORD_RESTRICTION;
+
/* TODO: Add cracklib support here */
/*
--- ./source/utils/pdbedit.c.orig Tue Feb 10 16:46:12 2004
+++ ./source/utils/pdbedit.c Wed Feb 11 10:35:40 2004
@@ -48,6 +48,7 @@
#define BIT_IMPORT 0x01000000
#define BIT_EXPORT 0x02000000
#define BIT_FIX_INIT 0x04000000
+#define BIT_BADPWRESET 0x08000000
#define MASK_ALWAYS_GOOD 0x0000001F
#define MASK_USER_GOOD 0x00401F00
@@ -154,6 +155,10 @@
tmp = pdb_get_pass_must_change_time(sam_pwent);
printf ("Password must change: %s\n", tmp ? http_timestring
(tmp) : "0");
+ tmp = pdb_get_bad_password_time(sam_pwent);
+ printf ("Last Bad Password Time: %s\n", tmp ? http_timestring
(tmp) : "0");
+ printf ("Bad Password Count: %d\n", pdb_get_bad_password_count
(sam_pwent));
+
} else if (smbpwdstyle) {
char lm_passwd[33];
char nt_passwd[33];
@@ -186,6 +191,8 @@
{
SAM_ACCOUNT *sam_pwent=NULL;
BOOL ret;
+ BOOL updated = False, updated1=False;
+
if (!NT_STATUS_IS_OK(pdb_init_sam (&sam_pwent))) {
return -1;
@@ -198,6 +205,19 @@
pdb_free_sam(&sam_pwent);
return -1;
}
+
+ if (!pdb_update_autolock_flag(sam_pwent, &updated))
+ DEBUG(2,("pdb_update_autolock_flag failed.\n"));
+
+ if (!pdb_update_bad_password_count(sam_pwent, &updated))
+ DEBUG(2,("pdb_update_bad_password_count failed.\n"));
+
+ if (updated || updated1){
+ become_root();
+ if(!pdb_update_sam_account(sam_pwent))
+ DEBUG(1, ("Failed to modify entry.\n"));
+ unbecome_root();
+ }
ret=print_sam_info (sam_pwent, verbosity, smbpwdstyle);
pdb_free_sam(&sam_pwent);
@@ -275,7 +295,7 @@
const char *fullname, const char *homedir,
const char *drive, const char *script,
const char *profile, const char *account_control,
- const char *user_sid, const char *group_sid)
+ const char *user_sid, const char *group_sid,const
BOOL badpw)
{
SAM_ACCOUNT *sam_pwent=NULL;
BOOL ret;
@@ -347,6 +367,11 @@
pdb_set_group_sid (sam_pwent, &g_sid, PDB_CHANGED);
}
+ if (badpw){
+ pdb_set_bad_password_count(sam_pwent, 0, PDB_CHANGED);
+ pdb_set_bad_password_time(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);
else {
@@ -593,6 +618,7 @@
static char *group_sid = NULL;
static long int account_policy_value = 0;
BOOL account_policy_value_set = False;
+ static BOOL badpw_reset = False;
struct pdb_context *bin;
struct pdb_context *bout;
@@ -623,6 +649,7 @@
{"value", 'C', POPT_ARG_LONG,
&account_policy_value, 'C',"set the account policy to this value", NULL},
{"account-control", 'c', POPT_ARG_STRING,
&account_control, 0, "Values of account control", NULL},
{"force-initialized-passwords", 0, POPT_ARG_NONE,
&force_initialised_password, 0, "Force initialization of corrupt password
strings in a passdb backend", NULL},
+ {"bad-password-count-reset", 'z', POPT_ARG_NONE,
&badpw_reset, 0, "reset bad password count" , NULL},
POPT_COMMON_SAMBA
POPT_TABLEEND
};
@@ -675,7 +702,8 @@
(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) +
+ (badpw_reset ? BIT_BADPWRESET : 0);
if (setparms & BIT_BACKEND) {
if (!NT_STATUS_IS_OK(make_pdb_context_string(&bdef,
backend))) {
@@ -773,6 +801,11 @@
/* mask out users options */
checkparms &= ~MASK_USER_GOOD;
+ if (checkparms & BIT_BADPWRESET){
+ checkparms |= BIT_MODIFY;
+ checkparms &= ~BIT_BADPWRESET;
+ }
+
/* account operation */
if ((checkparms & BIT_CREATE) || (checkparms & BIT_MODIFY) ||
(checkparms & BIT_DELETE)) {
/* check use of -u option */
@@ -808,7 +841,7 @@
home_drive,
logon_script,
profile_path, account_control,
- user_sid, group_sid);
+ user_sid,
group_sid,badpw_reset);
}
}
Jianliang Lu
TieSse s.p.a. Ivrea (To) - Italy
j.lu at tiesse.com luj at libero.it
http://www.tiesse.com
More information about the samba-technical
mailing list