I have implemented the "bad password attempt lockout" policy. If an user attempt with the bad password more than the count setted in the policy, then his account will be auto-locked, like what did NT. The implementation is only for LDAP passdb backend. To do this, I have to introduce a new integer attribute in samba.schema, "badPwAttempt". Folllowing are the patches, any comments?
Jianliang Lu TieSse s.p.a. Via Jervis, 60. 10015 Ivrea (To) - Italy [EMAIL PROTECTED] [EMAIL PROTECTED]
--- samba-3.0alpha22-orig/source/auth/auth_sam.c Mon Feb 17 16:31:06 2003 +++ samba-3.0alpha22-orig/source/auth/auth_sam.c.fix Thu Mar 27 12:40:10 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,7 @@ NTSTATUS nt_status; uint8 user_sess_key[16]; const uint8* lm_hash; + uint32 account_policy_lockout, badpwattempt; if (!user_info || !auth_context) { return NT_STATUS_UNSUCCESSFUL; @@ -448,10 +455,43 @@ 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)) { + 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 (badpwattempt >= account_policy_lockout) + 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_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;
--- samba-3.0alpha22-orig/source/passdb/passdb.c Mon Feb 24 16:12:31 2003 +++ samba-3.0alpha22-orig/source/passdb/passdb.c.fix Thu Mar 27 12:40:10 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. */
--- samba-3.0alpha22-orig/source/passdb/pdb_get_set.c Thu Jan 9 20:05:59 2003 +++ samba-3.0alpha22-orig/source/passdb/pdb_get_set.c.fix Thu Mar 27 12:40:10 2003 @@ -172,6 +172,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 @@ -1038,6 +1046,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 +1082,7 @@ BOOL pdb_set_pass_changed_now (SAM_ACCOUNT *sampass) { uint32 expire; + uint32 min_age; if (!sampass) return False; @@ -1082,6 +1101,16 @@ 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; }
--- samba-3.0alpha22-orig/source/passdb/pdb_ldap.c Thu Mar 13 12:27:01 2003 +++ samba-3.0alpha22-orig/source/passdb/pdb_ldap.c.fix Thu Mar 27 12:40:10 2003 @@ -149,7 +149,7 @@ "logoffTime", "kickoffTime", "cn", "pwdCanChange", "pwdMustChange", "displayName", "homeDrive", - "smbHome", "scriptPath", + "smbHome", "scriptPath", "badPwAttempt", "profilePath", "description", "userWorkstations", "rid", "primaryGroupID", "lmPassword", @@ -927,7 +927,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, @@ -980,6 +981,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 +1039,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 { @@ -1309,6 +1317,11 @@ make_a_mod(mods, ldap_op, "logonTime", temp); } + if (need_ldap_mod(pdb_add, sampass, PDB_BADPWATTEMPT)) { + slprintf(temp, sizeof(temp) - 1, "%li", 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);
--- samba-3.0alpha22-orig/source/utils/pdbedit.c Fri Feb 14 23:34:38 2003 +++ samba-3.0alpha22-orig/source/utils/pdbedit.c.fix Thu Mar 27 12:40:10 2003 @@ -136,6 +136,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];
--- ./samba-3.0alpha22-orig/examples/LDAP/samba.schema Mon Jan 6 17:39:40 2003 +++ ./samba-3.0alpha22-orig/examples/LDAP/samba.schema.fix Thu Mar 27 12:40:10 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 ## @@ -134,7 +139,7 @@ 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 ))
--- samba-3.0alpha22-orig/source/include/smb.h Thu Feb 27 22:21:08 2003 +++ samba-3.0alpha22-orig/source/include/smb.h.fix Thu Mar 27 12:40:10 2003 @@ -611,6 +611,7 @@ PDB_UNKNOWN3, PDB_UNKNOWN5, PDB_UNKNOWN6, + PDB_BADPWATTEMPT, PDB_LMPASSWD, PDB_NTPASSWD, @@ -684,6 +685,7 @@ uint32 unknown_5; /* 0x0002 0000 */ uint32 unknown_6; /* 0x0000 04ec */ + uint32 bad_pw_attempt; /* count of bad password attempt */ } private; /* Lets see if the remaining code can get the hint that you