summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerald Carter <jerry@samba.org>2004-08-06 05:44:26 +0000
committerGerald Carter <jerry@samba.org>2004-08-06 05:44:26 +0000
commit547587d57c0ca7fa5babac358d4b2f67a472e142 (patch)
treeabbcd3ba0d6ab0e15317fc0930a3c8e109f322f9
parentfecd5ea163ffcd1bbee5b06e05112dbff9aa71b1 (diff)
downloadsamba-3.0.6rc2.tar.gz
samba-3.0.6rc2.tar.xz
samba-3.0.6rc2.zip
r1664: last changes before 3.0.6rc2samba-3.0.6rc2
-rw-r--r--WHATSNEW.txt133
-rw-r--r--examples/LDAP/samba.schema13
-rwxr-xr-xsource/client/mount.cifs.c42
-rw-r--r--source/include/smb.h5
-rw-r--r--source/lib/snprintf.c2
-rw-r--r--source/libsmb/smbencrypt.c20
-rw-r--r--source/nsswitch/winbindd_group.c56
-rw-r--r--source/nsswitch/winbindd_user.c8
-rw-r--r--source/param/loadparm.c2
-rw-r--r--source/passdb/passdb.c14
-rw-r--r--source/passdb/pdb_get_set.c37
-rw-r--r--source/smbd/chgpasswd.c20
12 files changed, 308 insertions, 44 deletions
diff --git a/WHATSNEW.txt b/WHATSNEW.txt
index ea97e56844f..b53ffe549aa 100644
--- a/WHATSNEW.txt
+++ b/WHATSNEW.txt
@@ -1,6 +1,6 @@
================================
Release Notes for Samba 3.0.6rc2
- Aug 3, 2004
+ Aug 5, 2004
================================
This is a release candidate snapshot of the Samba 3.0.5 code
@@ -17,13 +17,38 @@ exact updates.
Common bugs fixed in 3.0.6rc2 include:
- o
+ o Fix stalls in smbd caused by inaccessible LDAP servers.
+ o Remove various memory leaks.
+ o Fix issues in the password lockout feature.
+ o Merge security fixes for CAN-2004-0600, CAN-2004-0686
+ from 3.0.5.
New features introduced in this release include:
o Support for maintaining user password history.
-
+------------------------
+Password History Support
+------------------------
+
+The new password history feature allows smbd to check the new
+password in password change requests against a list of the user's
+previous passwords. The number of previous passwords to save can be
+set using pdbedit (4 in this example):
+
+ root# pdbedit -P "password history" -C 4
+
+When using the ldapsam passdb backend, it is vital to secure
+the following attributes from access by non-administrative
+users:
+
+ * sambaNTPassword
+ * sambaLMPassword
+ * sambaPasswordHistory
+
+You should refer to your directory server's documentation on how
+to implement this restriction).
+
######################################################################
Changes
#######
@@ -37,6 +62,7 @@ smb.conf changes
Parameter Name Action
-------------- ------
+ ldap timeout New
commits
@@ -45,9 +71,108 @@ o Jeremy Allison <jra@samba.org>
* Add support for storing a user's password history.
LDAP portion of the code was based on a patch from
Jianliang Lu <j.lu@tiesse.com>.
+ * Correct memory leaks found in the password change code.
+ * Fix support for the mknod command with the Linux CIFS client.
+ * Remove support for passing the new password to smbpasswd
+ on the command line without using the -s option.
+ * Ensure home directory service number is correctly reused
+ (inspired by patches from Michael Collin Nielsen
+ <michael@hum.aau.dk>).
+ * Fix to stop printing accounts from resetting the bas
+ password and account lockout flags.
+ * If a account was locked out by an admin (and has a bad
+ password count of zero) leave it locked out until an admin
+ unlocks it (but log a message).
+
+
+o Tom Alsberg <alsbergt@cs.huji.ac.il>
+ * Allow pdbedit to export a single user from a passdb backend.
+
+
+o Andrew Bartlett <abartlet@samba.org>
+ * Improve smbd's internal random number generation.
+ * Fix a few outstanding long password changes in smbd.
+ * Fix LANMAN2 session setup code.
+
+
+o Gerald Carter <jerry@samba.org>
+ * BUG 1520: Work around bug in Windows XP SP2 RC2 where the
+ client sends a FindNextPrintChangeNotify() request without
+ previously sending a FindFirstPrintChangeNotify(). Return
+ the same error code as Windows 2000 SP4.
+ * BUG 1516: Manually declare ldap_open_with_timeout() to
+ workaround compiler errors on IRIX (or other systems without
+ LDAP headers).
+ * Merge security fixes for CAN-2004-0600, CAN-2004-0686 from
+ 3.0.5.
+ * Corrected syntax error in the OID for sambaUnixIdPool,
+ sambaSidEntry, & sambaIdmapEntry object classes.
+
+
+
+o Fabien Chevalier <fabien.chevalier@supelec.fr>
+ * Debian BUG 252591: Ensure that the return value from the
+ number of available interfaces is initialized in case no
+ interfaces are actually available.
+
+
+o Guenther Deschner <gd@sernet.de>
+ * Display share ACL entries from rpcclient.
+
+
+o Steve French <sfrench@us.ibm.com>
+ * Fix user unmount of shares mount with suid mount.cifs.
+
+
+o Volker Lendecke <vl@samba.org>
+ * Allow the 'idmap backend' parameter to accept a list of
+ LDAP servers for failover purposes.
+ * Revert code in smbd to remove a tdb when it has become
+ corrupted.
+ * Add paranoid checks when mapping SIDs to a uid/gid to
+ ensure that the type is correct.
+ * Initial work on getting client support for sending mailslot
+ datagrams.
+ * Add 'ldap timeout' parameter.
+ * Dont always uppercase 'afs username map'.
+ * Expand aliases for getusersids as well.
+
+
+o James Peach <jpeach@sgi.com>
+ * More iconv detection fixes for IRIX.
+ * Compile fixed for systems that do not have C99/UNIX98 compliant
+ vsnprintf by default.
+
+
+o Tim Potter <tpot@samba.org>
+ * BUG 1360: Use -Bsymbolic when creating shared libraries to
+ avoid conflicts with identical symbols in the global namespace
+ when loading libnss_wins.so.
+
+
+o Richard Renard <rrenard@idealx.com>
+ * Save the current password as it is being changed into the
+ password history list.
+
+
+o Simo Source <idra@samba.org>
+ * Tidy up parametric options in testparm output.
+
+
+o Richard Sharpe <rsharpe@samba.org>
+ * Add sigchild handling to winbindd to restart the child
+ daemon if necessary.
+
+
+o Tom Shaw <tomisfaraway@gmail.com>
+ * Use winbindd_fill_pwent() consistently.
+
+
+o Nick Thompson <nickthompson@agere.com>
+ * Protect smbd against broken filesystems which return zero
+ blocksize.
-
Changes for older versions follow below:
--------------------------------------------------
diff --git a/examples/LDAP/samba.schema b/examples/LDAP/samba.schema
index 71c954a0c00..d87815b3abc 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 'Concatenated MD4 hashes of the unicode passwords used on this account'
+ 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
@@ -350,17 +355,17 @@ objectclass ( 1.3.6.1.4.1.7165.2.2.5 NAME 'sambaDomain' SUP top STRUCTURAL
sambaAlgorithmicRidBase ) )
## used for idmap_ldap module
-objectclass ( 1.3.6.1.4.1.7165.1.2.2.7 NAME 'sambaUnixIdPool' SUP top AUXILIARY
+objectclass ( 1.3.6.1.4.1.7165.2.2.7 NAME 'sambaUnixIdPool' SUP top AUXILIARY
DESC 'Pool for allocating UNIX uids/gids'
MUST ( uidNumber $ gidNumber ) )
-objectclass ( 1.3.6.1.4.1.7165.1.2.2.8 NAME 'sambaIdmapEntry' SUP top AUXILIARY
+objectclass ( 1.3.6.1.4.1.7165.2.2.8 NAME 'sambaIdmapEntry' SUP top AUXILIARY
DESC 'Mapping from a SID to an ID'
MUST ( sambaSID )
MAY ( uidNumber $ gidNumber ) )
-objectclass ( 1.3.6.1.4.1.7165.1.2.2.9 NAME 'sambaSidEntry' SUP top STRUCTURAL
+objectclass ( 1.3.6.1.4.1.7165.2.2.9 NAME 'sambaSidEntry' SUP top STRUCTURAL
DESC 'Structural Class for a SID'
MUST ( sambaSID ) )
diff --git a/source/client/mount.cifs.c b/source/client/mount.cifs.c
index 5670a147468..55934e04b3c 100755
--- a/source/client/mount.cifs.c
+++ b/source/client/mount.cifs.c
@@ -38,7 +38,7 @@
#include <fcntl.h>
#define MOUNT_CIFS_VERSION_MAJOR "1"
-#define MOUNT_CIFS_VERSION_MINOR "3"
+#define MOUNT_CIFS_VERSION_MINOR "4"
#ifndef MOUNT_CIFS_VENDOR_SUFFIX
#define MOUNT_CIFS_VENDOR_SUFFIX ""
@@ -57,6 +57,7 @@ static int got_ip = 0;
static int got_unc = 0;
static int got_uid = 0;
static int got_gid = 0;
+static int free_share_name = 0;
static char * user_name = NULL;
char * mountpassword = NULL;
@@ -502,8 +503,9 @@ static int parse_options(char * options, int * filesys_flags)
}
/* Note that caller frees the returned buffer if necessary */
-char * parse_server(char * unc_name)
+char * parse_server(char ** punc_name)
{
+ char * unc_name = *punc_name;
int length = strnlen(unc_name,1024);
char * share;
char * ipaddress_string = NULL;
@@ -527,11 +529,23 @@ char * parse_server(char * unc_name)
return 0;
} else {
if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
- printf("mount error: improperly formatted UNC name.");
- printf(" %s does not begin with \\\\ or //\n",unc_name);
- return 0;
+ /* check for nfs syntax ie server:share */
+ share = strchr(unc_name,':');
+ if(share) {
+ free_share_name = 1;
+ *punc_name = malloc(length+3);
+ *share = '/';
+ strncpy((*punc_name)+2,unc_name,length);
+ unc_name = *punc_name;
+ unc_name[length+2] = 0;
+ goto continue_unc_parsing;
+ } else {
+ printf("mount error: improperly formatted UNC name.");
+ printf(" %s does not begin with \\\\ or //\n",unc_name);
+ return 0;
+ }
} else {
- unc_name[0] = '\\';
+continue_unc_parsing:
unc_name[0] = '/';
unc_name[1] = '/';
unc_name += 2;
@@ -753,8 +767,7 @@ int main(int argc, char ** argv)
get_password_from_file(0, getenv("PASSWD_FILE"));
}
- ipaddr = parse_server(share_name);
-
+ ipaddr = parse_server(&share_name);
if(ipaddr == NULL)
return -1;
@@ -879,8 +892,9 @@ int main(int argc, char ** argv)
mountent.mnt_fsname = share_name;
mountent.mnt_dir = mountpoint;
mountent.mnt_type = "cifs";
- mountent.mnt_opts = malloc(200);
+ mountent.mnt_opts = malloc(220);
if(mountent.mnt_opts) {
+ char * mount_user = getusername();
memset(mountent.mnt_opts,0,200);
if(flags & MS_RDONLY)
strcat(mountent.mnt_opts,"ro");
@@ -898,6 +912,13 @@ int main(int argc, char ** argv)
strcat(mountent.mnt_opts,",nodev");
if(flags & MS_SYNCHRONOUS)
strcat(mountent.mnt_opts,",synch");
+ if(mount_user) {
+ if(getuid() != 0) {
+ strcat(mountent.mnt_opts,",user=");
+ strcat(mountent.mnt_opts,mount_user);
+ }
+ free(mount_user);
+ }
}
mountent.mnt_freq = 0;
mountent.mnt_passno = 0;
@@ -927,6 +948,9 @@ int main(int argc, char ** argv)
free(resolved_path);
}
+ if(free_share_name) {
+ free(share_name);
+ }
return 0;
}
diff --git a/source/include/smb.h b/source/include/smb.h
index a802e962266..32dba0cf78f 100644
--- a/source/include/smb.h
+++ b/source/include/smb.h
@@ -625,6 +625,11 @@ typedef struct {
#define NT_HASH_LEN 16
#define LM_HASH_LEN 16
+/* Password history contants. */
+#define PW_HISTORY_SALT_LEN 16
+#define SALTED_MD5_HASH_LEN 16
+#define PW_HISTORY_ENTRY_LEN (PW_HISTORY_SALT_LEN+SALTED_MD5_HASH_LEN)
+
/*
* Flags for account policy.
*/
diff --git a/source/lib/snprintf.c b/source/lib/snprintf.c
index 79de3c0ca5d..633517def28 100644
--- a/source/lib/snprintf.c
+++ b/source/lib/snprintf.c
@@ -821,6 +821,7 @@ static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
{
return dopr(str, count, fmt, args);
}
+#define vsnprintf smb_vsnprintf
#endif
/* yes this really must be a ||. Don't muck with this (tridge)
@@ -840,6 +841,7 @@ int smb_snprintf(char *str,size_t count,const char *fmt,...)
va_end(ap);
return ret;
}
+#define snprintf smb_snprintf
#endif
#endif
diff --git a/source/libsmb/smbencrypt.c b/source/libsmb/smbencrypt.c
index 9f936b77aec..d4b05574118 100644
--- a/source/libsmb/smbencrypt.c
+++ b/source/libsmb/smbencrypt.c
@@ -73,6 +73,26 @@ void E_md4hash(const char *passwd, uchar p16[16])
}
/**
+ * Creates the MD5 Hash of a combination of 16 byte salt and 16 byte NT hash.
+ * @param 16 byte salt.
+ * @param 16 byte NT hash.
+ * @param 16 byte return hashed with md5, caller allocated 16 byte buffer
+ */
+
+void E_md5hash(const uchar salt[16], const uchar nthash[16], uchar hash_out[16])
+{
+ struct MD5Context tctx;
+ uchar array[32];
+
+ memset(hash_out, '\0', 16);
+ memcpy(array, salt, 16);
+ memcpy(&array[16], nthash, 16);
+ MD5Init(&tctx);
+ MD5Update(&tctx, array, 32);
+ MD5Final(hash_out, &tctx);
+}
+
+/**
* Creates the DES forward-only Hash of the users password in DOS ASCII charset
* @param passwd password in 'unix' charset.
* @param p16 return password hashed with DES, caller allocated 16 byte buffer
diff --git a/source/nsswitch/winbindd_group.c b/source/nsswitch/winbindd_group.c
index 346a2711b6c..ca7f72d0178 100644
--- a/source/nsswitch/winbindd_group.c
+++ b/source/nsswitch/winbindd_group.c
@@ -1169,6 +1169,48 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
return result;
}
+static void add_sid_to_array_unique(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+ DOM_SID ***sids, int *num_sids)
+{
+ int i;
+
+ for (i=0; i<(*num_sids); i++) {
+ if (sid_compare(sid, (*sids)[i]) == 0)
+ return;
+ }
+
+ *sids = talloc_realloc(mem_ctx, *sids, sizeof(**sids) * (*num_sids+1));
+
+ if (*sids == NULL)
+ return;
+
+ (*sids)[*num_sids] = talloc(mem_ctx, sizeof(DOM_SID));
+ sid_copy((*sids)[*num_sids], sid);
+ *num_sids += 1;
+ return;
+}
+
+static void add_local_sids_from_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
+ DOM_SID ***user_grpsids,
+ int *num_groups)
+{
+ DOM_SID *aliases = NULL;
+ int i, num_aliases = 0;
+
+ if (!pdb_enum_alias_memberships(sid, &aliases, &num_aliases))
+ return;
+
+ if (num_aliases == 0)
+ return;
+
+ for (i=0; i<num_aliases; i++)
+ add_sid_to_array_unique(mem_ctx, &aliases[i], user_grpsids,
+ num_groups);
+
+ SAFE_FREE(aliases);
+
+ return;
+}
/* Get user supplementary sids. This is equivalent to the
winbindd_getgroups() function but it involves a SID->SIDs mapping
@@ -1224,6 +1266,20 @@ enum winbindd_result winbindd_getusersids(struct winbindd_cli_state *state)
goto no_groups;
}
+ if (lp_winbind_nested_groups()) {
+ int k;
+ /* num_groups is changed during the loop, that's why we have
+ to count down here.*/
+
+ for (k=num_groups-1; k>=0; k--) {
+ add_local_sids_from_sid(mem_ctx, user_grpsids[k],
+ &user_grpsids, &num_groups);
+ }
+
+ add_local_sids_from_sid(mem_ctx, &user_sid, &user_grpsids,
+ &num_groups);
+ }
+
/* work out the response size */
for (i = 0; i < num_groups; i++) {
const char *s = sid_string_static(user_grpsids[i]);
diff --git a/source/nsswitch/winbindd_user.c b/source/nsswitch/winbindd_user.c
index c691705f9c0..795d657aae7 100644
--- a/source/nsswitch/winbindd_user.c
+++ b/source/nsswitch/winbindd_user.c
@@ -46,14 +46,14 @@ static BOOL winbindd_fill_pwent(char *dom_name, char *user_name,
/* Resolve the uid number */
- if (!NT_STATUS_IS_OK(idmap_sid_to_uid(user_sid, &(pw->pw_uid), 0))) {
+ if (!NT_STATUS_IS_OK(idmap_sid_to_uid(user_sid, &pw->pw_uid, 0))) {
DEBUG(1, ("error getting user id for sid %s\n", sid_to_string(sid_string, user_sid)));
return False;
}
/* Resolve the gid number */
- if (!NT_STATUS_IS_OK(idmap_sid_to_gid(group_sid, &(pw->pw_gid), 0))) {
+ if (!NT_STATUS_IS_OK(idmap_sid_to_gid(group_sid, &pw->pw_gid, 0))) {
DEBUG(1, ("error getting group id for sid %s\n", sid_to_string(sid_string, group_sid)));
return False;
}
@@ -185,7 +185,7 @@ enum winbindd_result winbindd_getpwnam(struct winbindd_cli_state *state)
}
/* Now take all this information and fill in a passwd structure */
- if (!winbindd_fill_pwent(name_domain, name_user,
+ if (!winbindd_fill_pwent(name_domain, user_info.acct_name,
user_info.user_sid, user_info.group_sid,
user_info.full_name,
&state->response.data.pw)) {
@@ -283,7 +283,7 @@ enum winbindd_result winbindd_getpwuid(struct winbindd_cli_state *state)
/* Fill in password structure */
- if (!winbindd_fill_pwent(domain->name, user_name, user_info.user_sid,
+ if (!winbindd_fill_pwent(domain->name, user_info.acct_name, user_info.user_sid,
user_info.group_sid,
user_info.full_name, &state->response.data.pw)) {
talloc_destroy(mem_ctx);
diff --git a/source/param/loadparm.c b/source/param/loadparm.c
index 978ea89d5c6..549e232fe07 100644
--- a/source/param/loadparm.c
+++ b/source/param/loadparm.c
@@ -1120,7 +1120,7 @@ static struct parm_struct parm_table[] = {
{"remote browse sync", P_STRING, P_GLOBAL, &Globals.szRemoteBrowseSync, NULL, NULL, FLAG_ADVANCED},
{"socket address", P_STRING, P_GLOBAL, &Globals.szSocketAddress, NULL, NULL, FLAG_ADVANCED},
{"homedir map", P_STRING, P_GLOBAL, &Globals.szNISHomeMapName, NULL, NULL, FLAG_ADVANCED},
- {"afs username map", P_USTRING, P_GLOBAL, &Globals.szAfsUsernameMap, NULL, NULL, FLAG_ADVANCED},
+ {"afs username map", P_STRING, P_GLOBAL, &Globals.szAfsUsernameMap, NULL, NULL, FLAG_ADVANCED},
{"time offset", P_INTEGER, P_GLOBAL, &extra_time_offset, NULL, NULL, FLAG_ADVANCED},
{"NIS homedir", P_BOOL, P_GLOBAL, &Globals.bNISHomeMap, NULL, NULL, FLAG_ADVANCED},
{"-valid", P_BOOL, P_LOCAL, &sDefault.valid, NULL, NULL, FLAG_HIDE},
diff --git a/source/passdb/passdb.c b/source/passdb/passdb.c
index 2f9742e17da..e404f5af3f9 100644
--- a/source/passdb/passdb.c
+++ b/source/passdb/passdb.c
@@ -1841,18 +1841,20 @@ BOOL init_sam_from_buffer_v2(SAM_ACCOUNT *sampass, uint8 *buf, uint32 buflen)
/* Change from V1 is addition of password history field. */
account_policy_get(AP_PASSWORD_HISTORY, &pwHistLen);
if (pwHistLen) {
- char *pw_hist = malloc(pwHistLen * NT_HASH_LEN);
+ char *pw_hist = malloc(pwHistLen * PW_HISTORY_ENTRY_LEN);
if (!pw_hist) {
ret = False;
goto done;
}
- memset(pw_hist, '\0', pwHistLen * NT_HASH_LEN);
+ 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 % NT_HASH_LEN) == 0);
- nt_pw_hist_len /= NT_HASH_LEN;
+ 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*NT_HASH_LEN], &nt_pw_hist_ptr[i*NT_HASH_LEN], NT_HASH_LEN);
+ 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)) {
@@ -2048,7 +2050,7 @@ uint32 init_buffer_from_sam_v2 (uint8 **buf, const SAM_ACCOUNT *sampass, BOOL si
account_policy_get(AP_PASSWORD_HISTORY, &pwHistLen);
nt_pw_hist = pdb_get_pw_history(sampass, &nt_pw_hist_len);
if (pwHistLen && nt_pw_hist && nt_pw_hist_len) {
- nt_pw_hist_len *= NT_HASH_LEN;
+ nt_pw_hist_len *= PW_HISTORY_ENTRY_LEN;
} else {
nt_pw_hist_len = 0;
}
diff --git a/source/passdb/pdb_get_set.c b/source/passdb/pdb_get_set.c
index dc8a2f68d21..51c408e6d51 100644
--- a/source/passdb/pdb_get_set.c
+++ b/source/passdb/pdb_get_set.c
@@ -154,8 +154,8 @@ const uint8* pdb_get_pw_history (const SAM_ACCOUNT *sampass, uint32 *current_his
{
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;
+ || ((sampass->private.nt_pw_his.length % PW_HISTORY_ENTRY_LEN) == 0));
+ *current_hist_len = sampass->private.nt_pw_his.length / PW_HISTORY_ENTRY_LEN;
return ((uint8*)sampass->private.nt_pw_his.data);
} else {
*current_hist_len = 0;
@@ -995,7 +995,8 @@ 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
+ Set the user's password history hash. historyLen is the number of
+ PW_HISTORY_SALT_LEN+SALTED_MD5_HASH_LEN length
entries to store in the history - this must match the size of the uint8 array
in pwd.
********************************************************************/
@@ -1006,7 +1007,8 @@ BOOL pdb_set_pw_history (SAM_ACCOUNT *sampass, const uint8 *pwd, uint32 historyL
return False;
if (historyLen && pwd){
- sampass->private.nt_pw_his = data_blob_talloc(sampass->mem_ctx, pwd, historyLen*NT_HASH_LEN);
+ sampass->private.nt_pw_his = data_blob_talloc(sampass->mem_ctx,
+ pwd, historyLen*PW_HISTORY_ENTRY_LEN);
if (!sampass->private.nt_pw_his.length) {
DEBUG(0, ("pdb_set_pw_history: data_blob_talloc() failed!\n"));
return False;
@@ -1221,17 +1223,34 @@ BOOL pdb_set_plaintext_passwd (SAM_ACCOUNT *sampass, const char *plaintext)
have more history than we need. */
if (current_history_len < pwHistLen) {
- /* We only have room for current_history_len entries. */
- pwHistLen = current_history_len;
+ /* Ensure we have space for the needed history. */
+ uchar *new_history = talloc(sampass->mem_ctx,
+ pwHistLen*PW_HISTORY_ENTRY_LEN);
+ /* And copy it into the new buffer. */
+ if (current_history_len) {
+ memcpy(new_history, pwhistory,
+ current_history_len*PW_HISTORY_ENTRY_LEN);
+ }
+ /* Clearing out any extra space. */
+ memset(&new_history[current_history_len*PW_HISTORY_ENTRY_LEN],
+ '\0', (pwHistLen-current_history_len)*PW_HISTORY_ENTRY_LEN);
+ /* Finally replace it. */
+ pwhistory = new_history;
}
}
if (pwhistory && pwHistLen){
/* Make room for the new password in the history list. */
if (pwHistLen > 1) {
- memmove(&pwhistory[NT_HASH_LEN], pwhistory, (pwHistLen -1)*NT_HASH_LEN );
+ memmove(&pwhistory[PW_HISTORY_ENTRY_LEN],
+ pwhistory, (pwHistLen -1)*PW_HISTORY_ENTRY_LEN );
}
- /* Ensure we have a copy of the new password as the first history entry. */
- memcpy(pwhistory, new_nt_p16, NT_HASH_LEN);
+ /* Create the new salt as the first part of the history entry. */
+ generate_random_buffer(pwhistory, PW_HISTORY_SALT_LEN);
+
+ /* Generate the md5 hash of the salt+new password as the second
+ part of the history entry. */
+
+ E_md5hash(pwhistory, new_nt_p16, &pwhistory[PW_HISTORY_SALT_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"));
diff --git a/source/smbd/chgpasswd.c b/source/smbd/chgpasswd.c
index a1b90c8fed4..5c1d66abc44 100644
--- a/source/smbd/chgpasswd.c
+++ b/source/smbd/chgpasswd.c
@@ -941,7 +941,7 @@ static NTSTATUS check_oem_password(const char *user,
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];
+ uchar zero_md5_nt_pw[SALTED_MD5_HASH_LEN];
const uint8 *nt_pw;
const uint8 *pwhistory;
BOOL found = False;
@@ -972,22 +972,28 @@ static BOOL check_passwd_history(SAM_ACCOUNT *sampass, const char *plaintext)
}
dump_data(100, new_nt_p16, NT_HASH_LEN);
- dump_data(100, pwhistory, NT_HASH_LEN*pwHisLen);
+ dump_data(100, pwhistory, PW_HISTORY_ENTRY_LEN*pwHisLen);
- memset(zero_nt_pw, '\0', NT_HASH_LEN);
+ memset(zero_md5_nt_pw, '\0', SALTED_MD5_HASH_LEN);
for (i=0; i<pwHisLen; i++) {
- if (!memcmp(&pwhistory[i*NT_HASH_LEN], zero_nt_pw, NT_HASH_LEN)) {
- /* Ignore zero entries. */
+ uchar new_nt_pw_salted_md5_hash[SALTED_MD5_HASH_LEN];
+ const uchar *current_salt = &pwhistory[i*PW_HISTORY_ENTRY_LEN];
+ const uchar *old_nt_pw_salted_md5_hash = &pwhistory[(i*PW_HISTORY_ENTRY_LEN)+
+ PW_HISTORY_SALT_LEN];
+ if (!memcmp(zero_md5_nt_pw, old_nt_pw_salted_md5_hash, SALTED_MD5_HASH_LEN)) {
+ /* Ignore zero valued entries. */
continue;
}
- if (!memcmp(&pwhistory[i*NT_HASH_LEN], new_nt_p16, NT_HASH_LEN)) {
+ /* Create salted versions of new to compare. */
+ E_md5hash(current_salt, new_nt_p16, new_nt_pw_salted_md5_hash);
+
+ if (!memcmp(new_nt_pw_salted_md5_hash, old_nt_pw_salted_md5_hash, SALTED_MD5_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;
}