diff options
Diffstat (limited to 'source3/nsswitch')
-rw-r--r-- | source3/nsswitch/winbindd_cache.c | 44 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_creds.c | 5 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_pam.c | 24 |
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 */ |