summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/smb.h5
-rw-r--r--source3/libsmb/smbencrypt.c20
-rw-r--r--source3/passdb/passdb.c14
-rw-r--r--source3/passdb/pdb_get_set.c37
-rw-r--r--source3/smbd/chgpasswd.c20
5 files changed, 74 insertions, 22 deletions
diff --git a/source3/include/smb.h b/source3/include/smb.h
index a802e96226..32dba0cf78 100644
--- a/source3/include/smb.h
+++ b/source3/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/source3/libsmb/smbencrypt.c b/source3/libsmb/smbencrypt.c
index 9f936b77ae..d4b0557411 100644
--- a/source3/libsmb/smbencrypt.c
+++ b/source3/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/source3/passdb/passdb.c b/source3/passdb/passdb.c
index 2f9742e17d..e404f5af3f 100644
--- a/source3/passdb/passdb.c
+++ b/source3/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/source3/passdb/pdb_get_set.c b/source3/passdb/pdb_get_set.c
index dc8a2f68d2..51c408e6d5 100644
--- a/source3/passdb/pdb_get_set.c
+++ b/source3/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/source3/smbd/chgpasswd.c b/source3/smbd/chgpasswd.c
index a1b90c8fed..5c1d66abc4 100644
--- a/source3/smbd/chgpasswd.c
+++ b/source3/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;
}