summaryrefslogtreecommitdiff
path: root/source3/nsswitch
diff options
context:
space:
mode:
Diffstat (limited to 'source3/nsswitch')
-rw-r--r--source3/nsswitch/winbindd_cache.c44
-rw-r--r--source3/nsswitch/winbindd_creds.c5
-rw-r--r--source3/nsswitch/winbindd_pam.c24
3 files changed, 63 insertions, 10 deletions
diff --git a/source3/nsswitch/winbindd_cache.c b/source3/nsswitch/winbindd_cache.c
index 865cf121b1..63c4bb58fc 100644
--- a/source3/nsswitch/winbindd_cache.c
+++ b/source3/nsswitch/winbindd_cache.c
@@ -47,6 +47,7 @@ struct cache_entry {
};
#define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
+#define WINBINDD_CACHE_VERSION "WB_CACHE_VERSION_1"
static struct winbind_cache *wcache;
@@ -874,11 +875,14 @@ NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const DOM_SID
return NT_STATUS_OK;
}
-/* Lookup creds for a SID */
+/* Lookup creds for a SID - copes with old (unsalted) creds as well
+ as new salted ones. */
+
NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
const DOM_SID *sid,
- const uint8 **cached_nt_pass)
+ const uint8 **cached_nt_pass,
+ const uint8 **cached_salt)
{
struct winbind_cache *cache = get_cache(domain);
struct cache_entry *centry = NULL;
@@ -898,19 +902,37 @@ NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
return NT_STATUS_INVALID_SID;
}
+ /* Try and get a salted cred first. If we can't
+ fall back to an unsalted cred. */
+
centry = wcache_fetch(cache, domain, "CRED/%s", sid_string_static(sid));
-
if (!centry) {
DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
- sid_string_static(sid)));
+ sid_string_static(sid)));
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
t = centry_time(centry);
+
+ /* In the salted case this isn't actually the nt_hash itself,
+ but the MD5 of the salt + nt_hash. Let the caller
+ sort this out. It can tell as we only return the cached_salt
+ if we are returning a salted cred. */
+
*cached_nt_pass = (const uint8 *)centry_hash16(centry, mem_ctx);
+ /* We only have 17 bytes more data in the salted cred case. */
+ if (centry->len - centry->ofs == 17) {
+ *cached_salt = (const uint8 *)centry_hash16(centry, mem_ctx);
+ } else {
+ *cached_salt = NULL;
+ }
+
#if DEBUG_PASSWORD
- dump_data(100, (const char *)cached_nt_pass, NT_HASH_LEN);
+ dump_data(100, (const char *)*cached_nt_pass, NT_HASH_LEN);
+ if (*cached_salt) {
+ dump_data(100, (const char *)*cached_salt, NT_HASH_LEN);
+ }
#endif
status = centry->status;
@@ -921,6 +943,8 @@ NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
return status;
}
+/* Store creds for a SID - only writes out new salted ones. */
+
NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
const DOM_SID *sid,
@@ -929,6 +953,8 @@ NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
struct cache_entry *centry;
fstring sid_string;
uint32 rid;
+ uint8 cred_salt[NT_HASH_LEN];
+ uint8 salted_hash[NT_HASH_LEN];
if (is_null_sid(sid)) {
return NT_STATUS_INVALID_SID;
@@ -948,7 +974,13 @@ NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
#endif
centry_put_time(centry, time(NULL));
- centry_put_hash16(centry, nt_pass);
+
+ /* Create a salt and then salt the hash. */
+ generate_random_buffer(cred_salt, NT_HASH_LEN);
+ E_md5hash(cred_salt, nt_pass, salted_hash);
+
+ centry_put_hash16(centry, salted_hash);
+ centry_put_hash16(centry, cred_salt);
centry_end(centry, "CRED/%s", sid_to_string(sid_string, sid));
DEBUG(10,("wcache_save_creds: %s\n", sid_string));
diff --git a/source3/nsswitch/winbindd_creds.c b/source3/nsswitch/winbindd_creds.c
index 414dd24af9..75d21353fd 100644
--- a/source3/nsswitch/winbindd_creds.c
+++ b/source3/nsswitch/winbindd_creds.c
@@ -31,12 +31,13 @@ NTSTATUS winbindd_get_creds(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
const DOM_SID *sid,
NET_USER_INFO_3 **info3,
- const uint8 *cached_nt_pass[NT_HASH_LEN])
+ const uint8 *cached_nt_pass[NT_HASH_LEN],
+ const uint8 *cred_salt[NT_HASH_LEN])
{
NET_USER_INFO_3 *info;
NTSTATUS status;
- status = wcache_get_creds(domain, mem_ctx, sid, cached_nt_pass);
+ status = wcache_get_creds(domain, mem_ctx, sid, cached_nt_pass, cred_salt);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
diff --git a/source3/nsswitch/winbindd_pam.c b/source3/nsswitch/winbindd_pam.c
index 365b277160..8931b1373e 100644
--- a/source3/nsswitch/winbindd_pam.c
+++ b/source3/nsswitch/winbindd_pam.c
@@ -736,8 +736,10 @@ NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain,
enum SID_NAME_USE type;
uchar new_nt_pass[NT_HASH_LEN];
const uint8 *cached_nt_pass;
+ const uint8 *cached_salt;
NET_USER_INFO_3 *my_info3;
time_t kickoff_time, must_change_time;
+ BOOL password_good = False;
*info3 = NULL;
@@ -768,7 +770,8 @@ NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain,
state->mem_ctx,
&sid,
&my_info3,
- &cached_nt_pass);
+ &cached_nt_pass,
+ &cached_salt);
if (!NT_STATUS_IS_OK(result)) {
DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get creds: %s\n", nt_errstr(result)));
return result;
@@ -781,9 +784,26 @@ NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain,
#if DEBUG_PASSWORD
dump_data(100, (const char *)new_nt_pass, NT_HASH_LEN);
dump_data(100, (const char *)cached_nt_pass, NT_HASH_LEN);
+ if (cached_salt) {
+ dump_data(100, (const char *)cached_salt, NT_HASH_LEN);
+ }
#endif
- if (!memcmp(cached_nt_pass, new_nt_pass, NT_HASH_LEN)) {
+ if (cached_salt) {
+ /* In this case we didn't store the nt_hash itself,
+ but the MD5 combination of salt + nt_hash. */
+ uchar salted_hash[NT_HASH_LEN];
+ E_md5hash(cached_salt, new_nt_pass, salted_hash);
+
+ password_good = (memcmp(cached_nt_pass, salted_hash, NT_HASH_LEN) == 0) ?
+ True : False;
+ } else {
+ /* Old cached cred - direct store of nt_hash (bad bad bad !). */
+ password_good = (memcmp(cached_nt_pass, new_nt_pass, NT_HASH_LEN) == 0) ?
+ True : False;
+ }
+
+ if (password_good) {
/* User *DOES* know the password, update logon_time and reset
* bad_pw_count */