diff -u -r samba-3.0.20rc1/source/passdb/passdb.c samba-3.0.20rc1.pw_must_change_update/source/passdb/passdb.c --- samba-3.0.20rc1/source/passdb/passdb.c 2005-07-28 08:19:48.000000000 -0500 +++ samba-3.0.20rc1.pw_must_change_update/source/passdb/passdb.c 2005-08-09 13:16:29.000000000 -0500 @@ -1332,6 +1332,7 @@ #define TDB_FORMAT_STRING_V0 "ddddddBBBBBBBBBBBBddBBwdwdBwwd" #define TDB_FORMAT_STRING_V1 "dddddddBBBBBBBBBBBBddBBwdwdBwwd" #define TDB_FORMAT_STRING_V2 "dddddddBBBBBBBBBBBBddBBBwwdBwwd" +#define TDB_FORMAT_STRING_V3 "dddddddBBBBBBBBBBBBddBBBwwdBwwd" /********************************************************************** Intialize a SAM_ACCOUNT struct from a BYTE buffer of size len @@ -1339,7 +1340,7 @@ BOOL init_sam_from_buffer(SAM_ACCOUNT *sampass, uint8 *buf, uint32 buflen) { - return(init_sam_from_buffer_v2(sampass, buf, buflen)); + return(init_sam_from_buffer_v3(sampass, buf, buflen)); } /********************************************************************** @@ -1348,7 +1349,7 @@ uint32 init_buffer_from_sam (uint8 **buf, const SAM_ACCOUNT *sampass, BOOL size_only) { - return(init_buffer_from_sam_v2(buf, sampass, size_only)); + return(init_buffer_from_sam_v3(buf, sampass, size_only)); } @@ -1935,7 +1936,242 @@ return ret; } -uint32 init_buffer_from_sam_v2 (uint8 **buf, const SAM_ACCOUNT *sampass, BOOL size_only) +BOOL init_sam_from_buffer_v3(SAM_ACCOUNT *sampass, uint8 *buf, uint32 buflen) +{ + + /* times are stored as 32bit integer + take care on system with 64bit wide time_t + --SSS */ + uint32 logon_time, + logoff_time, + kickoff_time, + bad_password_time, + pass_last_set_time, + pass_can_change_time, + pass_must_change_time, + expire; + char *username = NULL; + char *domain = NULL; + char *nt_username = NULL; + char *dir_drive = NULL; + char *unknown_str = NULL; + char *munged_dial = NULL; + char *fullname = NULL; + char *homedir = NULL; + char *logon_script = NULL; + char *profile_path = NULL; + char *acct_desc = NULL; + char *workstations = NULL; + uint32 username_len, domain_len, nt_username_len, + dir_drive_len, unknown_str_len, munged_dial_len, + fullname_len, homedir_len, logon_script_len, + profile_path_len, acct_desc_len, workstations_len; + + uint32 user_rid, group_rid, hours_len, unknown_6; + uint16 acct_ctrl, logon_divs; + uint16 bad_password_count, logon_count; + uint8 *hours = NULL; + uint8 *lm_pw_ptr = NULL, *nt_pw_ptr = NULL, *nt_pw_hist_ptr = NULL; + uint32 len = 0; + uint32 lm_pw_len, nt_pw_len, nt_pw_hist_len, hourslen; + uint32 pwHistLen = 0; + BOOL ret = True; + fstring tmpstring; + + if(sampass == NULL || buf == NULL) { + DEBUG(0, ("init_sam_from_buffer_v2: NULL parameters found!\n")); + return False; + } + +/* TDB_FORMAT_STRING_V3 "dddddddBBBBBBBBBBBBddBBBwwdBwwd" */ + + /* unpack the buffer into variables */ + len = tdb_unpack ((char *)buf, buflen, TDB_FORMAT_STRING_V3, + &logon_time, /* d */ + &logoff_time, /* d */ + &kickoff_time, /* d */ + &bad_password_time, /* d */ + &pass_last_set_time, /* d */ + &pass_can_change_time, /* d */ + &pass_must_change_time, /* d */ + &username_len, &username, /* B */ + &domain_len, &domain, /* B */ + &nt_username_len, &nt_username, /* B */ + &fullname_len, &fullname, /* B */ + &homedir_len, &homedir, /* B */ + &dir_drive_len, &dir_drive, /* B */ + &logon_script_len, &logon_script, /* B */ + &profile_path_len, &profile_path, /* B */ + &acct_desc_len, &acct_desc, /* B */ + &workstations_len, &workstations, /* B */ + &unknown_str_len, &unknown_str, /* B */ + &munged_dial_len, &munged_dial, /* B */ + &user_rid, /* d */ + &group_rid, /* d */ + &lm_pw_len, &lm_pw_ptr, /* B */ + &nt_pw_len, &nt_pw_ptr, /* B */ + /* Change from V1 is addition of password history field. */ + &nt_pw_hist_len, &nt_pw_hist_ptr, /* B */ + &acct_ctrl, /* w */ + /* Also "remove_me" field was removed. */ + &logon_divs, /* w */ + &hours_len, /* d */ + &hourslen, &hours, /* B */ + &bad_password_count, /* w */ + &logon_count, /* w */ + &unknown_6); /* d */ + + if (len == (uint32) -1) { + ret = False; + goto done; + } + + pdb_set_logon_time(sampass, logon_time, PDB_SET); + pdb_set_logoff_time(sampass, logoff_time, PDB_SET); + pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET); + pdb_set_bad_password_time(sampass, bad_password_time, PDB_SET); + pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET); + pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET); + + /*Change from V2 is that pass_must_change_time is 0 or 1 in backend and corresponds + to force password change at login. The time is calculated based on the policy and + last password set time */ + + if(pass_must_change_time) { + if (!account_policy_get(AP_MAX_PASSWORD_AGE, &expire) + || (expire==(uint32)-1) || (expire == 0)) { + pdb_set_pass_must_change_time (sampass, get_time_t_max() , PDB_SET); + } else { + pdb_set_pass_must_change_time (sampass, pdb_get_pass_last_set_time(sampass) + + expire, PDB_SET); + } + } else { + pdb_set_pass_must_change_time (sampass, pdb_get_pass_last_set_time(sampass), PDB_SET); + } + + pdb_set_username(sampass, username, PDB_SET); + pdb_set_domain(sampass, domain, PDB_SET); + pdb_set_nt_username(sampass, nt_username, PDB_SET); + pdb_set_fullname(sampass, fullname, PDB_SET); + + if (homedir) { + fstrcpy( tmpstring, homedir ); + standard_sub_basic( username, tmpstring, sizeof(tmpstring) ); + pdb_set_homedir(sampass, tmpstring, PDB_SET); + } + else { + pdb_set_homedir(sampass, + talloc_sub_basic(sampass->mem_ctx, username, lp_logon_home()), + PDB_DEFAULT); + } + + if (dir_drive) + pdb_set_dir_drive(sampass, dir_drive, PDB_SET); + else + pdb_set_dir_drive(sampass, lp_logon_drive(), PDB_DEFAULT ); + + if (logon_script) { + fstrcpy( tmpstring, logon_script ); + standard_sub_basic( username, tmpstring, sizeof(tmpstring) ); + pdb_set_logon_script(sampass, tmpstring, PDB_SET); + } + else { + pdb_set_logon_script(sampass, + talloc_sub_basic(sampass->mem_ctx, username, lp_logon_script()), + PDB_DEFAULT); + } + + if (profile_path) { + fstrcpy( tmpstring, profile_path ); + standard_sub_basic( username, tmpstring, sizeof(tmpstring) ); + pdb_set_profile_path(sampass, tmpstring, PDB_SET); + } + else { + pdb_set_profile_path(sampass, + talloc_sub_basic(sampass->mem_ctx, username, lp_logon_path()), + PDB_DEFAULT); + } + + pdb_set_acct_desc(sampass, acct_desc, PDB_SET); + pdb_set_workstations(sampass, workstations, PDB_SET); + pdb_set_munged_dial(sampass, munged_dial, PDB_SET); + + if (lm_pw_ptr && lm_pw_len == LM_HASH_LEN) { + if (!pdb_set_lanman_passwd(sampass, lm_pw_ptr, PDB_SET)) { + ret = False; + goto done; + } + } + + if (nt_pw_ptr && nt_pw_len == NT_HASH_LEN) { + if (!pdb_set_nt_passwd(sampass, nt_pw_ptr, PDB_SET)) { + ret = False; + goto done; + } + } + + /* Change from V1 is addition of password history field. */ + account_policy_get(AP_PASSWORD_HISTORY, &pwHistLen); + if (pwHistLen) { + uint8 *pw_hist = SMB_MALLOC(pwHistLen * PW_HISTORY_ENTRY_LEN); + if (!pw_hist) { + ret = False; + goto done; + } + memset(pw_hist, '\0', pwHistLen * PW_HISTORY_ENTRY_LEN); + if (nt_pw_hist_ptr && nt_pw_hist_len) { + int i; + SMB_ASSERT((nt_pw_hist_len % PW_HISTORY_ENTRY_LEN) == 0); + nt_pw_hist_len /= PW_HISTORY_ENTRY_LEN; + for (i = 0; (i < pwHistLen) && (i < nt_pw_hist_len); i++) { + memcpy(&pw_hist[i*PW_HISTORY_ENTRY_LEN], + &nt_pw_hist_ptr[i*PW_HISTORY_ENTRY_LEN], + PW_HISTORY_ENTRY_LEN); + } + } + if (!pdb_set_pw_history(sampass, pw_hist, pwHistLen, PDB_SET)) { + SAFE_FREE(pw_hist); + ret = False; + goto done; + } + SAFE_FREE(pw_hist); + } else { + pdb_set_pw_history(sampass, NULL, 0, PDB_SET); + } + + pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET); + pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET); + pdb_set_hours_len(sampass, hours_len, PDB_SET); + pdb_set_bad_password_count(sampass, bad_password_count, PDB_SET); + pdb_set_logon_count(sampass, logon_count, PDB_SET); + pdb_set_unknown_6(sampass, unknown_6, PDB_SET); + pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET); + pdb_set_logon_divs(sampass, logon_divs, PDB_SET); + pdb_set_hours(sampass, hours, PDB_SET); + +done: + + SAFE_FREE(username); + SAFE_FREE(domain); + SAFE_FREE(nt_username); + SAFE_FREE(fullname); + SAFE_FREE(homedir); + SAFE_FREE(dir_drive); + SAFE_FREE(logon_script); + SAFE_FREE(profile_path); + SAFE_FREE(acct_desc); + SAFE_FREE(workstations); + SAFE_FREE(munged_dial); + SAFE_FREE(unknown_str); + SAFE_FREE(lm_pw_ptr); + SAFE_FREE(nt_pw_ptr); + SAFE_FREE(nt_pw_hist_ptr); + SAFE_FREE(hours); + + return ret; +} + +uint32 init_buffer_from_sam_v3 (uint8 **buf, const SAM_ACCOUNT *sampass, BOOL size_only) { size_t len, buflen; @@ -1992,6 +2228,10 @@ bad_password_time = (uint32)pdb_get_bad_password_time(sampass); pass_can_change_time = (uint32)pdb_get_pass_can_change_time(sampass); pass_must_change_time = (uint32)pdb_get_pass_must_change_time(sampass); + + if(pass_must_change_time) + pass_must_change_time = 1; + pass_last_set_time = (uint32)pdb_get_pass_last_set_time(sampass); user_rid = pdb_get_user_rid(sampass); @@ -2115,10 +2355,10 @@ munged_dial_len = 0; } -/* TDB_FORMAT_STRING_V2 "dddddddBBBBBBBBBBBBddBBBwwdBwwd" */ +/* TDB_FORMAT_STRING_V3 "dddddddBBBBBBBBBBBBddBBBwwdBwwd" */ /* one time to get the size needed */ - len = tdb_pack(NULL, 0, TDB_FORMAT_STRING_V2, + len = tdb_pack(NULL, 0, TDB_FORMAT_STRING_V3, logon_time, /* d */ logoff_time, /* d */ kickoff_time, /* d */ @@ -2157,7 +2397,7 @@ /* malloc the space needed */ if ( (*buf=(uint8*)SMB_MALLOC(len)) == NULL) { - DEBUG(0,("init_buffer_from_sam_v2: Unable to malloc() memory for buffer!\n")); + DEBUG(0,("init_buffer_from_sam_v3: Unable to malloc() memory for buffer!\n")); return (-1); } @@ -2197,7 +2437,7 @@ /* check to make sure we got it correct */ if (buflen != len) { - DEBUG(0, ("init_buffer_from_sam_v2: somthing odd is going on here: bufflen (%lu) != len (%lu) in tdb_pack operations!\n", + DEBUG(0, ("init_buffer_from_sam_v3: somthing odd is going on here: bufflen (%lu) != len (%lu) in tdb_pack operations!\n", (unsigned long)buflen, (unsigned long)len)); /* error */ SAFE_FREE (*buf); @@ -2216,7 +2456,7 @@ if ((*dst == NULL) && (!NT_STATUS_IS_OK(pdb_init_sam(dst)))) return False; - len = init_buffer_from_sam_v2(&buf, src, False); + len = init_buffer_from_sam_v3(&buf, src, False); if (len == -1) return False; diff -u -r samba-3.0.20rc1/source/passdb/pdb_get_set.c samba-3.0.20rc1.pw_must_change_update/source/passdb/pdb_get_set.c --- samba-3.0.20rc1/source/passdb/pdb_get_set.c 2005-07-28 08:19:48.000000000 -0500 +++ samba-3.0.20rc1.pw_must_change_update/source/passdb/pdb_get_set.c 2005-08-09 11:23:48.000000000 -0500 @@ -1108,7 +1108,7 @@ /* Helpful interfaces to the above */ /********************************************************************* - Sets the last changed times and must change times for a normal + Sets the last changed times and can change times for a normal password change. ********************************************************************/ @@ -1123,16 +1123,8 @@ 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) || (expire == 0)) { - 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_set_pass_must_change_time (sampass, 1, PDB_CHANGED)) + return False; if (!account_policy_get(AP_MIN_PASSWORD_AGE, &min_age) || (min_age==(uint32)-1)) { diff -u -r samba-3.0.20rc1/source/passdb/pdb_ldap.c samba-3.0.20rc1.pw_must_change_update/source/passdb/pdb_ldap.c --- samba-3.0.20rc1/source/passdb/pdb_ldap.c 2005-07-28 08:19:48.000000000 -0500 +++ samba-3.0.20rc1.pw_must_change_update/source/passdb/pdb_ldap.c 2005-08-09 13:10:50.000000000 -0500 @@ -450,7 +450,8 @@ acct_desc, workstations; char munged_dial[2048]; - uint32 user_rid; + uint32 user_rid, + expire; uint8 smblmpwd[LM_HASH_LEN], smbntpwd[NT_HASH_LEN]; BOOL use_samba_attrs = True; @@ -599,7 +600,20 @@ /* leave as default */ } else { pass_must_change_time = (time_t) atol(temp); - pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET); + if(pass_must_change_time) { + /* pwd_must_change value of 0 means password must change, + otherwise we need to calculate based on account policy */ + + if (!account_policy_get(AP_MAX_PASSWORD_AGE, &expire) + || (expire==(uint32)-1) || (expire == 0)) { + pdb_set_pass_must_change_time (sampass, get_time_t_max() , PDB_SET); + } else { + pdb_set_pass_must_change_time (sampass, pdb_get_pass_last_set_time(sampass) + + expire, PDB_SET); + } + } else { + pdb_set_pass_must_change_time(sampass, pdb_get_pass_last_set_time(sampass), PDB_SET); + } } /* recommend that 'gecos' and 'displayName' should refer to the same @@ -892,7 +906,8 @@ enum pdb_elements)) { pstring temp; - uint32 rid; + uint32 rid, + pass_must_change_time; if (mods == NULL || sampass == NULL) { DEBUG(0, ("init_ldap_from_sam: NULL parameters found!\n")); @@ -1047,7 +1062,11 @@ smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods, get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_CAN_CHANGE), temp); - slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_must_change_time(sampass)); + pass_must_change_time = pdb_get_pass_must_change_time(sampass); + if(pass_must_change_time) + pass_must_change_time = 1; + + slprintf (temp, sizeof (temp) - 1, "%li", pass_must_change_time); if (need_update(sampass, PDB_MUSTCHANGETIME)) smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods, get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_MUST_CHANGE), temp); diff -u -r samba-3.0.20rc1/source/passdb/pdb_tdb.c samba-3.0.20rc1.pw_must_change_update/source/passdb/pdb_tdb.c --- samba-3.0.20rc1/source/passdb/pdb_tdb.c 2005-02-25 11:59:35.000000000 -0600 +++ samba-3.0.20rc1.pw_must_change_update/source/passdb/pdb_tdb.c 2005-08-09 11:23:48.000000000 -0500 @@ -129,6 +129,9 @@ case 2: ret = init_sam_from_buffer_v2(user, (uint8 *)data.dptr, data.dsize); break; + case 3: + ret = init_sam_from_buffer_v3(user, (uint8 *)data.dptr, data.dsize); + break; default: /* unknown tdbsam version */ ret = False; diff -u -r samba-3.0.20rc1/source/utils/pdbedit.c samba-3.0.20rc1.pw_must_change_update/source/utils/pdbedit.c --- samba-3.0.20rc1/source/utils/pdbedit.c 2005-07-28 08:19:51.000000000 -0500 +++ samba-3.0.20rc1.pw_must_change_update/source/utils/pdbedit.c 2005-08-09 13:12:15.000000000 -0500 @@ -304,7 +304,7 @@ const char *profile, const char *account_control, const char *user_sid, const char *group_sid, const BOOL badpw, const BOOL hours, - time_t pwd_can_change, time_t pwd_must_change) + time_t pwd_can_change, const char *pwd_must_change) { BOOL updated_autolock = False, updated_badpw = False; SAM_ACCOUNT *sam_pwent=NULL; @@ -333,8 +333,18 @@ pdb_set_pass_can_change_time(sam_pwent, pwd_can_change, PDB_CHANGED); } - if (pwd_must_change != -1) { - pdb_set_pass_must_change_time(sam_pwent, pwd_must_change, PDB_CHANGED); + if (pwd_must_change) { + + DEBUG(1, ("pwd_must_change is not NULL\n")); + if(strncmp(pwd_must_change, "yes", strlen(pwd_must_change)) == 0) { + DEBUG(1, ("pwd_must_change was yes\n")); + pdb_set_pass_must_change_time(sam_pwent, 0, PDB_CHANGED); + } else { + if(strncmp(pwd_must_change, "no", strlen(pwd_must_change)) == 0) { + DEBUG(1, ("pwd_must_change was no\n")); + pdb_set_pass_must_change_time(sam_pwent, 1, PDB_CHANGED); + } + } } if (!pdb_update_autolock_flag(sam_pwent, &updated_autolock)) { @@ -664,7 +674,7 @@ static BOOL badpw_reset = False; static BOOL hours_reset = False; static char *pwd_can_change_time = NULL; - static char *pwd_must_change_time = NULL; + static char *pwd_must_change = NULL; static char *pwd_time_format = NULL; struct pdb_context *bin; @@ -700,7 +710,7 @@ {"bad-password-count-reset", 'z', POPT_ARG_NONE, &badpw_reset, 0, "reset bad password count", NULL}, {"logon-hours-reset", 'Z', POPT_ARG_NONE, &hours_reset, 0, "reset logon hours", NULL}, {"pwd-can-change-time", 0, POPT_ARG_STRING, &pwd_can_change_time, 0, "Set password can change time (unix time in seconds since 1970 if time format not provided)", NULL }, - {"pwd-must-change-time", 0, POPT_ARG_STRING, &pwd_must_change_time, 0, "Set password can change time (unix time in seconds since 1970 if time format not provided)", NULL }, + {"pwd-must-change", 0, POPT_ARG_STRING, &pwd_must_change, 0, "Set passsword must change flag (yes or no)", NULL }, {"time-format", 0, POPT_ARG_STRING, &pwd_time_format, 0, "The time format for time parameters", NULL }, POPT_COMMON_SAMBA POPT_TABLEEND @@ -758,7 +768,7 @@ (badpw_reset ? BIT_BADPWRESET : 0) + (hours_reset ? BIT_LOGONHOURS : 0) + (pwd_can_change_time ? BIT_CAN_CHANGE: 0) + - (pwd_must_change_time ? BIT_MUST_CHANGE: 0); + (pwd_must_change ? BIT_MUST_CHANGE: 0); if (setparms & BIT_BACKEND) { if (!NT_STATUS_IS_OK(make_pdb_context_string(&bdef, backend))) { @@ -878,6 +888,11 @@ checkparms |= BIT_MODIFY; checkparms &= ~BIT_LOGONHOURS; } + + if (checkparms & BIT_MUST_CHANGE) { + checkparms |= BIT_MODIFY; + checkparms &= ~BIT_MUST_CHANGE; + } /* account operation */ if ((checkparms & BIT_CREATE) || (checkparms & BIT_MODIFY) || (checkparms & BIT_DELETE)) { @@ -910,7 +925,6 @@ /* account modification operations */ if (!(checkparms & ~(BIT_MODIFY + BIT_USER))) { time_t pwd_can_change = -1; - time_t pwd_must_change = -1; const char *errstr; if (pwd_can_change_time) { @@ -938,31 +952,6 @@ } } } - if (pwd_must_change_time) { - errstr = "must"; - if (pwd_time_format) { - struct tm tm; - char *ret; - - memset(&tm, 0, sizeof(struct tm)); - ret = strptime(pwd_must_change_time, pwd_time_format, &tm); - if (ret == NULL || *ret != '\0') { - goto error; - } - - pwd_must_change = mktime(&tm); - - if (pwd_must_change == -1) { - goto error; - } - } else { /* assume it is unix time */ - errno = 0; - pwd_must_change = strtol(pwd_must_change_time, NULL, 10); - if (errno) { - goto error; - } - } - } return set_user_info (bdef, user_name, full_name, home_dir, acct_desc,