summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/LDAP/samba.schema7
-rw-r--r--source3/include/passdb.h8
-rw-r--r--source3/include/smbldap.h5
-rw-r--r--source3/lib/smbldap.c24
-rw-r--r--source3/passdb/pdb_get_set.c90
-rw-r--r--source3/passdb/pdb_ldap.c72
-rw-r--r--source3/passdb/pdb_tdb.c1
-rw-r--r--source3/smbd/chgpasswd.c85
8 files changed, 251 insertions, 41 deletions
diff --git a/examples/LDAP/samba.schema b/examples/LDAP/samba.schema
index 71c954a0c0..0ad94f973d 100644
--- a/examples/LDAP/samba.schema
+++ b/examples/LDAP/samba.schema
@@ -251,6 +251,11 @@ attributetype ( 1.3.6.1.4.1.7165.2.1.47 NAME 'sambaMungedDial'
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.50 NAME 'sambaPasswordHistory'
+ 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
##
@@ -329,7 +334,7 @@ objectclass ( 1.3.6.1.4.1.7165.2.2.6 NAME 'sambaSamAccount' SUP top AUXILIARY
displayName $ sambaHomePath $ sambaHomeDrive $ sambaLogonScript $
sambaProfilePath $ description $ sambaUserWorkstations $
sambaPrimaryGroupSID $ sambaDomainName $ sambaMungedDial $
- sambaBadPasswordCount $ sambaBadPasswordTime))
+ sambaBadPasswordCount $ sambaBadPasswordTime $ sambaPasswordHistory))
##
## Group mapping info
diff --git a/source3/include/passdb.h b/source3/include/passdb.h
index d08fd13a72..7d3e0014b6 100644
--- a/source3/include/passdb.h
+++ b/source3/include/passdb.h
@@ -99,6 +99,7 @@ enum pdb_elements {
PDB_UNKNOWN6,
PDB_LMPASSWD,
PDB_NTPASSWD,
+ PDB_PWHISTORY,
PDB_BACKEND_PRIVATE_DATA,
/* this must be the last element */
@@ -165,16 +166,17 @@ typedef struct sam_passwd
const char * dir_drive; /* home directory drive string */
const char * logon_script; /* logon script string */
const char * profile_path; /* profile path string */
- const char * acct_desc ; /* user description string */
+ const char * acct_desc; /* user description string */
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 char * unknown_str; /* don't know what this is, yet. */
+ const char * munged_dial; /* munged path name and dial-back tel number */
DOM_SID user_sid; /* Primary User SID */
DOM_SID group_sid; /* Primary Group SID */
DATA_BLOB lm_pw; /* .data is Null if no password */
DATA_BLOB nt_pw; /* .data is Null if no password */
+ DATA_BLOB nt_pw_his; /* nt hashed password history .data is Null if not available */
char* plaintext_pw; /* is Null if not available */
uint16 acct_ctrl; /* account info (ACB_xxxx bit-mask) */
diff --git a/source3/include/smbldap.h b/source3/include/smbldap.h
index c7de7d84b3..b94577178b 100644
--- a/source3/include/smbldap.h
+++ b/source3/include/smbldap.h
@@ -93,8 +93,9 @@
#define LDAP_ATTR_LOGON_COUNT 36
#define LDAP_ATTR_MUNGED_DIAL 37
#define LDAP_ATTR_BAD_PASSWORD_TIME 38
-
-#define LDAP_ATTR_SID_LIST 40
+#define LDAP_ATTR_PWD_HISTORY 39
+#define LDAP_ATTR_SID_LIST 40
+#define LDAP_ATTR_MOD_TIMESTAMP 41
typedef struct _attrib_map_entry {
int attrib;
diff --git a/source3/lib/smbldap.c b/source3/lib/smbldap.c
index d058613f00..9b6d597606 100644
--- a/source3/lib/smbldap.c
+++ b/source3/lib/smbldap.c
@@ -100,6 +100,8 @@ ATTRIB_MAP_ENTRY attrib_map_v30[] = {
{ LDAP_ATTR_MUNGED_DIAL, "sambaMungedDial" },
{ LDAP_ATTR_BAD_PASSWORD_COUNT, "sambaBadPasswordCount" },
{ LDAP_ATTR_BAD_PASSWORD_TIME, "sambaBadPasswordTime" },
+ { LDAP_ATTR_PWD_HISTORY, "sambaPasswordHistory" },
+ { LDAP_ATTR_MOD_TIMESTAMP, "modifyTimestamp" },
{ LDAP_ATTR_LIST_END, NULL }
};
@@ -345,19 +347,19 @@ static BOOL fetch_ldap_pw(char **dn, char** pw)
/* sanity checks on the mod values */
- if (attribute == NULL || *attribute == '\0')
+ if (attribute == NULL || *attribute == '\0') {
return;
+ }
+
#if 0 /* commented out after discussion with abartlet. Do not reenable.
left here so other so re-add similar code --jerry */
if (value == NULL || *value == '\0')
return;
#endif
- if (mods == NULL)
- {
+ if (mods == NULL) {
mods = (LDAPMod **) malloc(sizeof(LDAPMod *));
- if (mods == NULL)
- {
+ if (mods == NULL) {
DEBUG(0, ("make_a_mod: out of memory!\n"));
return;
}
@@ -369,17 +371,14 @@ static BOOL fetch_ldap_pw(char **dn, char** pw)
break;
}
- if (mods[i] == NULL)
- {
+ if (mods[i] == NULL) {
mods = (LDAPMod **) Realloc (mods, (i + 2) * sizeof (LDAPMod *));
- if (mods == NULL)
- {
+ if (mods == NULL) {
DEBUG(0, ("make_a_mod: out of memory!\n"));
return;
}
mods[i] = (LDAPMod *) malloc(sizeof(LDAPMod));
- if (mods[i] == NULL)
- {
+ if (mods[i] == NULL) {
DEBUG(0, ("make_a_mod: out of memory!\n"));
return;
}
@@ -389,8 +388,7 @@ static BOOL fetch_ldap_pw(char **dn, char** pw)
mods[i + 1] = NULL;
}
- if (value != NULL)
- {
+ if (value != NULL) {
char *utf8_value = NULL;
j = 0;
diff --git a/source3/passdb/pdb_get_set.c b/source3/passdb/pdb_get_set.c
index e69dac524f..4abb951d7b 100644
--- a/source3/passdb/pdb_get_set.c
+++ b/source3/passdb/pdb_get_set.c
@@ -150,6 +150,19 @@ const uint8* pdb_get_lanman_passwd (const SAM_ACCOUNT *sampass)
return (NULL);
}
+const uint8* pdb_get_pw_history (const SAM_ACCOUNT *sampass, uint32 *current_hist_len)
+{
+ if (sampass) {
+ SMB_ASSERT((!sampass->private.nt_pw_his.data)
+ || ((sampass->private.nt_pw_his.length % NT_HASH_LEN) == 0));
+ *current_hist_len = sampass->private.nt_pw_his.length / NT_HASH_LEN;
+ return ((uint8*)sampass->private.nt_pw_his.data);
+ } else {
+ *current_hist_len = 0;
+ return (NULL);
+ }
+}
+
/* Return the plaintext password if known. Most of the time
it isn't, so don't assume anything magic about this function.
@@ -982,6 +995,30 @@ BOOL pdb_set_lanman_passwd (SAM_ACCOUNT *sampass, const uint8 pwd[LM_HASH_LEN],
}
/*********************************************************************
+ Set the user's password history hash. historyLen is the number of NT_HASH_LEN
+ entries to store in the history - this must match the size of the uint8 array
+ in pwd.
+********************************************************************/
+
+BOOL pdb_set_pw_history (SAM_ACCOUNT *sampass, const uint8 *pwd, uint32 historyLen, enum pdb_value_state flag)
+{
+ if (!sampass)
+ return False;
+
+ if (historyLen && pwd){
+ sampass->private.nt_pw_his = data_blob_talloc(sampass->mem_ctx, pwd, historyLen*NT_HASH_LEN);
+ if (!sampass->private.nt_pw_his.length) {
+ DEBUG(0, ("pdb_set_pw_history: data_blob_talloc() failed!\n"));
+ return False;
+ }
+ } else {
+ sampass->private.nt_pw_his = data_blob_talloc(sampass->mem_ctx, NULL, 0);
+ }
+
+ return pdb_set_init_flags(sampass, PDB_PWHISTORY, flag);
+}
+
+/*********************************************************************
Set the user's plaintext password only (base procedure, see helper
below)
********************************************************************/
@@ -1133,12 +1170,20 @@ BOOL pdb_set_pass_changed_now (SAM_ACCOUNT *sampass)
BOOL pdb_set_plaintext_passwd (SAM_ACCOUNT *sampass, const char *plaintext)
{
- uchar new_lanman_p16[16];
- uchar new_nt_p16[16];
+ uchar new_lanman_p16[LM_HASH_LEN];
+ uchar new_nt_p16[NT_HASH_LEN];
+ uchar current_ntpw_copy[NT_HASH_LEN];
+ uchar *current_ntpw = NULL;
if (!sampass || !plaintext)
return False;
-
+
+ /* Store the current password for history purposes. */
+ current_ntpw = (uint8 *)pdb_get_nt_passwd(sampass);
+ if (current_ntpw) {
+ memcpy (current_ntpw_copy, current_ntpw, NT_HASH_LEN);
+ }
+
/* Calculate the MD4 hash (NT compatible) of the password */
E_md4hash(plaintext, new_nt_p16);
@@ -1164,6 +1209,45 @@ BOOL pdb_set_plaintext_passwd (SAM_ACCOUNT *sampass, const char *plaintext)
if (!pdb_set_pass_changed_now (sampass))
return False;
+ /* Store the password history. */
+ if (pdb_get_acct_ctrl(sampass) & ACB_NORMAL) {
+ uchar *pwhistory;
+ uint32 pwHistLen;
+ account_policy_get(AP_PASSWORD_HISTORY, &pwHistLen);
+ if (pwHistLen != 0){
+ uint32 current_history_len;
+ /* We need to make sure we don't have a race condition here - the
+ account policy history length can change between when the pw_history
+ was first loaded into the SAM_ACCOUNT struct and now.... JRA. */
+ pwhistory = (uchar *)pdb_get_pw_history(sampass, &current_history_len);
+
+ if (current_history_len != pwHistLen) {
+ /* After closing and reopening SAM_ACCOUNT the history
+ values will sync up. We can't do this here. */
+
+ /* current_history_len > pwHistLen is not a problem - we
+ have more history than we need. */
+
+ if (current_history_len < pwHistLen) {
+ /* We only have room for current_history_len entries. */
+ pwHistLen = current_history_len;
+ }
+ }
+ if (pwhistory && current_ntpw && pwHistLen){
+ if (pwHistLen > 1) {
+ memmove(&pwhistory[NT_HASH_LEN], pwhistory, (pwHistLen -1)*NT_HASH_LEN );
+ }
+ memcpy(pwhistory, current_ntpw_copy, NT_HASH_LEN);
+ pdb_set_pw_history(sampass, pwhistory, pwHistLen, PDB_CHANGED);
+ } else {
+ DEBUG (10,("pdb_get_set.c: pdb_set_plaintext_passwd: pwhistory was NULL!\n"));
+ }
+ } else {
+ /* Set the history length to zero. */
+ pdb_set_pw_history(sampass, NULL, 0, PDB_CHANGED);
+ }
+ }
+
return True;
}
diff --git a/source3/passdb/pdb_ldap.c b/source3/passdb/pdb_ldap.c
index d2ee9a2d9d..fed92cea56 100644
--- a/source3/passdb/pdb_ldap.c
+++ b/source3/passdb/pdb_ldap.c
@@ -81,8 +81,6 @@
#define SAM_ACCOUNT struct sam_passwd
#endif
-#define MODIFY_TIMESTAMP_STRING "modifyTimestamp"
-
#include "smbldap.h"
struct ldapsam_privates {
@@ -301,7 +299,9 @@ static NTSTATUS ldapsam_delete_entry(struct ldapsam_privates *ldap_state,
really exist. */
for (attrib = attrs; *attrib != NULL; attrib++) {
- if (StrCaseCmp(*attrib, name) == 0) {
+ if ((StrCaseCmp(*attrib, name) == 0) &&
+ !(StrCaseCmp(*attrib,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_MOD_TIMESTAMP)))) {
DEBUG(10, ("ldapsam_delete_entry: deleting attribute %s\n", name));
smbldap_set_mod(&mods, LDAP_MOD_DELETE, name, NULL);
}
@@ -400,8 +400,9 @@ static time_t ldapsam_get_entry_timestamp(
pstring temp;
struct tm tm;
- if (!smbldap_get_single_pstring(ldap_state->smbldap_state->ldap_struct,
- entry, MODIFY_TIMESTAMP_STRING, temp))
+ if (!smbldap_get_single_pstring(ldap_state->smbldap_state->ldap_struct, entry,
+ get_userattr_key2string(ldap_state->schema_ver,LDAP_ATTR_MOD_TIMESTAMP),
+ temp))
return (time_t) 0;
strptime(temp, "%Y%m%d%H%M%SZ", &tm);
@@ -448,6 +449,7 @@ static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state,
uint8 hours[MAX_HOURS_LEN];
pstring temp;
LOGIN_CACHE *cache_entry = NULL;
+ int pwHistLen;
/*
* do a little initialization
@@ -694,6 +696,37 @@ static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state,
ZERO_STRUCT(smbntpwd);
}
+ account_policy_get(AP_PASSWORD_HISTORY, &pwHistLen);
+ if (pwHistLen > 0){
+ uint8 *pwhist = NULL;
+ int i;
+
+ if ((pwhist = malloc(NT_HASH_LEN * pwHistLen)) == NULL){
+ DEBUG(0, ("init_sam_from_ldap: malloc failed!\n"));
+ return False;
+ }
+ memset(pwhist, '\0', NT_HASH_LEN * pwHistLen);
+
+ if (!smbldap_get_single_pstring (ldap_state->smbldap_state->ldap_struct, entry,
+ get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_HISTORY), temp)) {
+ /* leave as default - zeros */
+ } else {
+ for (i = 0; i < pwHistLen; i++){
+ if (!pdb_gethexpwd(&temp[i*32], smbntpwd)) {
+ break;
+ }
+ memset(&temp[i*32], '\0', 32);
+ memcpy(&pwhist[i*NT_HASH_LEN], smbntpwd, NT_HASH_LEN);
+ ZERO_STRUCT(smbntpwd);
+ }
+ }
+ if (!pdb_set_pw_history(sampass, pwhist, pwHistLen, PDB_SET)){
+ SAFE_FREE(pwhist);
+ return False;
+ }
+ SAFE_FREE(pwhist);
+ }
+
if (!smbldap_get_single_pstring (ldap_state->smbldap_state->ldap_struct, entry,
get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_ACB_INFO), temp)) {
acct_ctrl |= ACB_NORMAL;
@@ -781,7 +814,7 @@ static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state,
}
/**********************************************************************
- Initialize SAM_ACCOUNT from an LDAP query.
+ Initialize the ldap db from a SAM_ACCOUNT. Called on update.
(Based on init_buffer_from_sam in pdb_tdb.c)
*********************************************************************/
@@ -985,6 +1018,29 @@ static BOOL init_ldap_from_sam (struct ldapsam_privates *ldap_state,
}
}
+ if (need_update(sampass, PDB_PWHISTORY)) {
+ int pwHistLen = 0;
+ account_policy_get(AP_PASSWORD_HISTORY, &pwHistLen);
+ if (pwHistLen == 0) {
+ /* Remove any password history from the LDAP store. */
+ pstrcpy(temp, "00000000000000000000000000000000");
+ } else {
+ int i, currHistLen = 0;
+ const uint8 *pwhist = pdb_get_pw_history(sampass, &currHistLen);
+ if (pwhist != NULL) {
+ /* We can only store (sizeof(pstring)-1)/32 password history entries. */
+ pwHistLen = MIN(pwHistLen, ((sizeof(temp)-1)/32));
+ for (i=0; i< pwHistLen && i < currHistLen; i++) {
+ pdb_sethexpwd (&temp[i*32], &pwhist[i*NT_HASH_LEN], 0);
+ DEBUG(100, ("temp=%s\n", 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,
@@ -1162,7 +1218,7 @@ static NTSTATUS ldapsam_getsampwnam(struct pdb_methods *my_methods, SAM_ACCOUNT
int rc;
attr_list = get_userattr_list( ldap_state->schema_ver );
- append_attr(&attr_list, MODIFY_TIMESTAMP_STRING);
+ append_attr(&attr_list, get_userattr_key2string(ldap_state->schema_ver,LDAP_ATTR_MOD_TIMESTAMP));
rc = ldapsam_search_suffix_by_name(ldap_state, sname, &result, attr_list);
free_attr_list( attr_list );
@@ -1208,7 +1264,7 @@ static int ldapsam_get_ldap_user_by_sid(struct ldapsam_privates *ldap_state,
switch ( ldap_state->schema_ver ) {
case SCHEMAVER_SAMBASAMACCOUNT:
attr_list = get_userattr_list(ldap_state->schema_ver);
- append_attr(&attr_list, MODIFY_TIMESTAMP_STRING);
+ append_attr(&attr_list, get_userattr_key2string(ldap_state->schema_ver,LDAP_ATTR_MOD_TIMESTAMP));
rc = ldapsam_search_suffix_by_sid(ldap_state, sid, result, attr_list);
free_attr_list( attr_list );
diff --git a/source3/passdb/pdb_tdb.c b/source3/passdb/pdb_tdb.c
index 9bfb10c400..2cf7c55049 100644
--- a/source3/passdb/pdb_tdb.c
+++ b/source3/passdb/pdb_tdb.c
@@ -746,4 +746,3 @@ NTSTATUS pdb_tdbsam_init(void)
{
return smb_register_passdb(PASSDB_INTERFACE_VERSION, "tdbsam", pdb_init_tdbsam);
}
-
diff --git a/source3/smbd/chgpasswd.c b/source3/smbd/chgpasswd.c
index ca13a167fb..a1b90c8fed 100644
--- a/source3/smbd/chgpasswd.c
+++ b/source3/smbd/chgpasswd.c
@@ -933,6 +933,65 @@ static NTSTATUS check_oem_password(const char *user,
}
/***********************************************************
+ 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.
NOTE this function is designed to be called as root. Check the old password
@@ -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;
}