Fix bug #8521 - winbindd cache timeout expiry test was reversed
[samba.git] / source3 / winbindd / winbindd_cache.c
index 9ee8f6ab2a6add3a76c8483cc6958ba1e8fe3f8e..620b8588aa06891dd883e6a2e32ade7aff24e412 100644 (file)
@@ -24,6 +24,7 @@
 */
 
 #include "includes.h"
+#include "system/filesys.h"
 #include "winbindd.h"
 #include "tdb_validate.h"
 #include "../libcli/auth/libcli_auth.h"
 #include "ads.h"
 #include "nss_info.h"
 #include "../libcli/security/security.h"
+#include "passdb/machine_sid.h"
+#include "util_tdb.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_WINBIND
 
-#define WINBINDD_CACHE_VERSION 1
+#define WINBINDD_CACHE_VERSION 2
 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
 
 extern struct winbindd_methods reconnect_methods;
@@ -96,6 +99,7 @@ struct winbind_cache {
 struct cache_entry {
        NTSTATUS status;
        uint32 sequence_number;
+       uint64_t timeout;
        uint8 *data;
        uint32 len, ofs;
 };
@@ -119,7 +123,7 @@ static struct winbind_cache *get_cache(struct winbindd_domain *domain)
        }
 
        if (strequal(domain->name, get_global_sam_name()) &&
-           dom_sid_equal(&domain->sid, get_global_sam_sid())) {
+           sid_check_is_domain(&domain->sid)) {
                domain->backend = &sam_passdb_methods;
                domain->initialized = True;
        }
@@ -204,6 +208,21 @@ static bool centry_check_bytes(struct cache_entry *centry, size_t nbytes)
        return true;
 }
 
+/*
+  pull a uint64_t from a cache entry
+*/
+static uint64_t centry_uint64_t(struct cache_entry *centry)
+{
+       uint64_t ret;
+
+       if (!centry_check_bytes(centry, 8)) {
+               smb_panic_fn("centry_uint64_t");
+       }
+       ret = BVAL(centry->data, centry->ofs);
+       centry->ofs += 8;
+       return ret;
+}
+
 /*
   pull a uint32 from a cache entry 
 */
@@ -228,7 +247,7 @@ static uint16 centry_uint16(struct cache_entry *centry)
        if (!centry_check_bytes(centry, 2)) {
                smb_panic_fn("centry_uint16");
        }
-       ret = CVAL(centry->data, centry->ofs);
+       ret = SVAL(centry->data, centry->ofs);
        centry->ofs += 2;
        return ret;
 }
@@ -258,7 +277,7 @@ static NTTIME centry_nttime(struct cache_entry *centry)
        }
        ret = IVAL(centry->data, centry->ofs);
        centry->ofs += 4;
-       ret += (uint64_t)IVAL(centry->data, centry->ofs) << 32;
+       ret += (uint64)IVAL(centry->data, centry->ofs) << 32;
        centry->ofs += 4;
        return ret;
 }
@@ -290,7 +309,7 @@ static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
                smb_panic_fn("centry_string");
        }
 
-       ret = TALLOC_ARRAY(mem_ctx, char, len+1);
+       ret = talloc_array(mem_ctx, char, len+1);
        if (!ret) {
                smb_panic_fn("centry_string out of memory\n");
        }
@@ -320,7 +339,7 @@ static char *centry_hash16(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
                return NULL;
        }
 
-       ret = TALLOC_ARRAY(mem_ctx, char, 16);
+       ret = talloc_array(mem_ctx, char, 16);
        if (!ret) {
                smb_panic_fn("centry_hash out of memory\n");
        }
@@ -465,9 +484,9 @@ bool wcache_store_seqnum(const char *domain_name, uint32_t seqnum,
        ret = tdb_store_bystring(wcache->tdb, key_str,
                                 make_tdb_data(buf, sizeof(buf)), TDB_REPLACE);
        TALLOC_FREE(key_str);
-       if (ret == -1) {
+       if (ret != 0) {
                DEBUG(10, ("tdb_store_bystring failed: %s\n",
-                          tdb_errorstr(wcache->tdb)));
+                          tdb_errorstr_compat(wcache->tdb)));
                TALLOC_FREE(key_str);
                return false;
        }
@@ -596,9 +615,10 @@ static bool centry_expired(struct winbindd_domain *domain, const char *keystr, s
        }
 
        /* if the server is down or the cache entry is not older than the
-          current sequence number then it is OK */
-       if (wcache_server_down(domain) || 
-           centry->sequence_number == domain->sequence_number) {
+          current sequence number or it did not timeout then it is OK */
+       if (wcache_server_down(domain)
+           || ((centry->sequence_number == domain->sequence_number)
+               && (centry->timeout > time(NULL)))) {
                DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
                        keystr, domain->name ));
                return false;
@@ -618,7 +638,7 @@ static struct cache_entry *wcache_fetch_raw(char *kstr)
        TDB_DATA key;
 
        key = string_tdb_data(kstr);
-       data = tdb_fetch(wcache->tdb, key);
+       data = tdb_fetch_compat(wcache->tdb, key);
        if (!data.dptr) {
                /* a cache miss */
                return NULL;
@@ -629,15 +649,17 @@ static struct cache_entry *wcache_fetch_raw(char *kstr)
        centry->len = data.dsize;
        centry->ofs = 0;
 
-       if (centry->len < 8) {
+       if (centry->len < 16) {
                /* huh? corrupt cache? */
-               DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr));
+               DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s "
+                         "(len < 16)?\n", kstr));
                centry_free(centry);
                return NULL;
        }
 
        centry->status = centry_ntstatus(centry);
        centry->sequence_number = centry_uint32(centry);
+       centry->timeout = centry_uint64_t(centry);
 
        return centry;
 }
@@ -645,7 +667,7 @@ static struct cache_entry *wcache_fetch_raw(char *kstr)
 static bool is_my_own_sam_domain(struct winbindd_domain *domain)
 {
        if (strequal(domain->name, get_global_sam_name()) &&
-            dom_sid_equal(&domain->sid, get_global_sam_sid())) {
+           sid_check_is_domain(&domain->sid)) {
                return true;
        }
 
@@ -655,7 +677,7 @@ static bool is_my_own_sam_domain(struct winbindd_domain *domain)
 static bool is_builtin_domain(struct winbindd_domain *domain)
 {
        if (strequal(domain->name, "BUILTIN") &&
-           dom_sid_equal(&domain->sid, &global_sid_Builtin)) {
+           sid_check_is_builtin(&domain->sid)) {
                return true;
        }
 
@@ -745,6 +767,16 @@ static void centry_expand(struct cache_entry *centry, uint32 len)
        }
 }
 
+/*
+  push a uint64_t into a centry
+*/
+static void centry_put_uint64_t(struct cache_entry *centry, uint64_t v)
+{
+       centry_expand(centry, 8);
+       SBVAL(centry->data, centry->ofs, v);
+       centry->ofs += 8;
+}
+
 /*
   push a uint32 into a centry 
 */
@@ -761,7 +793,7 @@ static void centry_put_uint32(struct cache_entry *centry, uint32 v)
 static void centry_put_uint16(struct cache_entry *centry, uint16 v)
 {
        centry_expand(centry, 2);
-       SIVAL(centry->data, centry->ofs, v);
+       SSVAL(centry->data, centry->ofs, v);
        centry->ofs += 2;
 }
 
@@ -866,8 +898,10 @@ struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status
        centry->data = SMB_XMALLOC_ARRAY(uint8, centry->len);
        centry->ofs = 0;
        centry->sequence_number = domain->sequence_number;
+       centry->timeout = lp_winbind_cache_time() + time(NULL);
        centry_put_ntstatus(centry, status);
        centry_put_uint32(centry, centry->sequence_number);
+       centry_put_uint64_t(centry, centry->timeout);
        return centry;
 }
 
@@ -935,8 +969,8 @@ static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS sta
        }
 
        centry_end(centry, "SN/%s", sid_to_fstring(sid_string, sid));
-       DEBUG(10,("wcache_save_sid_to_name: %s -> %s (%s)\n", sid_string, 
-                 name, nt_errstr(status)));
+       DEBUG(10,("wcache_save_sid_to_name: %s -> %s\\%s (%s)\n", sid_string,
+                 domain_name, name, nt_errstr(status)));
        centry_free(centry);
 }
 
@@ -1237,7 +1271,7 @@ NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const struct
 
        fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
 
-       data = tdb_fetch(cache->tdb, string_tdb_data(key_str));
+       data = tdb_fetch_compat(cache->tdb, string_tdb_data(key_str));
        if (!data.dptr) {
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
@@ -1262,6 +1296,10 @@ NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
        uint32 rid;
        fstring tmp;
 
+       if (!winbindd_use_cache()) {
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       }
+
        if (!cache->tdb) {
                return NT_STATUS_INTERNAL_DB_ERROR;
        }
@@ -1398,7 +1436,7 @@ do_fetch_cache:
        if (*num_entries == 0)
                goto do_cached;
 
-       (*info) = TALLOC_ARRAY(mem_ctx, struct wbint_userinfo, *num_entries);
+       (*info) = talloc_array(mem_ctx, struct wbint_userinfo, *num_entries);
        if (! (*info)) {
                smb_panic_fn("query_user_list out of memory");
        }
@@ -1528,7 +1566,7 @@ skip_save:
 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
                                TALLOC_CTX *mem_ctx,
                                uint32 *num_entries, 
-                               struct acct_info **info)
+                               struct wb_acct_info **info)
 {
        struct winbind_cache *cache = get_cache(domain);
        struct cache_entry *centry = NULL;
@@ -1550,7 +1588,7 @@ do_fetch_cache:
        if (*num_entries == 0)
                goto do_cached;
 
-       (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
+       (*info) = talloc_array(mem_ctx, struct wb_acct_info, *num_entries);
        if (! (*info)) {
                smb_panic_fn("enum_dom_groups out of memory");
        }
@@ -1623,7 +1661,7 @@ skip_save:
 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
                                TALLOC_CTX *mem_ctx,
                                uint32 *num_entries, 
-                               struct acct_info **info)
+                               struct wb_acct_info **info)
 {
        struct winbind_cache *cache = get_cache(domain);
        struct cache_entry *centry = NULL;
@@ -1645,7 +1683,7 @@ do_fetch_cache:
        if (*num_entries == 0)
                goto do_cached;
 
-       (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
+       (*info) = talloc_array(mem_ctx, struct wb_acct_info, *num_entries);
        if (! (*info)) {
                smb_panic_fn("enum_dom_groups out of memory");
        }
@@ -1823,8 +1861,8 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain,
 
                /* Only save the reverse mapping if this was not a UPN */
                if (!strchr(name, '@')) {
-                       strupper_m(CONST_DISCARD(char *,domain_name));
-                       strlower_m(CONST_DISCARD(char *,name));
+                       strupper_m(discard_const_p(char, domain_name));
+                       strlower_m(discard_const_p(char, name));
                        wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
                }
        }
@@ -1968,8 +2006,8 @@ static NTSTATUS rids_to_names(struct winbindd_domain *domain,
                return NT_STATUS_OK;
        }
 
-       *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
-       *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
+       *names = talloc_array(mem_ctx, char *, num_rids);
+       *types = talloc_array(mem_ctx, enum lsa_SidType, num_rids);
 
        if ((*names == NULL) || (*types == NULL)) {
                result = NT_STATUS_NO_MEMORY;
@@ -2011,7 +2049,8 @@ static NTSTATUS rids_to_names(struct winbindd_domain *domain,
 
                        (*names)[i] = centry_string(centry, *names);
 
-               } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
+               } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)
+                          || NT_STATUS_EQUAL(centry->status, STATUS_SOME_UNMAPPED)) {
                        have_unmapped = true;
 
                } else {
@@ -2735,7 +2774,7 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain,
        }
 
 do_fetch_cache:
-       trusts->array = TALLOC_ZERO_ARRAY(mem_ctx, struct netr_DomainTrust, num_domains);
+       trusts->array = talloc_zero_array(mem_ctx, struct netr_DomainTrust, num_domains);
        if (!trusts->array) {
                TALLOC_FREE(dom_list);
                return NT_STATUS_NO_MEMORY;
@@ -2968,9 +3007,8 @@ static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
 
 void wcache_invalidate_samlogon(struct winbindd_domain *domain, 
-                               struct netr_SamInfo3 *info3)
+                               const struct dom_sid *sid)
 {
-        struct dom_sid sid;
         fstring key_str, sid_string;
        struct winbind_cache *cache;
 
@@ -2990,20 +3028,18 @@ void wcache_invalidate_samlogon(struct winbindd_domain *domain,
                 return;
         }
 
-       sid_compose(&sid, info3->base.domain_sid, info3->base.rid);
-
        /* Clear U/SID cache entry */
-       fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, &sid));
+       fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, sid));
        DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
        tdb_delete(cache->tdb, string_tdb_data(key_str));
 
        /* Clear UG/SID cache entry */
-       fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, &sid));
+       fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, sid));
        DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
        tdb_delete(cache->tdb, string_tdb_data(key_str));
 
        /* Samba/winbindd never needs this. */
-       netsamlogon_clear_cached_user(info3);
+       netsamlogon_clear_cached_user(sid);
 }
 
 bool wcache_invalidate_cache(void)
@@ -3070,7 +3106,7 @@ bool init_wcache(void)
                return true;
 
        /* when working offline we must not clear the cache on restart */
-       wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
+       wcache->tdb = tdb_open_log(state_path("winbindd_cache.tdb"),
                                WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE, 
                                TDB_INCOMPATIBLE_HASH |
                                        (lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
@@ -3114,9 +3150,9 @@ bool initialize_winbindd_cache(void)
                tdb_close(wcache->tdb);
                wcache->tdb = NULL;
 
-               if (unlink(cache_path("winbindd_cache.tdb")) == -1) {
+               if (unlink(state_path("winbindd_cache.tdb")) == -1) {
                        DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
-                               cache_path("winbindd_cache.tdb"),
+                               state_path("winbindd_cache.tdb"),
                                strerror(errno) ));
                        return false;
                }
@@ -3129,7 +3165,7 @@ bool initialize_winbindd_cache(void)
                /* Write the version. */
                if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
                        DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
-                               tdb_errorstr(wcache->tdb) ));
+                               tdb_errorstr_compat(wcache->tdb) ));
                        return false;
                }
        }
@@ -3243,7 +3279,7 @@ void wcache_flush_cache(void)
        }
 
        /* when working offline we must not clear the cache on restart */
-       wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
+       wcache->tdb = tdb_open_log(state_path("winbindd_cache.tdb"),
                                WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE, 
                                TDB_INCOMPATIBLE_HASH |
                                (lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
@@ -3347,7 +3383,7 @@ NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const
        ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
        if (ret == 0) {
                return NT_STATUS_OK;
-       } else if ((ret == -1) || (wcache_cred_list == NULL)) {
+       } else if ((ret < 0) || (wcache_cred_list == NULL)) {
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
 
@@ -3358,7 +3394,7 @@ NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const
                TDB_DATA data;
                time_t t;
 
-               data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
+               data = tdb_fetch_compat(cache->tdb, string_tdb_data(cred->name));
                if (!data.dptr) {
                        DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n", 
                                cred->name));
@@ -3484,9 +3520,10 @@ static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA dat
        centry->len = data.dsize;
        centry->ofs = 0;
 
-       if (centry->len < 8) {
+       if (centry->len < 16) {
                /* huh? corrupt cache? */
-               DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr));
+               DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
+                        "(len < 16) ?\n", kstr));
                centry_free(centry);
                state->bad_entry = true;
                state->success = false;
@@ -3495,6 +3532,7 @@ static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA dat
 
        centry->status = NT_STATUS(centry_uint32(centry));
        centry->sequence_number = centry_uint32(centry);
+       centry->timeout = centry_uint64_t(centry);
        return centry;
 }
 
@@ -4055,7 +4093,7 @@ static void validate_panic(const char *const why)
 int winbindd_validate_cache(void)
 {
        int ret = -1;
-       const char *tdb_path = cache_path("winbindd_cache.tdb");
+       const char *tdb_path = state_path("winbindd_cache.tdb");
        TDB_CONTEXT *tdb = NULL;
 
        DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
@@ -4098,7 +4136,7 @@ done:
 int winbindd_validate_cache_nobackup(void)
 {
        int ret = -1;
-       const char *tdb_path = cache_path("winbindd_cache.tdb");
+       const char *tdb_path = state_path("winbindd_cache.tdb");
 
        DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
        smb_panic_fn = validate_panic;
@@ -4165,10 +4203,10 @@ static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
 
        if ( !set_only ) {
                if ( !*domains ) {
-                       list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, 1 );
+                       list = talloc_array( NULL, struct winbindd_tdc_domain, 1 );
                        idx = 0;
                } else {
-                       list = TALLOC_REALLOC_ARRAY( *domains, *domains, 
+                       list = talloc_realloc( *domains, *domains, 
                                                     struct winbindd_tdc_domain,  
                                                     (*num_domains)+1);
                        idx = *num_domains;             
@@ -4308,7 +4346,7 @@ static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
                return 0;
        }
 
-       list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, num_domains );
+       list = talloc_array( NULL, struct winbindd_tdc_domain, num_domains );
        if ( !list ) {
                DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
                return 0;               
@@ -4382,7 +4420,7 @@ static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t n
        SAFE_FREE( data.dptr );
        SAFE_FREE( key.dptr );
 
-       return ( ret != -1 );   
+       return ( ret == 0 );
 }
 
 /*********************************************************************
@@ -4399,7 +4437,7 @@ bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_do
        if ( !key.dptr )
                return false;
 
-       data = tdb_fetch( wcache->tdb, key );
+       data = tdb_fetch_compat( wcache->tdb, key );
 
        SAFE_FREE( key.dptr );
 
@@ -4489,7 +4527,7 @@ struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const cha
                        DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
                                  name));
 
-                       d = TALLOC_P( ctx, struct winbindd_tdc_domain );
+                       d = talloc( ctx, struct winbindd_tdc_domain );
                        if ( !d )
                                break;                  
 
@@ -4509,6 +4547,58 @@ struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const cha
        return d;       
 }
 
+/*********************************************************************
+ ********************************************************************/
+
+struct winbindd_tdc_domain*
+       wcache_tdc_fetch_domainbysid(TALLOC_CTX *ctx,
+                                    const struct dom_sid *sid)
+{
+       struct winbindd_tdc_domain *dom_list = NULL;
+       size_t num_domains = 0;
+       int i;
+       struct winbindd_tdc_domain *d = NULL;
+
+       DEBUG(10,("wcache_tdc_fetch_domainbysid: Searching for domain %s\n",
+                 sid_string_dbg(sid)));
+
+       if (!init_wcache()) {
+               return false;
+       }
+
+       /* fetch the list */
+
+       wcache_tdc_fetch_list(&dom_list, &num_domains);
+
+       for (i = 0; i<num_domains; i++) {
+               if (dom_sid_equal(sid, &(dom_list[i].sid))) {
+                       DEBUG(10, ("wcache_tdc_fetch_domainbysid: "
+                                  "Found domain %s for SID %s\n",
+                                  dom_list[i].domain_name,
+                                  sid_string_dbg(sid)));
+
+                       d = talloc(ctx, struct winbindd_tdc_domain);
+                       if (!d)
+                               break;
+
+                       d->domain_name = talloc_strdup(d,
+                                                      dom_list[i].domain_name);
+
+                       d->dns_name = talloc_strdup(d, dom_list[i].dns_name);
+                       sid_copy(&d->sid, &dom_list[i].sid);
+                       d->trust_flags = dom_list[i].trust_flags;
+                       d->trust_type = dom_list[i].trust_type;
+                       d->trust_attribs = dom_list[i].trust_attribs;
+
+                       break;
+               }
+       }
+
+        TALLOC_FREE(dom_list);
+
+       return d;
+}
+
 
 /*********************************************************************
  ********************************************************************/
@@ -4558,7 +4648,6 @@ static void wcache_save_user_pwinfo(struct winbindd_domain *domain,
 NTSTATUS nss_get_info_cached( struct winbindd_domain *domain, 
                              const struct dom_sid *user_sid,
                              TALLOC_CTX *ctx,
-                             ADS_STRUCT *ads, LDAPMessage *msg,
                              const char **homedir, const char **shell,
                              const char **gecos, gid_t *p_gid)
 {
@@ -4590,7 +4679,7 @@ NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
 
 do_query:
 
-       nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg, 
+       nt_status = nss_get_info( domain->name, user_sid, ctx,
                                  homedir, shell, gecos, p_gid );
 
        DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status)));
@@ -4693,18 +4782,19 @@ bool wcache_fetch_ndr(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
        if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
                return false;
        }
-       data = tdb_fetch(wcache->tdb, key);
+       data = tdb_fetch_compat(wcache->tdb, key);
        TALLOC_FREE(key.dptr);
 
        if (data.dptr == NULL) {
                return false;
        }
-       if (data.dsize < 4) {
+       if (data.dsize < 12) {
                goto fail;
        }
 
        if (!is_domain_offline(domain)) {
                uint32_t entry_seqnum, dom_seqnum, last_check;
+               uint64_t entry_timeout;
 
                if (!wcache_fetch_seqnum(domain->name, &dom_seqnum,
                                         &last_check)) {
@@ -4716,15 +4806,20 @@ bool wcache_fetch_ndr(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
                                   (int)entry_seqnum));
                        goto fail;
                }
+               entry_timeout = BVAL(data.dptr, 4);
+               if (time(NULL) > entry_timeout) {
+                       DEBUG(10, ("Entry has timed out\n"));
+                       goto fail;
+               }
        }
 
-       resp->data = (uint8_t *)talloc_memdup(mem_ctx, data.dptr + 4,
-                                             data.dsize - 4);
+       resp->data = (uint8_t *)talloc_memdup(mem_ctx, data.dptr + 12,
+                                             data.dsize - 12);
        if (resp->data == NULL) {
                DEBUG(10, ("talloc failed\n"));
                goto fail;
        }
-       resp->length = data.dsize - 4;
+       resp->length = data.dsize - 12;
 
        ret = true;
 fail:
@@ -4737,6 +4832,7 @@ void wcache_store_ndr(struct winbindd_domain *domain, uint32_t opnum,
 {
        TDB_DATA key, data;
        uint32_t dom_seqnum, last_check;
+       uint64_t timeout;
 
        if (!wcache_opnum_cacheable(opnum) ||
            is_my_own_sam_domain(domain) ||
@@ -4758,14 +4854,17 @@ void wcache_store_ndr(struct winbindd_domain *domain, uint32_t opnum,
                return;
        }
 
-       data.dsize = resp->length + 4;
+       timeout = time(NULL) + lp_winbind_cache_time();
+
+       data.dsize = resp->length + 12;
        data.dptr = talloc_array(key.dptr, uint8_t, data.dsize);
        if (data.dptr == NULL) {
                goto done;
        }
 
        SIVAL(data.dptr, 0, dom_seqnum);
-       memcpy(data.dptr+4, resp->data, resp->length);
+       SBVAL(data.dptr, 4, timeout);
+       memcpy(data.dptr + 12, resp->data, resp->length);
 
        tdb_store(wcache->tdb, key, data, 0);