Revert "Convert idmap_cache to gencache"
authorVolker Lendecke <vl@samba.org>
Fri, 11 Jul 2008 15:42:58 +0000 (17:42 +0200)
committerVolker Lendecke <vl@samba.org>
Fri, 11 Jul 2008 15:53:24 +0000 (17:53 +0200)
This reverts commit 0bf0434f22b0ea46fda3ccc4dd612adbc88dd4f2.
(This used to be commit cc536677735ecc318cbd2176ce53b124f44d85a0)

source3/include/proto.h
source3/winbindd/idmap.c
source3/winbindd/idmap_cache.c
source3/winbindd/winbindd.h

index 43420985a3a1625d749b178de2051140861d13e0..278a42a9742aa9f6a026498469c5237db7a91421 100644 (file)
@@ -10494,13 +10494,12 @@ char *idmap_fetch_secret(const char *backend, bool alloc,
 
 /* The following definitions come from winbindd/idmap_cache.c  */
 
-NTSTATUS idmap_cache_set(const struct id_map *id);
-NTSTATUS idmap_cache_set_negative_sid(const struct id_map *id);
-NTSTATUS idmap_cache_set_negative_id(const struct id_map *id);
-bool idmap_cache_map_sid(const struct dom_sid *sid, struct unixid *xid,
-                        bool *mapped, bool *expired);
-bool idmap_cache_map_id(const struct unixid *xid, struct dom_sid *psid,
-                       bool *mapped, bool *expired);
+struct idmap_cache_ctx *idmap_cache_init(TALLOC_CTX *memctx);
+NTSTATUS idmap_cache_set(struct idmap_cache_ctx *cache, const struct id_map *id);
+NTSTATUS idmap_cache_set_negative_sid(struct idmap_cache_ctx *cache, const struct id_map *id);
+NTSTATUS idmap_cache_set_negative_id(struct idmap_cache_ctx *cache, const struct id_map *id);
+NTSTATUS idmap_cache_map_sid(struct idmap_cache_ctx *cache, struct id_map *id);
+NTSTATUS idmap_cache_map_id(struct idmap_cache_ctx *cache, struct id_map *id);
 
 /* The following definitions come from winbindd/idmap_nss.c  */
 
index db17245b9203db0e5e62417ee22b8120149e0896..32fc3dc9751222e171e7120879100f131c8f6f29 100644 (file)
@@ -40,6 +40,8 @@ struct idmap_alloc_backend {
        struct idmap_alloc_backend *prev, *next;
 };
 
+struct idmap_cache_ctx;
+
 struct idmap_alloc_context {
        const char *params;
        struct idmap_alloc_methods *methods;
@@ -47,6 +49,7 @@ struct idmap_alloc_context {
 };
 
 static TALLOC_CTX *idmap_ctx = NULL;
+static struct idmap_cache_ctx *idmap_cache;
 
 static struct idmap_backend *backends = NULL;
 static struct idmap_domain **idmap_domains = NULL;
@@ -243,6 +246,7 @@ NTSTATUS idmap_close(void)
        /* this talloc_free call will fire the talloc destructors
         * that will free all active backends resources */
        TALLOC_FREE(idmap_ctx);
+       idmap_cache = NULL;
        idmap_domains = NULL;
        backends = NULL;
 
@@ -265,6 +269,10 @@ NTSTATUS idmap_init_cache(void)
                return NT_STATUS_NO_MEMORY;
        }
 
+       if ( (idmap_cache = idmap_cache_init(idmap_ctx)) == NULL ) {
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
        return NT_STATUS_OK;
 }
 
@@ -1308,28 +1316,15 @@ NTSTATUS idmap_unixids_to_sids(struct id_map **ids)
 
        for (i = 0; ids[i]; i++) {
 
-               bool found, mapped, expired;
-
                if ( ! ids[i]->sid) {
                        DEBUG(1, ("invalid null SID in id_map array"));
                        talloc_free(ctx);
                        return NT_STATUS_INVALID_PARAMETER;
                }
 
-               ids[i]->status = ID_UNKNOWN;
-
-               found = idmap_cache_map_id(&ids[i]->xid, ids[i]->sid,
-                                          &mapped, &expired);
-
-               if (found) {
-                       ids[i]->status = mapped ? ID_MAPPED : ID_UNMAPPED;
-               }
-
-               if (!found || (expired && IS_DOMAIN_ONLINE(our_domain))) {
+               ret = idmap_cache_map_id(idmap_cache, ids[i]);
 
-                       /*
-                        * Need to ask the backend
-                        */
+               if ( ! NT_STATUS_IS_OK(ret)) {
 
                        if ( ! bids) {
                                /* alloc space for ids to be resolved by
@@ -1381,7 +1376,7 @@ NTSTATUS idmap_unixids_to_sids(struct id_map **ids)
                /* update the cache */
                for (i = 0; i < bi; i++) {
                        if (bids[i]->status == ID_MAPPED) {
-                               ret = idmap_cache_set(bids[i]);
+                               ret = idmap_cache_set(idmap_cache, bids[i]);
                        } else if (bids[i]->status == ID_EXPIRED) {
                                /* the cache returned an expired entry and the
                                 * backend was not able to clear the situation
@@ -1396,7 +1391,8 @@ NTSTATUS idmap_unixids_to_sids(struct id_map **ids)
                                 * settle down. */
                                bids[i]->status = ID_UNMAPPED;
                        } else { /* unmapped */
-                               ret = idmap_cache_set_negative_id(bids[i]);
+                               ret = idmap_cache_set_negative_id(idmap_cache,
+                                                                 bids[i]);
                        }
                        IDMAP_CHECK_RET(ret);
                }
@@ -1438,28 +1434,15 @@ NTSTATUS idmap_sids_to_unixids(struct id_map **ids)
 
        for (i = 0; ids[i]; i++) {
 
-               bool found, mapped, expired;
-
                if ( ! ids[i]->sid) {
                        DEBUG(1, ("invalid null SID in id_map array\n"));
                        talloc_free(ctx);
                        return NT_STATUS_INVALID_PARAMETER;
                }
 
-               ids[i]->status = ID_UNKNOWN;
-
-               found = idmap_cache_map_sid(ids[i]->sid, &ids[i]->xid,
-                                           &mapped, &expired);
-
-               if (found) {
-                       ids[i]->status = mapped ? ID_MAPPED : ID_UNMAPPED;
-               }
-
-               if (!found || (expired && IS_DOMAIN_ONLINE(our_domain))) {
+               ret = idmap_cache_map_sid(idmap_cache, ids[i]);
 
-                       /*
-                        * Need to ask the backends
-                        */
+               if ( ! NT_STATUS_IS_OK(ret)) {
 
                        if ( ! bids) {
                                /* alloc space for ids to be resolved
@@ -1511,7 +1494,7 @@ NTSTATUS idmap_sids_to_unixids(struct id_map **ids)
                /* update the cache */
                for (i = 0; bids[i]; i++) {
                        if (bids[i]->status == ID_MAPPED) {
-                               ret = idmap_cache_set(bids[i]);
+                               ret = idmap_cache_set(idmap_cache, bids[i]);
                        } else if (bids[i]->status == ID_EXPIRED) {
                                /* the cache returned an expired entry and the
                                 * backend was not able to clear the situation
@@ -1526,7 +1509,8 @@ NTSTATUS idmap_sids_to_unixids(struct id_map **ids)
                                 * settle down. */
                                bids[i]->status = ID_UNMAPPED;
                        } else { /* unmapped */
-                               ret = idmap_cache_set_negative_sid(bids[i]);
+                               ret = idmap_cache_set_negative_sid(idmap_cache,
+                                                                  bids[i]);
                        }
                        IDMAP_CHECK_RET(ret);
                }
@@ -1566,7 +1550,7 @@ NTSTATUS idmap_set_mapping(const struct id_map *id)
        IDMAP_CHECK_RET(ret);
 
        /* set the mapping in the cache */
-       ret = idmap_cache_set(id);
+       ret = idmap_cache_set(idmap_cache, id);
        IDMAP_CHECK_RET(ret);
 
 done:
index 191cadb536022eab4dc65156a4002df39587c54e..8bf797f95275be906578c95664baaf6c2f31f18a 100644 (file)
@@ -1,8 +1,9 @@
-/*
+/* 
    Unix SMB/CIFS implementation.
    ID Mapping Cache
 
-   Copyright (C) Volker Lendecke       2008
+   based on gencache
+
    Copyright (C) Simo Sorce            2006
    Copyright (C) Rafal Szczesniak      2002
 
 #include "includes.h"
 #include "winbindd.h"
 
+#define TIMEOUT_LEN 12
+#define IDMAP_CACHE_DATA_FMT   "%12u/%s"
+
+struct idmap_cache_ctx {
+       TDB_CONTEXT *tdb;
+};
+
+static int idmap_cache_destructor(struct idmap_cache_ctx *cache)
+{
+       int ret = 0;
+
+       if (cache && cache->tdb) {
+               ret = tdb_close(cache->tdb);
+               cache->tdb = NULL;
+       }
+
+       return ret;
+}
+
+struct idmap_cache_ctx *idmap_cache_init(TALLOC_CTX *memctx)
+{
+       struct idmap_cache_ctx *cache;
+       char* cache_fname = NULL;
+
+       cache = talloc(memctx, struct idmap_cache_ctx);
+       if ( ! cache) {
+               DEBUG(0, ("Out of memory!\n"));
+               return NULL;
+       }
+
+       cache_fname = lock_path("idmap_cache.tdb");
+
+       DEBUG(10, ("Opening cache file at %s\n", cache_fname));
+
+       cache->tdb = tdb_open_log(cache_fname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
+
+       if (!cache->tdb) {
+               DEBUG(5, ("Attempt to open %s has failed.\n", cache_fname));
+               return NULL;
+       }
+
+       talloc_set_destructor(cache, idmap_cache_destructor);
+
+       return cache;
+}
+
 static char *idmap_cache_sidkey(TALLOC_CTX *ctx, const DOM_SID *sid)
 {
        fstring sidstr;
@@ -30,19 +77,21 @@ static char *idmap_cache_sidkey(TALLOC_CTX *ctx, const DOM_SID *sid)
                               sid_to_fstring(sidstr, sid));
 }
 
-static char *idmap_cache_idkey(TALLOC_CTX *ctx, const struct unixid *xid)
+static char *idmap_cache_idkey(TALLOC_CTX *ctx, const struct id_map *id)
 {
        return talloc_asprintf(ctx, "IDMAP/%s/%lu",
-                              (xid->type==ID_TYPE_UID)?"UID":"GID",
-                              (unsigned long)xid->id);
+                              (id->xid.type==ID_TYPE_UID)?"UID":"GID",
+                              (unsigned long)id->xid.id);
 }
 
-NTSTATUS idmap_cache_set(const struct id_map *id)
+NTSTATUS idmap_cache_set(struct idmap_cache_ctx *cache, const struct id_map *id)
 {
        NTSTATUS ret;
        time_t timeout = time(NULL) + lp_idmap_cache_time();
+       TDB_DATA databuf;
        char *sidkey;
        char *idkey;
+       char *valstr;
 
        /* Don't cache lookups in the S-1-22-{1,2} domain */
 
@@ -51,179 +100,415 @@ NTSTATUS idmap_cache_set(const struct id_map *id)
                return NT_STATUS_OK;
        }
 
-       sidkey = idmap_cache_sidkey(talloc_tos(), id->sid);
+       sidkey = idmap_cache_sidkey(cache, id->sid);
        if (sidkey == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
 
        /* use sidkey as the local memory ctx */
-       idkey = idmap_cache_idkey(sidkey, &id->xid);
+       idkey = idmap_cache_idkey(sidkey, id);
        if (idkey == NULL) {
                ret = NT_STATUS_NO_MEMORY;
                goto done;
        }
 
-       if (!gencache_set(idkey, sidkey, timeout)
-           || !gencache_set(sidkey, idkey, timeout)) {
+       /* save SID -> ID */
+
+       /* use sidkey as the local memory ctx */
+       valstr = talloc_asprintf(sidkey, IDMAP_CACHE_DATA_FMT, (int)timeout, idkey);
+       if (!valstr) {
+               DEBUG(0, ("Out of memory!\n"));
+               ret = NT_STATUS_NO_MEMORY;
+               goto done;
+       }
+
+       databuf = string_term_tdb_data(valstr);
+       DEBUG(10, ("Adding cache entry with key = %s; value = %s and timeout ="
+                  " %s (%d seconds %s)\n", sidkey, valstr , ctime(&timeout),
+                  (int)(timeout - time(NULL)), 
+                  timeout > time(NULL) ? "ahead" : "in the past"));
+
+       if (tdb_store_bystring(cache->tdb, sidkey, databuf, TDB_REPLACE) != 0) {
+               DEBUG(3, ("Failed to store cache entry!\n"));
+               ret = NT_STATUS_UNSUCCESSFUL;
+               goto done;
+       }
+
+       /* save ID -> SID */
+
+       /* use sidkey as the local memory ctx */
+       valstr = talloc_asprintf(sidkey, IDMAP_CACHE_DATA_FMT, (int)timeout, sidkey);
+       if (!valstr) {
+               DEBUG(0, ("Out of memory!\n"));
+               ret = NT_STATUS_NO_MEMORY;
+               goto done;
+       }
+
+       databuf = string_term_tdb_data(valstr);
+       DEBUG(10, ("Adding cache entry with key = %s; value = %s and timeout ="
+                  " %s (%d seconds %s)\n", idkey, valstr, ctime(&timeout),
+                  (int)(timeout - time(NULL)), 
+                  timeout > time(NULL) ? "ahead" : "in the past"));
+
+       if (tdb_store_bystring(cache->tdb, idkey, databuf, TDB_REPLACE) != 0) {
                DEBUG(3, ("Failed to store cache entry!\n"));
-               ret = NT_STATUS_ACCESS_DENIED;
+               ret = NT_STATUS_UNSUCCESSFUL;
                goto done;
        }
 
        ret = NT_STATUS_OK;
 
 done:
-       TALLOC_FREE(sidkey);
+       talloc_free(sidkey);
        return ret;
 }
 
-NTSTATUS idmap_cache_set_negative_sid(const struct id_map *id)
+NTSTATUS idmap_cache_set_negative_sid(struct idmap_cache_ctx *cache, const struct id_map *id)
 {
        NTSTATUS ret = NT_STATUS_OK;
+       time_t timeout = time(NULL) + lp_idmap_negative_cache_time();
+       TDB_DATA databuf;
        char *sidkey;
+       char *valstr;
 
-       sidkey = idmap_cache_sidkey(talloc_tos(), id->sid);
+       sidkey = idmap_cache_sidkey(cache, id->sid);
        if (sidkey == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
 
-       if (!gencache_set(sidkey, "IDMAP/NEGATIVE",
-                         time(NULL) + lp_idmap_negative_cache_time())) {
+       /* use sidkey as the local memory ctx */
+       valstr = talloc_asprintf(sidkey, IDMAP_CACHE_DATA_FMT, (int)timeout, "IDMAP/NEGATIVE");
+       if (!valstr) {
+               DEBUG(0, ("Out of memory!\n"));
+               ret = NT_STATUS_NO_MEMORY;
+               goto done;
+       }
+
+       databuf = string_term_tdb_data(valstr);
+       DEBUG(10, ("Adding cache entry with key = %s; value = %s and timeout ="
+                  " %s (%d seconds %s)\n", sidkey, valstr, ctime(&timeout),
+                  (int)(timeout - time(NULL)), 
+                  timeout > time(NULL) ? "ahead" : "in the past"));
+
+       if (tdb_store_bystring(cache->tdb, sidkey, databuf, TDB_REPLACE) != 0) {
                DEBUG(3, ("Failed to store cache entry!\n"));
-               ret = NT_STATUS_ACCESS_DENIED;
+               ret = NT_STATUS_UNSUCCESSFUL;
                goto done;
        }
 
 done:
-       TALLOC_FREE(sidkey);
+       talloc_free(sidkey);
        return ret;
 }
 
-NTSTATUS idmap_cache_set_negative_id(const struct id_map *id)
+NTSTATUS idmap_cache_set_negative_id(struct idmap_cache_ctx *cache, const struct id_map *id)
 {
        NTSTATUS ret = NT_STATUS_OK;
+       time_t timeout = time(NULL) + lp_idmap_negative_cache_time();
+       TDB_DATA databuf;
        char *idkey;
+       char *valstr;
 
-       idkey = idmap_cache_idkey(talloc_tos(), &id->xid);
+       idkey = idmap_cache_idkey(cache, id);
        if (idkey == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
 
-       if (!gencache_set(idkey, "IDMAP/NEGATIVE",
-                         time(NULL) + lp_idmap_negative_cache_time())) {
+       /* use idkey as the local memory ctx */
+       valstr = talloc_asprintf(idkey, IDMAP_CACHE_DATA_FMT, (int)timeout, "IDMAP/NEGATIVE");
+       if (!valstr) {
+               DEBUG(0, ("Out of memory!\n"));
+               ret = NT_STATUS_NO_MEMORY;
+               goto done;
+       }
+
+       databuf = string_term_tdb_data(valstr);
+       DEBUG(10, ("Adding cache entry with key = %s; value = %s and timeout ="
+                  " %s (%d seconds %s)\n", idkey, valstr, ctime(&timeout),
+                  (int)(timeout - time(NULL)), 
+                  timeout > time(NULL) ? "ahead" : "in the past"));
+
+       if (tdb_store_bystring(cache->tdb, idkey, databuf, TDB_REPLACE) != 0) {
                DEBUG(3, ("Failed to store cache entry!\n"));
-               ret = NT_STATUS_ACCESS_DENIED;
+               ret = NT_STATUS_UNSUCCESSFUL;
                goto done;
        }
 
 done:
-       TALLOC_FREE(idkey);
+       talloc_free(idkey);
        return ret;
 }
 
-/*
- * search the cache for the SID an return a mapping if found
+static NTSTATUS idmap_cache_fill_map(struct id_map *id, const char *value)
+{
+       char *rem;
+
+       /* see if it is a sid */
+       if ( ! strncmp("IDMAP/SID/", value, 10)) {
+
+               if ( ! string_to_sid(id->sid, &value[10])) {
+                       goto failed;
+               }
+
+               id->status = ID_MAPPED;
+
+               return NT_STATUS_OK;
+       }
+
+       /* not a SID see if it is an UID or a GID */
+       if ( ! strncmp("IDMAP/UID/", value, 10)) {
+
+               /* a uid */
+               id->xid.type = ID_TYPE_UID;
+
+       } else if ( ! strncmp("IDMAP/GID/", value, 10)) {
+
+               /* a gid */
+               id->xid.type = ID_TYPE_GID;
+
+       } else {
+
+               /* a completely bogus value bail out */
+               goto failed;
+       }
+
+       id->xid.id = strtol(&value[10], &rem, 0);
+       if (*rem != '\0') {
+               goto failed;
+       }
+
+       id->status = ID_MAPPED;
+
+       return NT_STATUS_OK;
+
+failed:
+       DEBUG(1, ("invalid value: %s\n", value));
+       id->status = ID_UNKNOWN;
+       return NT_STATUS_INTERNAL_DB_CORRUPTION;
+}
+
+/* search the cache for the SID an return a mapping if found *
+ *
+ * 4 cases are possible
+ *
+ * 1 map found
+ *     in this case id->status = ID_MAPPED and NT_STATUS_OK is returned
+ * 2 map not found
+ *     in this case id->status = ID_UNKNOWN and NT_STATUS_NONE_MAPPED is returned
+ * 3 negative cache found
+ *     in this case id->status = ID_UNMAPPED and NT_STATUS_OK is returned
+ * 4 map found but timer expired
+ *      in this case id->status = ID_EXPIRED and NT_STATUS_SYNCHRONIZATION_REQUIRED
+ *      is returned. In this case revalidation of the cache is needed.
  */
 
-bool idmap_cache_map_sid(const struct dom_sid *sid, struct unixid *xid,
-                        bool *mapped, bool *expired)
+NTSTATUS idmap_cache_map_sid(struct idmap_cache_ctx *cache, struct id_map *id)
 {
-       bool ret = false;
-       time_t timeout;
+       NTSTATUS ret = NT_STATUS_OK;
+       TDB_DATA databuf;
+       time_t t;
        char *sidkey;
-       char *value;
-       char *rem;
+       char *endptr;
+       struct winbindd_domain *our_domain = find_our_domain(); 
+       time_t now = time(NULL);        
+
+       /* make sure it is marked as not mapped by default */
+       id->status = ID_UNKNOWN;
 
-       sidkey = idmap_cache_sidkey(talloc_tos(), sid);
+       sidkey = idmap_cache_sidkey(cache, id->sid);
        if (sidkey == NULL) {
-               DEBUG(0, ("idmap_cache_sidkey failed\n"));
-               return false;
+               return NT_STATUS_NO_MEMORY;
        }
 
-       if (!gencache_get(sidkey, &value, &timeout)) {
-               TALLOC_FREE(sidkey);
-               return false;
+       databuf = tdb_fetch_bystring(cache->tdb, sidkey);
+
+       if (databuf.dptr == NULL) {
+               DEBUG(10, ("Cache entry with key = %s couldn't be found\n", sidkey));
+               ret = NT_STATUS_NONE_MAPPED;
+               goto done;
        }
 
-       if (strcmp(value, "IDMAP/NEGATIVE") == 0) {
-               *mapped = false;
+       t = strtol((const char *)databuf.dptr, &endptr, 10);
+
+       if ((endptr == NULL) || (*endptr != '/')) {
+               DEBUG(2, ("Invalid idmap cache data format: %s\n",
+                         (const char *)databuf.dptr));
+               /* remove the entry */
+               tdb_delete_bystring(cache->tdb, sidkey);
+               ret = NT_STATUS_NONE_MAPPED;
+               goto done;
        }
-       else if (strncmp(value, "IDMAP/UID/", 10) == 0) {
-               *mapped = true;
-               xid->type = ID_TYPE_UID;
-               xid->id = strtol(&value[10], &rem, 10);
-               if (*rem != '\0') {
-                       goto fail;
+
+       /* check it is not negative */
+       if (strcmp("IDMAP/NEGATIVE", endptr+1) != 0) {
+
+               DEBUG(10, ("Returning %s cache entry: key = %s, value = %s, "
+                          "timeout = %s", t > now ? "valid" :
+                          "expired", sidkey, endptr+1, ctime(&t)));
+
+               /* this call if successful will also mark the entry as mapped */
+               ret = idmap_cache_fill_map(id, endptr+1);
+               if ( ! NT_STATUS_IS_OK(ret)) {
+                       /* if not valid form delete the entry */
+                       tdb_delete_bystring(cache->tdb, sidkey);
+                       ret = NT_STATUS_NONE_MAPPED;
+                       goto done;
                }
-       }
-       else if (strncmp(value, "IDMAP/GID/", 10) == 0) {
-               *mapped = true;
-               xid->type = ID_TYPE_GID;
-               xid->id = strtol(&value[10], &rem, 10);
-               if (*rem != '\0') {
-                       goto fail;
+
+               /* here ret == NT_STATUS_OK and id->status = ID_MAPPED */
+
+               if (t <= now) {
+                       /* If we've been told to be offline - stay in 
+                          that state... */
+                       if ( IS_DOMAIN_OFFLINE(our_domain) ) {
+                               DEBUG(10,("idmap_cache_map_sid: idmap is offline\n"));
+                               goto done;                              
+                       }
+
+                       /* We're expired, set an error code
+                          for upper layer */
+                       ret = NT_STATUS_SYNCHRONIZATION_REQUIRED;
                }
+
+               goto done;              
        }
-       else {
-               goto fail;
-       }
 
-       *expired = (timeout <= time(NULL));
+       /* Was a negative cache hit */
+
+       /* Ignore the negative cache when offline */
+
+       if ( IS_DOMAIN_OFFLINE(our_domain) ) {
+               DEBUG(10,("idmap_cache_map_sid: idmap is offline\n"));
+               goto done;
+       }
 
-       ret = true;
 
- fail:
-       if (!ret) {
-               DEBUG(1, ("Invalid entry %s in cache\n", value));
+       /* Check for valid or expired cache hits */
+       if (t <= now) {
+               /* We're expired. Return not mapped */
+               ret = NT_STATUS_NONE_MAPPED;
+       } else {
+               /* this is not mapped as it was a negative cache hit */
+               id->status = ID_UNMAPPED;
+               ret = NT_STATUS_OK;
        }
-       SAFE_FREE(value);
-       TALLOC_FREE(sidkey);
+
+done:
+       SAFE_FREE(databuf.dptr);
+       talloc_free(sidkey);
        return ret;
 }
 
-/*
- * search the cache for the ID an return a mapping if found
+/* search the cache for the ID an return a mapping if found *
+ *
+ * 4 cases are possible
+ *
+ * 1 map found
+ *     in this case id->status = ID_MAPPED and NT_STATUS_OK is returned
+ * 2 map not found
+ *     in this case id->status = ID_UNKNOWN and NT_STATUS_NONE_MAPPED is returned
+ * 3 negative cache found
+ *     in this case id->status = ID_UNMAPPED and NT_STATUS_OK is returned
+ * 4 map found but timer expired
+ *      in this case id->status = ID_EXPIRED and NT_STATUS_SYNCHRONIZATION_REQUIRED
+ *      is returned. In this case revalidation of the cache is needed.
  */
 
-bool idmap_cache_map_id(const struct unixid *xid, struct dom_sid *psid,
-                       bool *mapped, bool *expired)
+NTSTATUS idmap_cache_map_id(struct idmap_cache_ctx *cache, struct id_map *id)
 {
-       bool ret = false;
-       time_t timeout;
+       NTSTATUS ret;
+       TDB_DATA databuf;
+       time_t t;
        char *idkey;
-       char *value;
+       char *endptr;
+       struct winbindd_domain *our_domain = find_our_domain(); 
+       time_t now = time(NULL);        
 
-       idkey = idmap_cache_idkey(talloc_tos(), xid);
+       /* make sure it is marked as unknown by default */
+       id->status = ID_UNKNOWN;
+
+       idkey = idmap_cache_idkey(cache, id);
        if (idkey == NULL) {
-               return false;
+               return NT_STATUS_NO_MEMORY;
        }
 
-       if (!gencache_get(idkey, &value, &timeout)) {
-               TALLOC_FREE(idkey);
-               return false;
+       databuf = tdb_fetch_bystring(cache->tdb, idkey);
+
+       if (databuf.dptr == NULL) {
+               DEBUG(10, ("Cache entry with key = %s couldn't be found\n", idkey));
+               ret = NT_STATUS_NONE_MAPPED;
+               goto done;
        }
 
-       if (strcmp(value, "IDMAP/NEGATIVE") == 0) {
-               *mapped = false;
+       t = strtol((const char *)databuf.dptr, &endptr, 10);
+
+       if ((endptr == NULL) || (*endptr != '/')) {
+               DEBUG(2, ("Invalid idmap cache data format: %s\n",
+                         (const char *)databuf.dptr));
+               /* remove the entry */
+               tdb_delete_bystring(cache->tdb, idkey);
+               ret = NT_STATUS_NONE_MAPPED;
+               goto done;
        }
-       else if (strncmp(value, "IDMAP/SID/", 10) == 0) {
-               *mapped = true;
-               if (!string_to_sid(psid, value+10)) {
-                       goto fail;
+
+       /* check it is not negative */
+       if (strcmp("IDMAP/NEGATIVE", endptr+1) != 0) {
+
+               DEBUG(10, ("Returning %s cache entry: key = %s, value = %s, "
+                          "timeout = %s", t > now ? "valid" :
+                          "expired", idkey, endptr+1, ctime(&t)));
+
+               /* this call if successful will also mark the entry as mapped */
+               ret = idmap_cache_fill_map(id, endptr+1);
+               if ( ! NT_STATUS_IS_OK(ret)) {
+                       /* if not valid form delete the entry */
+                       tdb_delete_bystring(cache->tdb, idkey);
+                       ret = NT_STATUS_NONE_MAPPED;
+                       goto done;
                }
+
+               /* here ret == NT_STATUS_OK and id->mapped = ID_MAPPED */
+
+               if (t <= now) {
+                       /* If we've been told to be offline - stay in
+                          that state... */
+                       if ( IS_DOMAIN_OFFLINE(our_domain) ) {
+                               DEBUG(10,("idmap_cache_map_sid: idmap is offline\n"));
+                               goto done;
+                       }
+
+                       /* We're expired, set an error code
+                          for upper layer */
+                       ret = NT_STATUS_SYNCHRONIZATION_REQUIRED;
+               }
+
+               goto done;
        }
-       else {
-               goto fail;
+
+       /* Was a negative cache hit */
+
+       /* Ignore the negative cache when offline */
+
+       if ( IS_DOMAIN_OFFLINE(our_domain) ) {
+               DEBUG(10,("idmap_cache_map_sid: idmap is offline\n"));
+               ret = NT_STATUS_NONE_MAPPED;
+               goto done;
        }
 
-       ret = true;
+       /* Process the negative cache hit */
 
- fail:
-       if (!ret) {
-               DEBUG(1, ("Invalid entry %s in cache\n", value));
+       if (t <= now) {
+               /* We're expired.  Return not mapped */
+               ret = NT_STATUS_NONE_MAPPED;
+       } else {
+               /* this is not mapped is it was a negative cache hit */
+               id->status = ID_UNMAPPED;
+               ret = NT_STATUS_OK;
        }
-       SAFE_FREE(value);
-       TALLOC_FREE(idkey);
+
+done:
+       SAFE_FREE(databuf.dptr);
+       talloc_free(idkey);
        return ret;
 }
 
index 8a35fd9e37d774e916ca912ef2c2545c0eb40776..b2fe8b67e7ca58cb199fd09ee639af024a3505c1 100644 (file)
@@ -379,5 +379,4 @@ enum ent_type {
 #define IS_DOMAIN_OFFLINE(x) ( lp_winbind_offline_logon() && \
                               ( get_global_winbindd_state_offline() \
                                 || !(x)->online ) )
-#define IS_DOMAIN_ONLINE(x) (!(IS_DOMAIN_OFFLINE(x)))
 #endif /* _WINBINDD_H */