winbindd: Name<->SID cache is not sequence number based anymore
[nivanova/samba-autobuild/.git] / source3 / winbindd / winbindd_cache.c
index 76970d6be404178700b2c265028fc9d44c68f92e..9f9e8781c2177d569160c73878b1a2827e79a4f8 100644 (file)
 #include "winbindd.h"
 #include "tdb_validate.h"
 #include "../libcli/auth/libcli_auth.h"
-#include "../librpc/gen_ndr/ndr_wbint.h"
+#include "../librpc/gen_ndr/ndr_winbind.h"
 #include "ads.h"
 #include "nss_info.h"
 #include "../libcli/security/security.h"
 #include "passdb/machine_sid.h"
 #include "util_tdb.h"
+#include "libsmb/samlogon_cache.h"
+#include "lib/namemap_cache.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_WINBIND
 
 extern struct winbindd_methods reconnect_methods;
 #ifdef HAVE_ADS
-extern struct winbindd_methods ads_methods;
+extern struct winbindd_methods reconnect_ads_methods;
 #endif
 extern struct winbindd_methods builtin_passdb_methods;
 extern struct winbindd_methods sam_passdb_methods;
 
+static void wcache_flush_cache(void);
+
 /*
  * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
  * Here are the list of entry types that are *not* stored
@@ -99,84 +103,88 @@ struct winbind_cache {
 
 struct cache_entry {
        NTSTATUS status;
-       uint32 sequence_number;
+       uint32_t sequence_number;
        uint64_t timeout;
-       uint8 *data;
-       uint32 len, ofs;
+       uint8_t *data;
+       uint32_t len, ofs;
 };
 
 void (*smb_panic_fn)(const char *const why) = smb_panic;
 
-#define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
-
 static struct winbind_cache *wcache;
 
-/* get the winbind_cache structure */
-static struct winbind_cache *get_cache(struct winbindd_domain *domain)
+static char *wcache_path(void)
 {
-       struct winbind_cache *ret = wcache;
+       /*
+        * Data needs to be kept persistent in state directory for
+        * running with "winbindd offline logon".
+        */
+       return state_path("winbindd_cache.tdb");
+}
 
-       /* We have to know what type of domain we are dealing with first. */
+static void winbindd_domain_init_backend(struct winbindd_domain *domain)
+{
+       if (domain->backend != NULL) {
+               return;
+       }
 
        if (domain->internal) {
                domain->backend = &builtin_passdb_methods;
-               domain->initialized = True;
+       }
+
+       if (dom_sid_equal(&domain->sid, &global_sid_Builtin)) {
+               domain->initialized = true;
        }
 
        if (strequal(domain->name, get_global_sam_name()) &&
-           sid_check_is_our_sam(&domain->sid)) {
+           sid_check_is_our_sam(&domain->sid))
+       {
                domain->backend = &sam_passdb_methods;
-               domain->initialized = True;
        }
 
-       if ( !domain->initialized ) {
-               init_dc_connection( domain );
+       if (!domain->initialized) {
+               /* We do not need a connection to an RW DC for cache operation */
+               init_dc_connection(domain, false);
        }
 
-       /* 
-          OK.  listen up becasue I'm only going to say this once.
-          We have the following scenarios to consider
-          (a) trusted AD domains on a Samba DC,
-          (b) trusted AD domains and we are joined to a non-kerberos domain
-          (c) trusted AD domains and we are joined to a kerberos (AD) domain
-
-          For (a) we can always contact the trusted domain using krb5 
-          since we have the domain trust account password
-
-          For (b) we can only use RPC since we have no way of 
-          getting a krb5 ticket in our own domain
-
-          For (c) we can always use krb5 since we have a kerberos trust
-
-          --jerry
-        */
-
-       if (!domain->backend) {
 #ifdef HAVE_ADS
+       if (domain->backend == NULL) {
                struct winbindd_domain *our_domain = domain;
 
-               /* find our domain first so we can figure out if we 
+               /* find our domain first so we can figure out if we
                   are joined to a kerberized domain */
 
-               if ( !domain->primary )
+               if (!domain->primary) {
                        our_domain = find_our_domain();
+               }
 
                if ((our_domain->active_directory || IS_DC)
                    && domain->active_directory
-                   && !lp_winbind_rpc_only()) {
-                       DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain->name));
-                       domain->backend = &ads_methods;
-               } else {
-#endif /* HAVE_ADS */
-                       DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain->name));
-                       domain->backend = &reconnect_methods;
-#ifdef HAVE_ADS
+                   && !lp_winbind_rpc_only())
+               {
+                       DBG_INFO("Setting ADS methods for domain %s\n",
+                                domain->name);
+                       domain->backend = &reconnect_ads_methods;
                }
+       }
 #endif /* HAVE_ADS */
+
+       if (domain->backend == NULL) {
+               DBG_INFO("Setting MS-RPC methods for domain %s\n", domain->name);
+               domain->backend = &reconnect_methods;
        }
+}
 
-       if (ret)
+/* get the winbind_cache structure */
+static struct winbind_cache *get_cache(struct winbindd_domain *domain)
+{
+       struct winbind_cache *ret = wcache;
+
+       winbindd_domain_init_backend(domain);
+
+       if (ret != NULL) {
                return ret;
+       }
 
        ret = SMB_XMALLOC_P(struct winbind_cache);
        ZERO_STRUCTP(ret);
@@ -225,11 +233,11 @@ static uint64_t centry_uint64_t(struct cache_entry *centry)
 }
 
 /*
-  pull a uint32 from a cache entry 
+  pull a uint32_t from a cache entry
 */
-static uint32 centry_uint32(struct cache_entry *centry)
+static uint32_t centry_uint32(struct cache_entry *centry)
 {
-       uint32 ret;
+       uint32_t ret;
 
        if (!centry_check_bytes(centry, 4)) {
                smb_panic_fn("centry_uint32");
@@ -240,11 +248,11 @@ static uint32 centry_uint32(struct cache_entry *centry)
 }
 
 /*
-  pull a uint16 from a cache entry 
+  pull a uint16_t from a cache entry
 */
-static uint16 centry_uint16(struct cache_entry *centry)
+static uint16_t centry_uint16(struct cache_entry *centry)
 {
-       uint16 ret;
+       uint16_t ret;
        if (!centry_check_bytes(centry, 2)) {
                smb_panic_fn("centry_uint16");
        }
@@ -254,11 +262,11 @@ static uint16 centry_uint16(struct cache_entry *centry)
 }
 
 /*
-  pull a uint8 from a cache entry 
+  pull a uint8_t from a cache entry
 */
-static uint8 centry_uint8(struct cache_entry *centry)
+static uint8_t centry_uint8(struct cache_entry *centry)
 {
-       uint8 ret;
+       uint8_t ret;
        if (!centry_check_bytes(centry, 1)) {
                smb_panic_fn("centry_uint8");
        }
@@ -278,7 +286,7 @@ static NTTIME centry_nttime(struct cache_entry *centry)
        }
        ret = IVAL(centry->data, centry->ofs);
        centry->ofs += 4;
-       ret += (uint64)IVAL(centry->data, centry->ofs) << 32;
+       ret += (uint64_t)IVAL(centry->data, centry->ofs) << 32;
        centry->ofs += 4;
        return ret;
 }
@@ -296,7 +304,7 @@ static time_t centry_time(struct cache_entry *centry)
 */
 static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
 {
-       uint32 len;
+       uint32_t len;
        char *ret;
 
        len = centry_uint8(centry);
@@ -325,7 +333,7 @@ static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
 */
 static char *centry_hash16(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
 {
-       uint32 len;
+       uint32_t len;
        char *ret;
 
        len = centry_uint8(centry);
@@ -395,48 +403,53 @@ static bool wcache_server_down(struct winbindd_domain *domain)
        return ret;
 }
 
-static bool wcache_fetch_seqnum(const char *domain_name, uint32_t *seqnum,
-                               uint32_t *last_seq_check)
+struct wcache_seqnum_state {
+       uint32_t *seqnum;
+       uint32_t *last_seq_check;
+};
+
+static int wcache_seqnum_parser(TDB_DATA key, TDB_DATA data,
+                               void *private_data)
 {
-       char *key;
-       TDB_DATA data;
+       struct wcache_seqnum_state *state = private_data;
 
-       if (wcache->tdb == NULL) {
-               DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
-               return false;
+       if (data.dsize != 8) {
+               DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
+                          (int)data.dsize));
+               return -1;
        }
 
-       key = talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name);
-       if (key == NULL) {
-               DEBUG(10, ("talloc failed\n"));
-               return false;
-       }
+       *state->seqnum = IVAL(data.dptr, 0);
+       *state->last_seq_check = IVAL(data.dptr, 4);
+       return 0;
+}
 
-       data = tdb_fetch_bystring(wcache->tdb, key);
-       TALLOC_FREE(key);
+static bool wcache_fetch_seqnum(const char *domain_name, uint32_t *seqnum,
+                               uint32_t *last_seq_check)
+{
+       struct wcache_seqnum_state state = {
+               .seqnum = seqnum, .last_seq_check = last_seq_check
+       };
+       size_t len = strlen(domain_name);
+       char keystr[len+8];
+       TDB_DATA key = { .dptr = (uint8_t *)keystr, .dsize = sizeof(keystr) };
+       int ret;
 
-       if (data.dptr == NULL) {
-               DEBUG(10, ("wcache_fetch_seqnum: %s not found\n",
-                          domain_name));
-               return false;
-       }
-       if (data.dsize != 8) {
-               DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
-                          (int)data.dsize));
-               SAFE_FREE(data.dptr);
+       if (wcache->tdb == NULL) {
+               DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
                return false;
        }
 
-       *seqnum = IVAL(data.dptr, 0);
-       *last_seq_check = IVAL(data.dptr, 4);
-       SAFE_FREE(data.dptr);
+       snprintf(keystr, sizeof(keystr),  "SEQNUM/%s", domain_name);
 
-       return true;
+       ret = tdb_parse_record(wcache->tdb, key, wcache_seqnum_parser,
+                              &state);
+       return (ret == 0);
 }
 
 static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
 {
-       uint32 last_check, time_diff;
+       uint32_t last_check, time_diff;
 
        if (!wcache_fetch_seqnum(domain->name, &domain->sequence_number,
                                 &last_check)) {
@@ -447,16 +460,16 @@ static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
        /* have we expired? */
 
        time_diff = now - domain->last_seq_check;
-       if ( time_diff > lp_winbind_cache_time() ) {
+       if ((int)time_diff > lp_winbind_cache_time()) {
                DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
                        domain->name, domain->sequence_number,
-                       (uint32)domain->last_seq_check));
+                       (uint32_t)domain->last_seq_check));
                return NT_STATUS_UNSUCCESSFUL;
        }
 
        DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n", 
                domain->name, domain->sequence_number, 
-               (uint32)domain->last_seq_check));
+               (uint32_t)domain->last_seq_check));
 
        return NT_STATUS_OK;
 }
@@ -464,7 +477,9 @@ static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
 bool wcache_store_seqnum(const char *domain_name, uint32_t seqnum,
                         time_t last_seq_check)
 {
-       char *key_str;
+       size_t len = strlen(domain_name);
+       char keystr[len+8];
+       TDB_DATA key = { .dptr = (uint8_t *)keystr, .dsize = sizeof(keystr) };
        uint8_t buf[8];
        int ret;
 
@@ -473,22 +488,16 @@ bool wcache_store_seqnum(const char *domain_name, uint32_t seqnum,
                return false;
        }
 
-       key_str = talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name);
-       if (key_str == NULL) {
-               DEBUG(10, ("talloc_asprintf failed\n"));
-               return false;
-       }
+       snprintf(keystr, sizeof(keystr),  "SEQNUM/%s", domain_name);
 
        SIVAL(buf, 0, seqnum);
        SIVAL(buf, 4, last_seq_check);
 
-       ret = tdb_store_bystring(wcache->tdb, key_str,
-                                make_tdb_data(buf, sizeof(buf)), TDB_REPLACE);
-       TALLOC_FREE(key_str);
+       ret = tdb_store(wcache->tdb, key, make_tdb_data(buf, sizeof(buf)),
+                       TDB_REPLACE);
        if (ret != 0) {
                DEBUG(10, ("tdb_store_bystring failed: %s\n",
-                          tdb_errorstr_compat(wcache->tdb)));
-               TALLOC_FREE(key_str);
+                          tdb_errorstr(wcache->tdb)));
                return false;
        }
 
@@ -505,11 +514,10 @@ static bool store_cache_seqnum( struct winbindd_domain *domain )
 }
 
 /*
-  refresh the domain sequence number. If force is true
-  then always refresh it, no matter how recently we fetched it
+  refresh the domain sequence number on timeout.
 */
 
-static void refresh_sequence_number(struct winbindd_domain *domain, bool force)
+static void refresh_sequence_number(struct winbindd_domain *domain)
 {
        NTSTATUS status;
        unsigned time_diff;
@@ -532,7 +540,7 @@ static void refresh_sequence_number(struct winbindd_domain *domain, bool force)
        time_diff = t - domain->last_seq_check;
 
        /* see if we have to refetch the domain sequence number */
-       if (!force && (time_diff < cache_time) &&
+       if ((time_diff < cache_time) &&
                        (domain->sequence_number != DOM_SEQUENCE_NONE) &&
                        NT_STATUS_IS_OK(domain->last_status)) {
                DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
@@ -619,7 +627,7 @@ static bool centry_expired(struct winbindd_domain *domain, const char *keystr, s
           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)))) {
+               && ((time_t)centry->timeout > time(NULL)))) {
                DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
                        keystr, domain->name ));
                return false;
@@ -639,7 +647,7 @@ static struct cache_entry *wcache_fetch_raw(char *kstr)
        TDB_DATA key;
 
        key = string_tdb_data(kstr);
-       data = tdb_fetch_compat(wcache->tdb, key);
+       data = tdb_fetch(wcache->tdb, key);
        if (!data.dptr) {
                /* a cache miss */
                return NULL;
@@ -706,7 +714,7 @@ static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
                return NULL;
        }
 
-       refresh_sequence_number(domain, false);
+       refresh_sequence_number(domain);
 
        va_start(ap, format);
        smb_xvasprintf(&kstr, format, ap);
@@ -755,7 +763,7 @@ static void wcache_delete(const char *format, ...)
 /*
   make sure we have at least len bytes available in a centry 
 */
-static void centry_expand(struct cache_entry *centry, uint32 len)
+static void centry_expand(struct cache_entry *centry, uint32_t len)
 {
        if (centry->len - centry->ofs >= len)
                return;
@@ -779,9 +787,9 @@ static void centry_put_uint64_t(struct cache_entry *centry, uint64_t v)
 }
 
 /*
-  push a uint32 into a centry 
+  push a uint32_t into a centry
 */
-static void centry_put_uint32(struct cache_entry *centry, uint32 v)
+static void centry_put_uint32(struct cache_entry *centry, uint32_t v)
 {
        centry_expand(centry, 4);
        SIVAL(centry->data, centry->ofs, v);
@@ -789,9 +797,9 @@ static void centry_put_uint32(struct cache_entry *centry, uint32 v)
 }
 
 /*
-  push a uint16 into a centry 
+  push a uint16_t into a centry
 */
-static void centry_put_uint16(struct cache_entry *centry, uint16 v)
+static void centry_put_uint16(struct cache_entry *centry, uint16_t v)
 {
        centry_expand(centry, 2);
        SSVAL(centry->data, centry->ofs, v);
@@ -799,9 +807,9 @@ static void centry_put_uint16(struct cache_entry *centry, uint16 v)
 }
 
 /*
-  push a uint8 into a centry 
+  push a uint8_t into a centry
 */
-static void centry_put_uint8(struct cache_entry *centry, uint8 v)
+static void centry_put_uint8(struct cache_entry *centry, uint8_t v)
 {
        centry_expand(centry, 1);
        SCVAL(centry->data, centry->ofs, v);
@@ -836,7 +844,7 @@ static void centry_put_string(struct cache_entry *centry, const char *s)
 /* 
    push a 16 byte hash into a centry - treat as 16 byte string.
  */
-static void centry_put_hash16(struct cache_entry *centry, const uint8 val[16])
+static void centry_put_hash16(struct cache_entry *centry, const uint8_t val[16])
 {
        centry_put_uint8(centry, 16);
        centry_expand(centry, 16);
@@ -856,7 +864,7 @@ static void centry_put_sid(struct cache_entry *centry, const struct dom_sid *sid
 */
 static void centry_put_ntstatus(struct cache_entry *centry, NTSTATUS status)
 {
-       uint32 status_value = NT_STATUS_V(status);
+       uint32_t status_value = NT_STATUS_V(status);
        centry_put_uint32(centry, status_value);
 }
 
@@ -886,7 +894,8 @@ static void centry_put_time(struct cache_entry *centry, time_t t)
 /*
   start a centry for output. When finished, call centry_end()
 */
-struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status)
+static struct cache_entry *centry_start(struct winbindd_domain *domain,
+                                       NTSTATUS status)
 {
        struct cache_entry *centry;
 
@@ -896,7 +905,7 @@ struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status
        centry = SMB_XMALLOC_P(struct cache_entry);
 
        centry->len = 8192; /* reasonable default */
-       centry->data = SMB_XMALLOC_ARRAY(uint8, centry->len);
+       centry->data = SMB_XMALLOC_ARRAY(uint8_t, centry->len);
        centry->ofs = 0;
        centry->sequence_number = domain->sequence_number;
        centry->timeout = lp_winbind_cache_time() + time(NULL);
@@ -937,69 +946,40 @@ static void wcache_save_name_to_sid(struct winbindd_domain *domain,
                                    const char *name, const struct dom_sid *sid,
                                    enum lsa_SidType type)
 {
-       struct cache_entry *centry;
-       fstring uname;
+       bool ok;
 
-       centry = centry_start(domain, status);
-       if (!centry)
-               return;
-       centry_put_uint32(centry, type);
-       centry_put_sid(centry, sid);
-       fstrcpy(uname, name);
-       (void)strupper_m(uname);
-       centry_end(centry, "NS/%s/%s", domain_name, uname);
-       DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name,
-                 uname, sid_string_dbg(sid), nt_errstr(status)));
-       centry_free(centry);
+       ok = namemap_cache_set_name2sid(domain_name, name, sid, type,
+                                       time(NULL) + lp_winbind_cache_time());
+       if (!ok) {
+               DBG_DEBUG("namemap_cache_set_name2sid failed\n");
+       }
+
+       /*
+        * Don't store the reverse mapping. The name came from user
+        * input, and we might not have the correct capitalization,
+        * which is important for nsswitch.
+        */
 }
 
 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status, 
                                    const struct dom_sid *sid, const char *domain_name, const char *name, enum lsa_SidType type)
 {
-       struct cache_entry *centry;
-       fstring sid_string;
-
-       centry = centry_start(domain, status);
-       if (!centry)
-               return;
+       bool ok;
 
-       if (NT_STATUS_IS_OK(status)) {
-               centry_put_uint32(centry, type);
-               centry_put_string(centry, domain_name);
-               centry_put_string(centry, name);
+       ok = namemap_cache_set_sid2name(sid, domain_name, name, type,
+                                       time(NULL) + lp_winbind_cache_time());
+       if (!ok) {
+               DBG_DEBUG("namemap_cache_set_sid2name failed\n");
        }
 
-       centry_end(centry, "SN/%s", sid_to_fstring(sid_string, sid));
-       DEBUG(10,("wcache_save_sid_to_name: %s -> %s\\%s (%s)\n", sid_string,
-                 domain_name, name, nt_errstr(status)));
-       centry_free(centry);
-}
-
-
-static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status,
-                            struct wbint_userinfo *info)
-{
-       struct cache_entry *centry;
-       fstring sid_string;
-
-       if (is_null_sid(&info->user_sid)) {
-               return;
+       if (type != SID_NAME_UNKNOWN) {
+               ok = namemap_cache_set_name2sid(
+                       domain_name, name, sid, type,
+                       time(NULL) + lp_winbind_cache_time());
+               if (!ok) {
+                       DBG_DEBUG("namemap_cache_set_name2sid failed\n");
+               }
        }
-
-       centry = centry_start(domain, status);
-       if (!centry)
-               return;
-       centry_put_string(centry, info->acct_name);
-       centry_put_string(centry, info->full_name);
-       centry_put_string(centry, info->homedir);
-       centry_put_string(centry, info->shell);
-       centry_put_uint32(centry, info->primary_gid);
-       centry_put_sid(centry, &info->user_sid);
-       centry_put_sid(centry, &info->group_sid);
-       centry_end(centry, "U/%s", sid_to_fstring(sid_string,
-                                                 &info->user_sid));
-       DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
-       centry_free(centry);
 }
 
 static void wcache_save_lockout_policy(struct winbindd_domain *domain,
@@ -1111,14 +1091,10 @@ NTSTATUS resolve_username_to_alias( TALLOC_CTX *mem_ctx,
        if (!cache->tdb)
                goto do_query;
 
-       upper_name = talloc_strdup(mem_ctx, name);
+       upper_name = talloc_strdup_upper(mem_ctx, name);
        if (upper_name == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
-       if (!strupper_m(upper_name)) {
-               talloc_free(upper_name);
-               return NT_STATUS_INVALID_PARAMETER;
-       }
 
        centry = wcache_fetch(cache, domain, "NSS/NA/%s", upper_name);
 
@@ -1264,9 +1240,9 @@ do_query:
 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const struct dom_sid *sid)
 {
        struct winbind_cache *cache = get_cache(domain);
-       TDB_DATA data;
+       int ret;
        fstring key_str, tmp;
-       uint32 rid;
+       uint32_t rid;
 
        if (!cache->tdb) {
                return NT_STATUS_INTERNAL_DB_ERROR;
@@ -1282,12 +1258,11 @@ 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_compat(cache->tdb, string_tdb_data(key_str));
-       if (!data.dptr) {
+       ret = tdb_exists(cache->tdb, string_tdb_data(key_str));
+       if (ret != 1) {
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
 
-       SAFE_FREE(data.dptr);
        return NT_STATUS_OK;
 }
 
@@ -1297,13 +1272,13 @@ NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const struct
 NTSTATUS wcache_get_creds(struct winbindd_domain *domain, 
                          TALLOC_CTX *mem_ctx, 
                          const struct dom_sid *sid,
-                         const uint8 **cached_nt_pass,
-                         const uint8 **cached_salt)
+                         const uint8_t **cached_nt_pass,
+                         const uint8_t **cached_salt)
 {
        struct winbind_cache *cache = get_cache(domain);
        struct cache_entry *centry = NULL;
        NTSTATUS status;
-       uint32 rid;
+       uint32_t rid;
        fstring tmp;
 
        if (!cache->tdb) {
@@ -1341,7 +1316,7 @@ NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
           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);
+       *cached_nt_pass = (const uint8_t *)centry_hash16(centry, mem_ctx);
        if (*cached_nt_pass == NULL) {
                fstring sidstr;
 
@@ -1358,7 +1333,7 @@ NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
 
        /* 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);
+               *cached_salt = (const uint8_t *)centry_hash16(centry, mem_ctx);
        } else {
                *cached_salt = NULL;
        }
@@ -1381,13 +1356,13 @@ NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
 
 NTSTATUS wcache_save_creds(struct winbindd_domain *domain, 
                           const struct dom_sid *sid,
-                          const uint8 nt_pass[NT_HASH_LEN])
+                          const uint8_t nt_pass[NT_HASH_LEN])
 {
        struct cache_entry *centry;
        fstring sid_string;
-       uint32 rid;
-       uint8 cred_salt[NT_HASH_LEN];
-       uint8 salted_hash[NT_HASH_LEN];
+       uint32_t rid;
+       uint8_t cred_salt[NT_HASH_LEN];
+       uint8_t salted_hash[NT_HASH_LEN];
 
        if (is_null_sid(sid)) {
                return NT_STATUS_INVALID_SID;
@@ -1423,17 +1398,20 @@ NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
 
 
 /* Query display info. This is the basic user list fn */
-static NTSTATUS query_user_list(struct winbindd_domain *domain,
-                               TALLOC_CTX *mem_ctx,
-                               uint32 *num_entries, 
-                               struct wbint_userinfo **info)
+NTSTATUS wb_cache_query_user_list(struct winbindd_domain *domain,
+                                 TALLOC_CTX *mem_ctx,
+                                 uint32_t **prids)
 {
        struct winbind_cache *cache = get_cache(domain);
        struct cache_entry *centry = NULL;
+       uint32_t num_rids = 0;
+       uint32_t *rids = NULL;
        NTSTATUS status;
        unsigned int i, retry;
        bool old_status = domain->online;
 
+       *prids = NULL;
+
        if (!cache->tdb)
                goto do_query;
 
@@ -1442,22 +1420,20 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
                goto do_query;
 
 do_fetch_cache:
-       *num_entries = centry_uint32(centry);
+       num_rids = centry_uint32(centry);
 
-       if (*num_entries == 0)
+       if (num_rids == 0) {
                goto do_cached;
+       }
 
-       (*info) = talloc_array(mem_ctx, struct wbint_userinfo, *num_entries);
-       if (! (*info)) {
-               smb_panic_fn("query_user_list out of memory");
+       rids = talloc_array(mem_ctx, uint32_t, num_rids);
+       if (rids == NULL) {
+               centry_free(centry);
+               return NT_STATUS_NO_MEMORY;
        }
-       for (i=0; i<(*num_entries); i++) {
-               (*info)[i].acct_name = centry_string(centry, mem_ctx);
-               (*info)[i].full_name = centry_string(centry, mem_ctx);
-               (*info)[i].homedir = centry_string(centry, mem_ctx);
-               (*info)[i].shell = centry_string(centry, mem_ctx);
-               centry_sid(centry, &(*info)[i].user_sid);
-               centry_sid(centry, &(*info)[i].group_sid);
+
+       for (i=0; i<num_rids; i++) {
+               rids[i] = centry_uint32(centry);
        }
 
 do_cached:     
@@ -1470,8 +1446,6 @@ do_cached:
        return status;
 
 do_query:
-       *num_entries = 0;
-       *info = NULL;
 
        /* Return status value returned by seq number check */
 
@@ -1492,7 +1466,11 @@ do_query:
                DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
                        domain->name ));
 
-               status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
+               rids = NULL;
+               status = domain->backend->query_user_list(domain, mem_ctx,
+                                                         &rids);
+               num_rids = talloc_array_length(rids);
+
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(3, ("query_user_list: returned 0x%08x, "
                                  "retrying\n", NT_STATUS_V(status)));
@@ -1500,7 +1478,7 @@ do_query:
                if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
                        DEBUG(3, ("query_user_list: flushing "
                                  "connection cache\n"));
-                       invalidate_cm_connection(&domain->conn);
+                       invalidate_cm_connection(domain);
                }
                if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
                    NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
@@ -1508,7 +1486,7 @@ do_query:
                                set_domain_offline(domain);
                        }
                        /* store partial response. */
-                       if (*num_entries > 0) {
+                       if (num_rids > 0) {
                                /*
                                 * humm, what about the status used for cache?
                                 * Should it be NT_STATUS_OK?
@@ -1536,48 +1514,31 @@ do_query:
                 (retry++ < 5));
 
        /* and save it */
-       refresh_sequence_number(domain, false);
+       refresh_sequence_number(domain);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
        centry = centry_start(domain, status);
        if (!centry)
                goto skip_save;
-       centry_put_uint32(centry, *num_entries);
-       for (i=0; i<(*num_entries); i++) {
-               centry_put_string(centry, (*info)[i].acct_name);
-               centry_put_string(centry, (*info)[i].full_name);
-               centry_put_string(centry, (*info)[i].homedir);
-               centry_put_string(centry, (*info)[i].shell);
-               centry_put_sid(centry, &(*info)[i].user_sid);
-               centry_put_sid(centry, &(*info)[i].group_sid);
-               if (domain->backend && domain->backend->consistent) {
-                       /* when the backend is consistent we can pre-prime some mappings */
-                       wcache_save_name_to_sid(domain, NT_STATUS_OK, 
-                                               domain->name,
-                                               (*info)[i].acct_name, 
-                                               &(*info)[i].user_sid,
-                                               SID_NAME_USER);
-                       wcache_save_sid_to_name(domain, NT_STATUS_OK, 
-                                               &(*info)[i].user_sid,
-                                               domain->name,
-                                               (*info)[i].acct_name, 
-                                               SID_NAME_USER);
-                       wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
-               }
+       centry_put_uint32(centry, num_rids);
+       for (i=0; i<num_rids; i++) {
+               centry_put_uint32(centry, rids[i]);
        }       
        centry_end(centry, "UL/%s", domain->name);
        centry_free(centry);
 
+       *prids = rids;
+
 skip_save:
        return status;
 }
 
 /* list all domain groups */
-static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
-                               TALLOC_CTX *mem_ctx,
-                               uint32 *num_entries, 
-                               struct wb_acct_info **info)
+NTSTATUS wb_cache_enum_dom_groups(struct winbindd_domain *domain,
+                                 TALLOC_CTX *mem_ctx,
+                                 uint32_t *num_entries,
+                                 struct wb_acct_info **info)
 {
        struct winbind_cache *cache = get_cache(domain);
        struct cache_entry *centry = NULL;
@@ -1648,7 +1609,7 @@ do_query:
                }
        }
        /* and save it */
-       refresh_sequence_number(domain, false);
+       refresh_sequence_number(domain);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -1669,10 +1630,10 @@ skip_save:
 }
 
 /* list all domain groups */
-static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
-                               TALLOC_CTX *mem_ctx,
-                               uint32 *num_entries, 
-                               struct wb_acct_info **info)
+NTSTATUS wb_cache_enum_local_groups(struct winbindd_domain *domain,
+                                   TALLOC_CTX *mem_ctx,
+                                   uint32_t *num_entries,
+                                   struct wb_acct_info **info)
 {
        struct winbind_cache *cache = get_cache(domain);
        struct cache_entry *centry = NULL;
@@ -1753,7 +1714,7 @@ do_query:
                }
        }
        /* and save it */
-       refresh_sequence_number(domain, false);
+       refresh_sequence_number(domain);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -1773,53 +1734,61 @@ skip_save:
        return status;
 }
 
-NTSTATUS wcache_name_to_sid(struct winbindd_domain *domain,
-                           const char *domain_name,
-                           const char *name,
-                           struct dom_sid *sid,
-                           enum lsa_SidType *type)
+struct wcache_name_to_sid_state {
+       struct dom_sid *sid;
+       enum lsa_SidType *type;
+       bool offline;
+       bool found;
+};
+
+static void wcache_name_to_sid_fn(const struct dom_sid *sid,
+                                 enum lsa_SidType type, time_t timeout,
+                                 void *private_data)
 {
-       struct winbind_cache *cache = get_cache(domain);
-       struct cache_entry *centry;
-       NTSTATUS status;
-       char *uname;
+       struct wcache_name_to_sid_state *state = private_data;
 
-       if (cache->tdb == NULL) {
-               return NT_STATUS_NOT_FOUND;
-       }
+       *state->sid = *sid;
+       *state->type = type;
+       state->found = (state->offline || (timeout < time(NULL)));
+}
 
-       uname = talloc_strdup_upper(talloc_tos(), name);
-       if (uname == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
+static NTSTATUS wcache_name_to_sid(struct winbindd_domain *domain,
+                                  const char *domain_name,
+                                  const char *name,
+                                  struct dom_sid *sid,
+                                  enum lsa_SidType *type)
+{
+       struct wcache_name_to_sid_state state = {
+               .sid = sid, .type = type, .found = false,
+               .offline = is_domain_offline(domain),
+       };
+       bool ok;
 
-       centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
-       TALLOC_FREE(uname);
-       if (centry == NULL) {
+       ok = namemap_cache_find_name(domain_name, name, wcache_name_to_sid_fn,
+                                    &state);
+       if (!ok) {
+               DBG_DEBUG("namemap_cache_find_name failed\n");
                return NT_STATUS_NOT_FOUND;
        }
-
-       status = centry->status;
-       if (NT_STATUS_IS_OK(status)) {
-               *type = (enum lsa_SidType)centry_uint32(centry);
-               centry_sid(centry, sid);
+       if (!state.found) {
+               DBG_DEBUG("cache entry not found\n");
+               return NT_STATUS_NOT_FOUND;
+       }
+       if (*type == SID_NAME_UNKNOWN) {
+               return NT_STATUS_NONE_MAPPED;
        }
 
-       DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
-                 "%s\n", domain->name, nt_errstr(status) ));
-
-       centry_free(centry);
-       return status;
+       return NT_STATUS_OK;
 }
 
 /* convert a single name to a sid in a domain */
-static NTSTATUS name_to_sid(struct winbindd_domain *domain,
-                           TALLOC_CTX *mem_ctx,
-                           const char *domain_name,
-                           const char *name,
-                           uint32_t flags,
-                           struct dom_sid *sid,
-                           enum lsa_SidType *type)
+NTSTATUS wb_cache_name_to_sid(struct winbindd_domain *domain,
+                             TALLOC_CTX *mem_ctx,
+                             const char *domain_name,
+                             const char *name,
+                             uint32_t flags,
+                             struct dom_sid *sid,
+                             enum lsa_SidType *type)
 {
        NTSTATUS status;
        bool old_status;
@@ -1847,6 +1816,7 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain,
        DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
                domain->name ));
 
+       winbindd_domain_init_backend(domain);
        status = domain->backend->name_to_sid(domain, mem_ctx, domain_name,
                                              name, flags, sid, type);
 
@@ -1864,11 +1834,17 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain,
                }
        }
        /* and save it */
-       refresh_sequence_number(domain, false);
 
        if (domain->online &&
            (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
-               wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
+               enum lsa_SidType save_type = *type;
+
+               if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
+                       save_type = SID_NAME_UNKNOWN;
+               }
+
+               wcache_save_name_to_sid(domain, status, domain_name, name, sid,
+                                       save_type);
 
                /* Only save the reverse mapping if this was not a UPN */
                if (!strchr(name, '@')) {
@@ -1876,63 +1852,79 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain,
                                return NT_STATUS_INVALID_PARAMETER;
                        }
                        (void)strlower_m(discard_const_p(char, name));
-                       wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
+                       wcache_save_sid_to_name(domain, status, sid,
+                                               domain_name, name, save_type);
                }
        }
 
        return status;
 }
 
-NTSTATUS wcache_sid_to_name(struct winbindd_domain *domain,
-                           const struct dom_sid *sid,
-                           TALLOC_CTX *mem_ctx,
-                           char **domain_name,
-                           char **name,
-                           enum lsa_SidType *type)
+struct wcache_sid_to_name_state {
+       TALLOC_CTX *mem_ctx;
+       char **domain_name;
+       char **name;
+       enum lsa_SidType *type;
+       bool offline;
+       bool found;
+};
+
+static void wcache_sid_to_name_fn(const char *domain, const char *name,
+                                 enum lsa_SidType type, time_t timeout,
+                                 void *private_data)
 {
-       struct winbind_cache *cache = get_cache(domain);
-       struct cache_entry *centry;
-       char *sid_string;
-       NTSTATUS status;
+       struct wcache_sid_to_name_state *state = private_data;
 
-       if (cache->tdb == NULL) {
-               return NT_STATUS_NOT_FOUND;
+       *state->domain_name = talloc_strdup(state->mem_ctx, domain);
+       if (*state->domain_name == NULL) {
+               return;
        }
-
-       sid_string = sid_string_tos(sid);
-       if (sid_string == NULL) {
-               return NT_STATUS_NO_MEMORY;
+       *state->name = talloc_strdup(state->mem_ctx, name);
+       if (*state->name == NULL) {
+               return;
        }
+       *state->type = type;
+       state->found = (state->offline || (timeout < time(NULL)));
+}
 
-       centry = wcache_fetch(cache, domain, "SN/%s", sid_string);
-       TALLOC_FREE(sid_string);
-       if (centry == NULL) {
+static NTSTATUS wcache_sid_to_name(struct winbindd_domain *domain,
+                                  const struct dom_sid *sid,
+                                  TALLOC_CTX *mem_ctx,
+                                  char **domain_name,
+                                  char **name,
+                                  enum lsa_SidType *type)
+{
+       struct wcache_sid_to_name_state state = {
+               .mem_ctx = mem_ctx, .found = false,
+               .domain_name = domain_name, .name = name, .type = type,
+               .offline = is_domain_offline(domain)
+       };
+       bool ok;
+
+       ok = namemap_cache_find_sid(sid, wcache_sid_to_name_fn, &state);
+       if (!ok) {
+               DBG_DEBUG("namemap_cache_find_name failed\n");
                return NT_STATUS_NOT_FOUND;
        }
-
-       if (NT_STATUS_IS_OK(centry->status)) {
-               *type = (enum lsa_SidType)centry_uint32(centry);
-               *domain_name = centry_string(centry, mem_ctx);
-               *name = centry_string(centry, mem_ctx);
+       if (!state.found) {
+               DBG_DEBUG("cache entry not found\n");
+               return NT_STATUS_NOT_FOUND;
+       }
+       if (*type == SID_NAME_UNKNOWN) {
+               return NT_STATUS_NONE_MAPPED;
        }
 
-       status = centry->status;
-       centry_free(centry);
-
-       DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
-                 "%s\n", domain->name, nt_errstr(status) ));
-
-       return status;
+       return NT_STATUS_OK;
 }
 
 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
    given */
-static NTSTATUS sid_to_name(struct winbindd_domain *domain,
-                           TALLOC_CTX *mem_ctx,
-                           const struct dom_sid *sid,
-                           char **domain_name,
-                           char **name,
-                           enum lsa_SidType *type)
+NTSTATUS wb_cache_sid_to_name(struct winbindd_domain *domain,
+                             TALLOC_CTX *mem_ctx,
+                             const struct dom_sid *sid,
+                             char **domain_name,
+                             char **name,
+                             enum lsa_SidType *type)
 {
        NTSTATUS status;
        bool old_status;
@@ -1961,6 +1953,8 @@ static NTSTATUS sid_to_name(struct winbindd_domain *domain,
        DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
                domain->name ));
 
+       winbindd_domain_init_backend(domain);
+
        status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
 
        if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
@@ -1978,7 +1972,6 @@ static NTSTATUS sid_to_name(struct winbindd_domain *domain,
                }
        }
        /* and save it */
-       refresh_sequence_number(domain, false);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -1990,14 +1983,14 @@ static NTSTATUS sid_to_name(struct winbindd_domain *domain,
        return status;
 }
 
-static NTSTATUS rids_to_names(struct winbindd_domain *domain,
-                             TALLOC_CTX *mem_ctx,
-                             const struct dom_sid *domain_sid,
-                             uint32 *rids,
-                             size_t num_rids,
-                             char **domain_name,
-                             char ***names,
-                             enum lsa_SidType **types)
+NTSTATUS wb_cache_rids_to_names(struct winbindd_domain *domain,
+                               TALLOC_CTX *mem_ctx,
+                               const struct dom_sid *domain_sid,
+                               uint32_t *rids,
+                               size_t num_rids,
+                               char **domain_name,
+                               char ***names,
+                               enum lsa_SidType **types)
 {
        struct winbind_cache *cache = get_cache(domain);
        size_t i;
@@ -2031,48 +2024,45 @@ static NTSTATUS rids_to_names(struct winbindd_domain *domain,
 
        for (i=0; i<num_rids; i++) {
                struct dom_sid sid;
-               struct cache_entry *centry;
-               fstring tmp;
+               NTSTATUS status;
+               enum lsa_SidType type;
+               char *dom, *name;
 
                if (!sid_compose(&sid, domain_sid, rids[i])) {
                        result = NT_STATUS_INTERNAL_ERROR;
                        goto error;
                }
 
-               centry = wcache_fetch(cache, domain, "SN/%s",
-                                     sid_to_fstring(tmp, &sid));
-               if (!centry) {
-                       goto do_query;
-               }
+               status = wcache_sid_to_name(domain, &sid, *names, &dom,
+                                           &name, &type);
 
                (*types)[i] = SID_NAME_UNKNOWN;
                (*names)[i] = talloc_strdup(*names, "");
 
-               if (NT_STATUS_IS_OK(centry->status)) {
-                       char *dom;
+               if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
+                       /* not cached */
+                       goto do_query;
+               }
+
+               if (NT_STATUS_IS_OK(status)) {
                        have_mapped = true;
-                       (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
+                       (*types)[i] = type;
 
-                       dom = centry_string(centry, mem_ctx);
                        if (*domain_name == NULL) {
                                *domain_name = dom;
                        } else {
-                               talloc_free(dom);
+                               TALLOC_FREE(dom);
                        }
 
-                       (*names)[i] = centry_string(centry, *names);
+                       (*names)[i] = name;
 
-               } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)
-                          || NT_STATUS_EQUAL(centry->status, STATUS_SOME_UNMAPPED)) {
+               } else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
                        have_unmapped = true;
-
                } else {
                        /* something's definitely wrong */
-                       result = centry->status;
+                       result = status;
                        goto error;
                }
-
-               centry_free(centry);
        }
 
        if (!have_mapped) {
@@ -2093,7 +2083,7 @@ static NTSTATUS rids_to_names(struct winbindd_domain *domain,
                                                names, types);
 
        if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
-               NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
+           NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
                if (!domain->internal && old_status) {
                        set_domain_offline(domain);
                }
@@ -2103,51 +2093,58 @@ static NTSTATUS rids_to_names(struct winbindd_domain *domain,
                        old_status) {
                        have_mapped = have_unmapped = false;
 
+                       *names = talloc_array(mem_ctx, char *, num_rids);
+                       if (*names == NULL) {
+                               result = NT_STATUS_NO_MEMORY;
+                               goto error;
+                       }
+
+                       *types = talloc_array(mem_ctx, enum lsa_SidType,
+                                             num_rids);
+                       if (*types == NULL) {
+                               result = NT_STATUS_NO_MEMORY;
+                               goto error;
+                       }
+
                        for (i=0; i<num_rids; i++) {
                                struct dom_sid sid;
-                               struct cache_entry *centry;
-                               fstring tmp;
+                               NTSTATUS status;
+                               enum lsa_SidType type;
+                               char *dom, *name;
 
                                if (!sid_compose(&sid, domain_sid, rids[i])) {
                                        result = NT_STATUS_INTERNAL_ERROR;
                                        goto error;
                                }
 
-                               centry = wcache_fetch(cache, domain, "SN/%s",
-                                                     sid_to_fstring(tmp, &sid));
-                               if (!centry) {
-                                       (*types)[i] = SID_NAME_UNKNOWN;
-                                       (*names)[i] = talloc_strdup(*names, "");
-                                       continue;
-                               }
+                               status = wcache_sid_to_name(domain, &sid,
+                                                           *names, &dom,
+                                                           &name, &type);
 
                                (*types)[i] = SID_NAME_UNKNOWN;
                                (*names)[i] = talloc_strdup(*names, "");
 
-                               if (NT_STATUS_IS_OK(centry->status)) {
-                                       char *dom;
+                               if (NT_STATUS_IS_OK(status)) {
                                        have_mapped = true;
-                                       (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
+                                       (*types)[i] = type;
 
-                                       dom = centry_string(centry, mem_ctx);
                                        if (*domain_name == NULL) {
                                                *domain_name = dom;
                                        } else {
-                                               talloc_free(dom);
+                                               TALLOC_FREE(dom);
                                        }
 
-                                       (*names)[i] = centry_string(centry, *names);
+                                       (*names)[i] = name;
 
-                               } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
+                               } else if (NT_STATUS_EQUAL(
+                                                  status,
+                                                  NT_STATUS_NONE_MAPPED)) {
                                        have_unmapped = true;
-
                                } else {
                                        /* something's definitely wrong */
-                                       result = centry->status;
+                                       result = status;
                                        goto error;
                                }
-
-                               centry_free(centry);
                        }
 
                        if (!have_mapped) {
@@ -2188,7 +2185,7 @@ static NTSTATUS rids_to_names(struct winbindd_domain *domain,
                return result;
        }
 
-       refresh_sequence_number(domain, false);
+       refresh_sequence_number(domain);
 
        for (i=0; i<num_rids; i++) {
                struct dom_sid sid;
@@ -2214,10 +2211,10 @@ static NTSTATUS rids_to_names(struct winbindd_domain *domain,
        return result;
 }
 
-NTSTATUS wcache_query_user(struct winbindd_domain *domain,
-                          TALLOC_CTX *mem_ctx,
-                          const struct dom_sid *user_sid,
-                          struct wbint_userinfo *info)
+static NTSTATUS wcache_query_user(struct winbindd_domain *domain,
+                                 TALLOC_CTX *mem_ctx,
+                                 const struct dom_sid *user_sid,
+                                 struct wbint_userinfo *info)
 {
        struct winbind_cache *cache = get_cache(domain);
        struct cache_entry *centry = NULL;
@@ -2258,11 +2255,14 @@ NTSTATUS wcache_query_user(struct winbindd_domain *domain,
           and the rest of the data doesn't matter */
        status = centry->status;
        if (NT_STATUS_IS_OK(status)) {
+               info->domain_name = centry_string(centry, mem_ctx);
                info->acct_name = centry_string(centry, mem_ctx);
                info->full_name = centry_string(centry, mem_ctx);
                info->homedir = centry_string(centry, mem_ctx);
                info->shell = centry_string(centry, mem_ctx);
+               info->uid = centry_uint32(centry);
                info->primary_gid = centry_uint32(centry);
+               info->primary_group_name = centry_string(centry, mem_ctx);
                centry_sid(centry, &info->user_sid);
                centry_sid(centry, &info->group_sid);
        }
@@ -2274,61 +2274,45 @@ NTSTATUS wcache_query_user(struct winbindd_domain *domain,
        return status;
 }
 
-/* Lookup user information from a rid */
-static NTSTATUS query_user(struct winbindd_domain *domain,
-                          TALLOC_CTX *mem_ctx,
-                          const struct dom_sid *user_sid,
-                          struct wbint_userinfo *info)
+
+/**
+* @brief Query a fullname from the username cache (for further gecos processing)
+*
+* @param domain                A pointer to the winbindd_domain struct.
+* @param mem_ctx       The talloc context.
+* @param user_sid      The user sid.
+* @param full_name     A pointer to the full_name string.
+*
+* @return NTSTATUS code
+*/
+NTSTATUS wcache_query_user_fullname(struct winbindd_domain *domain,
+                                   TALLOC_CTX *mem_ctx,
+                                   const struct dom_sid *user_sid,
+                                   const char **full_name)
 {
        NTSTATUS status;
-       bool old_status;
+       struct wbint_userinfo info;
 
-       old_status = domain->online;
-       status = wcache_query_user(domain, mem_ctx, user_sid, info);
-       if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
+       status = wcache_query_user(domain, mem_ctx, user_sid, &info);
+       if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-       ZERO_STRUCTP(info);
-
-       /* Return status value returned by seq number check */
-
-       if (!NT_STATUS_IS_OK(domain->last_status))
-               return domain->last_status;
-
-       DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
-               domain->name ));
-
-       status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
-
-       if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
-               NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
-               if (!domain->internal && old_status) {
-                       set_domain_offline(domain);
-               }
-               if (!domain->internal &&
-                       !domain->online &&
-                       old_status) {
-                       NTSTATUS cache_status;
-                       cache_status = wcache_query_user(domain, mem_ctx, user_sid, info);
-                       return cache_status;
+       if (info.full_name != NULL) {
+               *full_name = talloc_strdup(mem_ctx, info.full_name);
+               if (*full_name == NULL) {
+                       return NT_STATUS_NO_MEMORY;
                }
        }
-       /* and save it */
-       refresh_sequence_number(domain, false);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-       wcache_save_user(domain, status, info);
 
-       return status;
+       return NT_STATUS_OK;
 }
 
-NTSTATUS wcache_lookup_usergroups(struct winbindd_domain *domain,
-                                 TALLOC_CTX *mem_ctx,
-                                 const struct dom_sid *user_sid,
-                                 uint32_t *pnum_sids,
-                                 struct dom_sid **psids)
+static NTSTATUS wcache_lookup_usergroups(struct winbindd_domain *domain,
+                                        TALLOC_CTX *mem_ctx,
+                                        const struct dom_sid *user_sid,
+                                        uint32_t *pnum_sids,
+                                        struct dom_sid **psids)
 {
        struct winbind_cache *cache = get_cache(domain);
        struct cache_entry *centry = NULL;
@@ -2384,10 +2368,11 @@ NTSTATUS wcache_lookup_usergroups(struct winbindd_domain *domain,
 }
 
 /* Lookup groups a user is a member of. */
-static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
-                                 TALLOC_CTX *mem_ctx,
-                                 const struct dom_sid *user_sid,
-                                 uint32 *num_groups, struct dom_sid **user_gids)
+NTSTATUS wb_cache_lookup_usergroups(struct winbindd_domain *domain,
+                                   TALLOC_CTX *mem_ctx,
+                                   const struct dom_sid *user_sid,
+                                   uint32_t *num_groups,
+                                   struct dom_sid **user_gids)
 {
        struct cache_entry *centry = NULL;
        NTSTATUS status;
@@ -2433,7 +2418,7 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
                goto skip_save;
 
        /* and save it */
-       refresh_sequence_number(domain, false);
+       refresh_sequence_number(domain);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -2474,18 +2459,19 @@ static char *wcache_make_sidlist(TALLOC_CTX *mem_ctx, uint32_t num_sids,
        return sidlist;
 }
 
-NTSTATUS wcache_lookup_useraliases(struct winbindd_domain *domain,
-                                  TALLOC_CTX *mem_ctx, uint32_t num_sids,
-                                  const struct dom_sid *sids,
-                                  uint32_t *pnum_aliases, uint32_t **paliases)
+static NTSTATUS wcache_lookup_useraliases(struct winbindd_domain *domain,
+                                         TALLOC_CTX *mem_ctx,
+                                         uint32_t num_sids,
+                                         const struct dom_sid *sids,
+                                         uint32_t *pnum_aliases,
+                                         uint32_t **paliases)
 {
        struct winbind_cache *cache = get_cache(domain);
        struct cache_entry *centry = NULL;
-       uint32_t num_aliases;
+       uint32_t i, num_aliases;
        uint32_t *aliases;
        NTSTATUS status;
        char *sidlist;
-       int i;
 
        if (cache->tdb == NULL) {
                return NT_STATUS_NOT_FOUND;
@@ -2535,15 +2521,17 @@ NTSTATUS wcache_lookup_useraliases(struct winbindd_domain *domain,
        return status;
 }
 
-static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
-                                  TALLOC_CTX *mem_ctx,
-                                  uint32 num_sids, const struct dom_sid *sids,
-                                  uint32 *num_aliases, uint32 **alias_rids)
+NTSTATUS wb_cache_lookup_useraliases(struct winbindd_domain *domain,
+                                    TALLOC_CTX *mem_ctx,
+                                    uint32_t num_sids,
+                                    const struct dom_sid *sids,
+                                    uint32_t *num_aliases,
+                                    uint32_t **alias_rids)
 {
        struct cache_entry *centry = NULL;
        NTSTATUS status;
        char *sidlist;
-       int i;
+       uint32_t i;
        bool old_status;
 
        old_status = domain->online;
@@ -2586,7 +2574,7 @@ static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
                }
        }
        /* and save it */
-       refresh_sequence_number(domain, false);
+       refresh_sequence_number(domain);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -2603,12 +2591,12 @@ static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
        return status;
 }
 
-NTSTATUS wcache_lookup_groupmem(struct winbindd_domain *domain,
-                               TALLOC_CTX *mem_ctx,
-                               const struct dom_sid *group_sid,
-                               uint32_t *num_names,
-                               struct dom_sid **sid_mem, char ***names,
-                               uint32_t **name_types)
+static NTSTATUS wcache_lookup_groupmem(struct winbindd_domain *domain,
+                                      TALLOC_CTX *mem_ctx,
+                                      const struct dom_sid *group_sid,
+                                      uint32_t *num_names,
+                                      struct dom_sid **sid_mem, char ***names,
+                                      uint32_t **name_types)
 {
        struct winbind_cache *cache = get_cache(domain);
        struct cache_entry *centry = NULL;
@@ -2643,7 +2631,7 @@ NTSTATUS wcache_lookup_groupmem(struct winbindd_domain *domain,
 
        *sid_mem = talloc_array(mem_ctx, struct dom_sid, *num_names);
        *names = talloc_array(mem_ctx, char *, *num_names);
-       *name_types = talloc_array(mem_ctx, uint32, *num_names);
+       *name_types = talloc_array(mem_ctx, uint32_t, *num_names);
 
        if ((*sid_mem == NULL) || (*names == NULL) || (*name_types == NULL)) {
                TALLOC_FREE(*sid_mem);
@@ -2668,13 +2656,14 @@ NTSTATUS wcache_lookup_groupmem(struct winbindd_domain *domain,
        return status;
 }
 
-static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
-                               TALLOC_CTX *mem_ctx,
-                               const struct dom_sid *group_sid,
-                               enum lsa_SidType type,
-                               uint32 *num_names,
-                               struct dom_sid **sid_mem, char ***names,
-                               uint32 **name_types)
+NTSTATUS wb_cache_lookup_groupmem(struct winbindd_domain *domain,
+                                 TALLOC_CTX *mem_ctx,
+                                 const struct dom_sid *group_sid,
+                                 enum lsa_SidType type,
+                                 uint32_t *num_names,
+                                 struct dom_sid **sid_mem,
+                                 char ***names,
+                                 uint32_t **name_types)
 {
        struct cache_entry *centry = NULL;
        NTSTATUS status;
@@ -2722,7 +2711,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
                }
        }
        /* and save it */
-       refresh_sequence_number(domain, false);
+       refresh_sequence_number(domain);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -2743,9 +2732,10 @@ skip_save:
 }
 
 /* find the sequence number for a domain */
-static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
+NTSTATUS wb_cache_sequence_number(struct winbindd_domain *domain,
+                                 uint32_t *seq)
 {
-       refresh_sequence_number(domain, false);
+       refresh_sequence_number(domain);
 
        *seq = domain->sequence_number;
 
@@ -2755,16 +2745,16 @@ static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
 /* enumerate trusted domains 
  * (we need to have the list of trustdoms in the cache when we go offline) -
  * Guenther */
-static NTSTATUS trusted_domains(struct winbindd_domain *domain,
-                               TALLOC_CTX *mem_ctx,
-                               struct netr_DomainTrustList *trusts)
+NTSTATUS wb_cache_trusted_domains(struct winbindd_domain *domain,
+                                 TALLOC_CTX *mem_ctx,
+                                 struct netr_DomainTrustList *trusts)
 {
        NTSTATUS status;
        struct winbind_cache *cache;
        struct winbindd_tdc_domain *dom_list = NULL;
        size_t num_domains = 0;
        bool retval = false;
-       int i;
+       size_t i;
        bool old_status;
 
        old_status = domain->online;
@@ -2863,9 +2853,9 @@ do_query:
 }      
 
 /* get lockout policy */
-static NTSTATUS lockout_policy(struct winbindd_domain *domain,
-                              TALLOC_CTX *mem_ctx,
-                              struct samr_DomInfo12 *policy)
+NTSTATUS wb_cache_lockout_policy(struct winbindd_domain *domain,
+                                TALLOC_CTX *mem_ctx,
+                                struct samr_DomInfo12 *policy)
 {
        struct winbind_cache *cache = get_cache(domain);
        struct cache_entry *centry = NULL;
@@ -2923,7 +2913,7 @@ do_query:
                }
        }
        /* and save it */
-       refresh_sequence_number(domain, false);
+       refresh_sequence_number(domain);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -2933,9 +2923,9 @@ do_query:
 }
 
 /* get password policy */
-static NTSTATUS password_policy(struct winbindd_domain *domain,
-                               TALLOC_CTX *mem_ctx,
-                               struct samr_DomInfo1 *policy)
+NTSTATUS wb_cache_password_policy(struct winbindd_domain *domain,
+                                 TALLOC_CTX *mem_ctx,
+                                 struct samr_DomInfo1 *policy)
 {
        struct winbind_cache *cache = get_cache(domain);
        struct cache_entry *centry = NULL;
@@ -2995,7 +2985,7 @@ do_query:
                }
        }
        /* and save it */
-       refresh_sequence_number(domain, false);
+       refresh_sequence_number(domain);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -3025,7 +3015,7 @@ void wcache_invalidate_samlogon(struct winbindd_domain *domain,
         fstring key_str, sid_string;
        struct winbind_cache *cache;
 
-       /* dont clear cached U/SID and UG/SID entries when we want to logon
+       /* don't clear cached U/SID and UG/SID entries when we want to logon
         * offline - gd */
 
        if (lp_winbind_offline_logon()) {
@@ -3108,8 +3098,10 @@ bool wcache_invalidate_cache_noinit(void)
        return true;
 }
 
-bool init_wcache(void)
+static bool init_wcache(void)
 {
+       char *db_path;
+
        if (wcache == NULL) {
                wcache = SMB_XMALLOC_P(struct winbind_cache);
                ZERO_STRUCTP(wcache);
@@ -3118,13 +3110,18 @@ bool init_wcache(void)
        if (wcache->tdb != NULL)
                return true;
 
+       db_path = wcache_path();
+       if (db_path == NULL) {
+               return false;
+       }
+
        /* when working offline we must not clear the cache on restart */
-       wcache->tdb = tdb_open_log(state_path("winbindd_cache.tdb"),
+       wcache->tdb = tdb_open_log(db_path,
                                WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE, 
                                TDB_INCOMPATIBLE_HASH |
                                        (lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
                                O_RDWR|O_CREAT, 0600);
-
+       TALLOC_FREE(db_path);
        if (wcache->tdb == NULL) {
                DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
                return false;
@@ -3142,7 +3139,7 @@ bool init_wcache(void)
 bool initialize_winbindd_cache(void)
 {
        bool cache_bad = true;
-       uint32 vers;
+       uint32_t vers;
 
        if (!init_wcache()) {
                DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
@@ -3156,6 +3153,8 @@ bool initialize_winbindd_cache(void)
        }
 
        if (cache_bad) {
+               char *db_path;
+
                DEBUG(0,("initialize_winbindd_cache: clearing cache "
                        "and re-creating with version number %d\n",
                        WINBINDD_CACHE_VERSION ));
@@ -3163,12 +3162,19 @@ bool initialize_winbindd_cache(void)
                tdb_close(wcache->tdb);
                wcache->tdb = NULL;
 
-               if (unlink(state_path("winbindd_cache.tdb")) == -1) {
+               db_path = wcache_path();
+               if (db_path == NULL) {
+                       return false;
+               }
+
+               if (unlink(db_path) == -1) {
                        DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
-                               state_path("winbindd_cache.tdb"),
+                               db_path,
                                strerror(errno) ));
+                       TALLOC_FREE(db_path);
                        return false;
                }
+               TALLOC_FREE(db_path);
                if (!init_wcache()) {
                        DEBUG(0,("initialize_winbindd_cache: re-initialization "
                                        "init_wcache failed.\n"));
@@ -3178,7 +3184,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_compat(wcache->tdb) ));
+                               tdb_errorstr(wcache->tdb) ));
                        return false;
                }
        }
@@ -3240,11 +3246,36 @@ bool lookup_cached_name(const char *domain_name,
        return NT_STATUS_IS_OK(status);
 }
 
+/*
+ * Cache a name to sid without checking the sequence number.
+ * Used when caching from a trusted PAC.
+ */
+
+void cache_name2sid_trusted(struct winbindd_domain *domain,
+                       const char *domain_name,
+                       const char *name,
+                       enum lsa_SidType type,
+                       const struct dom_sid *sid)
+{
+       /*
+        * Ensure we store the mapping with the
+        * existing sequence number from the cache.
+        */
+       get_cache(domain);
+       (void)fetch_cache_seqnum(domain, time(NULL));
+       wcache_save_name_to_sid(domain,
+                               NT_STATUS_OK,
+                               domain_name,
+                               name,
+                               sid,
+                               type);
+}
+
 void cache_name2sid(struct winbindd_domain *domain, 
                    const char *domain_name, const char *name,
                    enum lsa_SidType type, const struct dom_sid *sid)
 {
-       refresh_sequence_number(domain, false);
+       refresh_sequence_number(domain);
        wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
                                sid, type);
 }
@@ -3279,8 +3310,10 @@ static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
 }
 
 /* flush the cache */
-void wcache_flush_cache(void)
+static void wcache_flush_cache(void)
 {
+       char *db_path;
+
        if (!wcache)
                return;
        if (wcache->tdb) {
@@ -3291,13 +3324,18 @@ void wcache_flush_cache(void)
                return;
        }
 
+       db_path = wcache_path();
+       if (db_path == NULL) {
+               return;
+       }
+
        /* when working offline we must not clear the cache on restart */
-       wcache->tdb = tdb_open_log(state_path("winbindd_cache.tdb"),
-                               WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE, 
+       wcache->tdb = tdb_open_log(db_path,
+                               WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
                                TDB_INCOMPATIBLE_HASH |
                                (lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
                                O_RDWR|O_CREAT, 0600);
-
+       TALLOC_FREE(db_path);
        if (!wcache->tdb) {
                DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
                return;
@@ -3373,7 +3411,7 @@ NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const
        struct winbind_cache *cache = get_cache(domain);
        NTSTATUS status;
        int ret;
-       struct cred_list *cred, *oldest = NULL;
+       struct cred_list *cred, *next, *oldest = NULL;
 
        if (!cache->tdb) {
                return NT_STATUS_INTERNAL_DB_ERROR;
@@ -3407,7 +3445,7 @@ NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const
                TDB_DATA data;
                time_t t;
 
-               data = tdb_fetch_compat(cache->tdb, string_tdb_data(cred->name));
+               data = tdb_fetch(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));
@@ -3442,7 +3480,11 @@ NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const
                status = NT_STATUS_UNSUCCESSFUL;
        }
 done:
-       SAFE_FREE(wcache_cred_list);
+       for (cred = wcache_cred_list; cred; cred = next) {
+               next = cred->next;
+               DLIST_REMOVE(wcache_cred_list, cred);
+               SAFE_FREE(cred);
+       }
        SAFE_FREE(oldest);
 
        return status;
@@ -3525,7 +3567,7 @@ static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA dat
        struct cache_entry *centry;
 
        centry = SMB_XMALLOC_P(struct cache_entry);
-       centry->data = (unsigned char *)memdup(data.dptr, data.dsize);
+       centry->data = (unsigned char *)smb_memdup(data.dptr, data.dsize);
        if (!centry->data) {
                SAFE_FREE(centry);
                return NULL;
@@ -3561,52 +3603,6 @@ static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbu
        return 0;
 }
 
-static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
-                      struct tdb_validation_status *state)
-{
-       struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
-       if (!centry) {
-               return 1;
-       }
-
-       (void)centry_uint32(centry);
-       if (NT_STATUS_IS_OK(centry->status)) {
-               struct dom_sid sid;
-               (void)centry_sid(centry, &sid);
-       }
-
-       centry_free(centry);
-
-       if (!(state->success)) {
-               return 1;
-       }
-       DEBUG(10,("validate_ns: %s ok\n", keystr));
-       return 0;
-}
-
-static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
-                      struct tdb_validation_status *state)
-{
-       struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
-       if (!centry) {
-               return 1;
-       }
-
-       if (NT_STATUS_IS_OK(centry->status)) {
-               (void)centry_uint32(centry);
-               (void)centry_string(centry, mem_ctx);
-               (void)centry_string(centry, mem_ctx);
-       }
-
-       centry_free(centry);
-
-       if (!(state->success)) {
-               return 1;
-       }
-       DEBUG(10,("validate_sn: %s ok\n", keystr));
-       return 0;
-}
-
 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
                      struct tdb_validation_status *state)
 {
@@ -3621,7 +3617,10 @@ static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
        (void)centry_string(centry, mem_ctx);
        (void)centry_string(centry, mem_ctx);
        (void)centry_string(centry, mem_ctx);
+       (void)centry_string(centry, mem_ctx);
        (void)centry_uint32(centry);
+       (void)centry_uint32(centry);
+       (void)centry_string(centry, mem_ctx);
        (void)centry_sid(centry, &sid);
        (void)centry_sid(centry, &sid);
 
@@ -3710,22 +3709,16 @@ static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
                       struct tdb_validation_status *state)
 {
        struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
-       int32 num_entries, i;
+       int32_t num_entries, i;
 
        if (!centry) {
                return 1;
        }
 
-       num_entries = (int32)centry_uint32(centry);
+       num_entries = (int32_t)centry_uint32(centry);
 
        for (i=0; i< num_entries; i++) {
-               struct dom_sid sid;
-               (void)centry_string(centry, mem_ctx);
-               (void)centry_string(centry, mem_ctx);
-               (void)centry_string(centry, mem_ctx);
-               (void)centry_string(centry, mem_ctx);
-               (void)centry_sid(centry, &sid);
-               (void)centry_sid(centry, &sid);
+               (void)centry_uint32(centry);
        }
 
        centry_free(centry);
@@ -3741,7 +3734,7 @@ static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
                       struct tdb_validation_status *state)
 {
        struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
-       int32 num_entries, i;
+       int32_t num_entries, i;
 
        if (!centry) {
                return 1;
@@ -3768,7 +3761,7 @@ static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
                       struct tdb_validation_status *state)
 {
        struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
-       int32 num_groups, i;
+       int32_t num_groups, i;
 
        if (!centry) {
                return 1;
@@ -3794,7 +3787,7 @@ static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
                       struct tdb_validation_status *state)
 {
        struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
-       int32 num_aliases, i;
+       int32_t num_aliases, i;
 
        if (!centry) {
                return 1;
@@ -3819,7 +3812,7 @@ static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
                       struct tdb_validation_status *state)
 {
        struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
-       int32 num_names, i;
+       int32_t num_names, i;
 
        if (!centry) {
                return 1;
@@ -3875,29 +3868,6 @@ static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
        return 0;
 }
 
-static int validate_pwinfo(TALLOC_CTX *mem_ctx, const char *keystr,
-                          TDB_DATA dbuf, struct tdb_validation_status *state)
-{
-       struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
-
-       if (!centry) {
-               return 1;
-       }
-
-       (void)centry_string(centry, mem_ctx);
-       (void)centry_string(centry, mem_ctx);
-       (void)centry_string(centry, mem_ctx);
-       (void)centry_uint32(centry);
-
-       centry_free(centry);
-
-       if (!(state->success)) {
-               return 1;
-       }
-       DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
-       return 0;
-}
-
 static int validate_nss_an(TALLOC_CTX *mem_ctx, const char *keystr,
                           TDB_DATA dbuf,
                           struct tdb_validation_status *state)
@@ -3936,7 +3906,7 @@ static int validate_nss_na(TALLOC_CTX *mem_ctx, const char *keystr,
        if (!(state->success)) {
                return 1;
        }
-       DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
+       DBG_DEBUG("%s ok\n", keystr);
        return 0;
 }
 
@@ -4007,8 +3977,6 @@ struct key_val_struct {
        int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
 } key_val[] = {
        {"SEQNUM/", validate_seqnum},
-       {"NS/", validate_ns},
-       {"SN/", validate_sn},
        {"U/", validate_u},
        {"LOC_POL/", validate_loc_pol},
        {"PWD_POL/", validate_pwd_pol},
@@ -4020,7 +3988,6 @@ struct key_val_struct {
        {"GM/", validate_gm},
        {"DR/", validate_dr},
        {"DE/", validate_de},
-       {"NSS/PWINFO/", validate_pwinfo},
        {"TRUSTDOMCACHE/", validate_trustdomcache},
        {"NSS/NA/", validate_nss_na},
        {"NSS/AN/", validate_nss_an},
@@ -4042,7 +4009,8 @@ static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_D
        struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
 
        /* Paranoia check. */
-       if (strncmp("UA/", (const char *)kbuf.dptr, 3) == 0) {
+       if (strncmp("UA/", (const char *)kbuf.dptr, 3) == 0 ||
+           strncmp("NDR/", (const char *)kbuf.dptr, 4) == 0) {
                max_key_len = 1024 * 1024;
        }
        if (kbuf.dsize > max_key_len) {
@@ -4083,9 +4051,9 @@ static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_D
        }
 
        DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
-       dump_data(0, (uint8 *)kbuf.dptr, kbuf.dsize);
+       dump_data(0, (uint8_t *)kbuf.dptr, kbuf.dsize);
        DEBUG(0,("data :\n"));
-       dump_data(0, (uint8 *)dbuf.dptr, dbuf.dsize);
+       dump_data(0, (uint8_t *)dbuf.dptr, dbuf.dsize);
        v_state->unknown_key = true;
        v_state->success = false;
        return 1; /* terminate. */
@@ -4170,7 +4138,7 @@ static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT *tdb)
 int winbindd_validate_cache(void)
 {
        int ret = -1;
-       const char *tdb_path = state_path("winbindd_cache.tdb");
+       char *tdb_path = NULL;
        TDB_CONTEXT *tdb = NULL;
        uint32_t vers_id;
        bool ok;
@@ -4178,13 +4146,18 @@ int winbindd_validate_cache(void)
        DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
        smb_panic_fn = validate_panic;
 
-       tdb = tdb_open_log(tdb_path, 
+       tdb_path = wcache_path();
+       if (tdb_path == NULL) {
+               goto done;
+       }
+
+       tdb = tdb_open_log(tdb_path,
                           WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
                           TDB_INCOMPATIBLE_HASH |
-                          ( lp_winbind_offline_logon() 
-                            ? TDB_DEFAULT 
+                          ( lp_winbind_offline_logon()
+                            ? TDB_DEFAULT
                             : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
-                          O_RDWR|O_CREAT, 
+                          O_RDWR|O_CREAT,
                           0600);
        if (!tdb) {
                DEBUG(0, ("winbindd_validate_cache: "
@@ -4226,6 +4199,7 @@ int winbindd_validate_cache(void)
        }
 
 done:
+       TALLOC_FREE(tdb_path);
        DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
        smb_panic_fn = smb_panic;
        return ret;
@@ -4238,11 +4212,15 @@ done:
 int winbindd_validate_cache_nobackup(void)
 {
        int ret = -1;
-       const char *tdb_path = state_path("winbindd_cache.tdb");
+       char *tdb_path;
 
        DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
        smb_panic_fn = validate_panic;
 
+       tdb_path = wcache_path();
+       if (tdb_path == NULL) {
+               goto err_panic_restore;
+       }
 
        if (wcache == NULL || wcache->tdb == NULL) {
                ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
@@ -4255,6 +4233,8 @@ int winbindd_validate_cache_nobackup(void)
                           "successful.\n"));
        }
 
+       TALLOC_FREE(tdb_path);
+err_panic_restore:
        DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
                   "function\n"));
        smb_panic_fn = smb_panic;
@@ -4283,8 +4263,7 @@ static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
                                       size_t *num_domains )
 {
        struct winbindd_tdc_domain *list = NULL;
-       size_t idx;
-       int i;
+       size_t i, idx;
        bool set_only = false;
 
        /* don't allow duplicates */
@@ -4320,8 +4299,16 @@ static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
        if ( !list )
                return false;
 
-       list[idx].domain_name = talloc_strdup( list, new_dom->name );
-       list[idx].dns_name = talloc_strdup( list, new_dom->alt_name );
+       list[idx].domain_name = talloc_strdup(list, new_dom->name);
+       if (list[idx].domain_name == NULL) {
+               return false;
+       }
+       if (new_dom->alt_name != NULL) {
+               list[idx].dns_name = talloc_strdup(list, new_dom->alt_name);
+               if (list[idx].dns_name == NULL) {
+                       return false;
+               }
+       }
 
        if ( !is_null_sid( &new_dom->sid ) ) {
                sid_copy( &list[idx].sid, &new_dom->sid );
@@ -4377,7 +4364,7 @@ static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
         unsigned char *buffer = NULL;
        int len = 0;
        int buflen = 0;
-       int i = 0;
+       size_t i = 0;
 
        DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
                  (int)num_domains));
@@ -4404,7 +4391,7 @@ static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
 
                len += tdb_pack( buffer+len, buflen-len, "fffddd",
                                 domains[i].domain_name,
-                                domains[i].dns_name,
+                                domains[i].dns_name ? domains[i].dns_name : "",
                                 sid_to_fstring(tmp, &domains[i].sid),
                                 domains[i].trust_flags,
                                 domains[i].trust_attribs,
@@ -4435,7 +4422,7 @@ static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
                                  struct winbindd_tdc_domain **domains )
 {
        fstring domain_name, dns_name, sid_string;      
-       uint32 type, attribs, flags;
+       uint32_t type, attribs, flags;
        int num_domains;
        int len = 0;
        int i;
@@ -4455,7 +4442,9 @@ static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
        }
 
        for ( i=0; i<num_domains; i++ ) {
-               len += tdb_unpack( buf+len, buflen-len, "fffddd",
+               int this_len;
+
+               this_len = tdb_unpack( buf+len, buflen-len, "fffddd",
                                   domain_name,
                                   dns_name,
                                   sid_string,
@@ -4463,11 +4452,12 @@ static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
                                   &attribs,
                                   &type );
 
-               if ( len == -1 ) {
+               if ( this_len == -1 ) {
                        DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
                        TALLOC_FREE( list );                    
                        return 0;
                }
+               len += this_len;
 
                DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
                          "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
@@ -4475,7 +4465,10 @@ static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
                          flags, attribs, type));
 
                list[i].domain_name = talloc_strdup( list, domain_name );
-               list[i].dns_name = talloc_strdup( list, dns_name );
+               list[i].dns_name = NULL;
+               if (dns_name[0] != '\0') {
+                       list[i].dns_name = talloc_strdup(list, dns_name);
+               }
                if ( !string_to_sid( &(list[i].sid), sid_string ) ) {                   
                        DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
                                  domain_name));
@@ -4539,7 +4532,7 @@ bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_do
        if ( !key.dptr )
                return false;
 
-       data = tdb_fetch_compat( wcache->tdb, key );
+       data = tdb_fetch( wcache->tdb, key );
 
        SAFE_FREE( key.dptr );
 
@@ -4602,6 +4595,38 @@ bool wcache_tdc_add_domain( struct winbindd_domain *domain )
        return ret;     
 }
 
+static struct winbindd_tdc_domain *wcache_tdc_dup_domain(
+       TALLOC_CTX *mem_ctx, const struct winbindd_tdc_domain *src)
+{
+       struct winbindd_tdc_domain *dst;
+
+       dst = talloc(mem_ctx, struct winbindd_tdc_domain);
+       if (dst == NULL) {
+               goto fail;
+       }
+       dst->domain_name = talloc_strdup(dst, src->domain_name);
+       if (dst->domain_name == NULL) {
+               goto fail;
+       }
+
+       dst->dns_name = NULL;
+       if (src->dns_name != NULL) {
+               dst->dns_name = talloc_strdup(dst, src->dns_name);
+               if (dst->dns_name == NULL) {
+                       goto fail;
+               }
+       }
+
+       sid_copy(&dst->sid, &src->sid);
+       dst->trust_flags = src->trust_flags;
+       dst->trust_type = src->trust_type;
+       dst->trust_attribs = src->trust_attribs;
+       return dst;
+fail:
+       TALLOC_FREE(dst);
+       return NULL;
+}
+
 /*********************************************************************
  ********************************************************************/
 
@@ -4609,7 +4634,7 @@ struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const cha
 {
        struct winbindd_tdc_domain *dom_list = NULL;
        size_t num_domains = 0;
-       int i;
+       size_t i;
        struct winbindd_tdc_domain *d = NULL;   
 
        DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
@@ -4629,17 +4654,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( 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;
-
+                       d = wcache_tdc_dup_domain(ctx, &dom_list[i]);
                        break;
                }
        }
@@ -4649,59 +4664,6 @@ 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 NULL;
-       }
-
-       /* 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;
-}
-
-
 /*********************************************************************
  ********************************************************************/
 
@@ -4715,118 +4677,7 @@ void wcache_tdc_clear( void )
        return; 
 }
 
-
-/*********************************************************************
- ********************************************************************/
-
-static void wcache_save_user_pwinfo(struct winbindd_domain *domain, 
-                                   NTSTATUS status,
-                                   const struct dom_sid *user_sid,
-                                   const char *homedir,
-                                   const char *shell,
-                                   const char *gecos,
-                                   uint32 gid)
-{
-       struct cache_entry *centry;
-       fstring tmp;
-
-       if ( (centry = centry_start(domain, status)) == NULL )
-               return;
-
-       centry_put_string( centry, homedir );
-       centry_put_string( centry, shell );
-       centry_put_string( centry, gecos );
-       centry_put_uint32( centry, gid );
-
-       centry_end(centry, "NSS/PWINFO/%s", sid_to_fstring(tmp, user_sid) );
-
-       DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid) ));
-
-       centry_free(centry);
-}
-
-#ifdef HAVE_ADS
-
-NTSTATUS nss_get_info_cached( struct winbindd_domain *domain, 
-                             const struct dom_sid *user_sid,
-                             TALLOC_CTX *ctx,
-                             const char **homedir, const char **shell,
-                             const char **gecos, gid_t *p_gid)
-{
-       struct winbind_cache *cache = get_cache(domain);
-       struct cache_entry *centry = NULL;
-       NTSTATUS nt_status;
-       fstring tmp;
-
-       if (!cache->tdb)
-               goto do_query;
-
-       centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s",
-                             sid_to_fstring(tmp, user_sid));
-
-       if (!centry)
-               goto do_query;
-
-       *homedir = centry_string( centry, ctx );
-       *shell   = centry_string( centry, ctx );
-       *gecos   = centry_string( centry, ctx );
-       *p_gid   = centry_uint32( centry );     
-
-       centry_free(centry);
-
-       DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
-                 sid_string_dbg(user_sid)));
-
-       return NT_STATUS_OK;
-
-do_query:
-
-       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)));
-
-       if ( NT_STATUS_IS_OK(nt_status) ) {
-               DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir));
-                DEBUGADD(10, ("\tshell = '%s'\n", *shell));
-                DEBUGADD(10, ("\tgecos = '%s'\n", *gecos));
-                DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid));
-
-               wcache_save_user_pwinfo( domain, nt_status, user_sid,
-                                        *homedir, *shell, *gecos, *p_gid );
-       }       
-
-       if ( NT_STATUS_EQUAL( nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
-               DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
-                        domain->name ));
-               set_domain_offline( domain );
-       }
-
-       return nt_status;       
-}
-
-#endif
-
-/* the cache backend methods are exposed via this structure */
-struct winbindd_methods cache_methods = {
-       true,
-       query_user_list,
-       enum_dom_groups,
-       enum_local_groups,
-       name_to_sid,
-       sid_to_name,
-       rids_to_names,
-       query_user,
-       lookup_usergroups,
-       lookup_useraliases,
-       lookup_groupmem,
-       sequence_number,
-       lockout_policy,
-       password_policy,
-       trusted_domains
-};
-
-static bool wcache_ndr_key(TALLOC_CTX *mem_ctx, char *domain_name,
+static bool wcache_ndr_key(TALLOC_CTX *mem_ctx, const char *domain_name,
                           uint32_t opnum, const DATA_BLOB *req,
                           TDB_DATA *pkey)
 {
@@ -4884,7 +4735,7 @@ 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_compat(wcache->tdb, key);
+       data = tdb_fetch(wcache->tdb, key);
        TALLOC_FREE(key.dptr);
 
        if (data.dptr == NULL) {
@@ -4894,7 +4745,7 @@ bool wcache_fetch_ndr(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
                goto fail;
        }
 
-       if (!is_domain_offline(domain)) {
+       if (is_domain_online(domain)) {
                uint32_t entry_seqnum, dom_seqnum, last_check;
                uint64_t entry_timeout;
 
@@ -4909,7 +4760,7 @@ bool wcache_fetch_ndr(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
                        goto fail;
                }
                entry_timeout = BVAL(data.dptr, 4);
-               if (time(NULL) > entry_timeout) {
+               if (time(NULL) > (time_t)entry_timeout) {
                        DEBUG(10, ("Entry has timed out\n"));
                        goto fail;
                }