summaryrefslogtreecommitdiff
path: root/source3/winbindd/winbindd_cache.c
diff options
context:
space:
mode:
authorChristian Ambach <christian.ambach@de.ibm.com>2010-11-04 17:10:25 +0100
committerVolker Lendecke <vl@samba.org>2010-11-08 13:39:51 +0100
commit57b3d32c8d87c4273d30d73fe2bfd3de0178945d (patch)
treeae2c2e897361512f57d0ab1ca5a1a1c51b61304a /source3/winbindd/winbindd_cache.c
parent58cfa5a82519e2850cb400bb9f1e76d3dbfd3ff2 (diff)
downloadsamba-57b3d32c8d87c4273d30d73fe2bfd3de0178945d.tar.gz
samba-57b3d32c8d87c4273d30d73fe2bfd3de0178945d.tar.bz2
samba-57b3d32c8d87c4273d30d73fe2bfd3de0178945d.zip
s3:winbind add timeouts to winbind cache
This adds a timeout value to cache entries and the NDR records in the winbind cache. The previous approach of just comparing the sequence number has some issues, e.g. when retrying a wbinfo -n operation for a user in a not yet trusted domain was always failing even after the trusted domain was added. The new approach compares sequence number and timeout value to determine if a cache entry is still valid or not. I increased the cache version number so an old cache will be wiped automatically after upgrade.
Diffstat (limited to 'source3/winbindd/winbindd_cache.c')
-rw-r--r--source3/winbindd/winbindd_cache.c71
1 files changed, 57 insertions, 14 deletions
diff --git a/source3/winbindd/winbindd_cache.c b/source3/winbindd/winbindd_cache.c
index 9ee8f6ab2a..54cbc616bd 100644
--- a/source3/winbindd/winbindd_cache.c
+++ b/source3/winbindd/winbindd_cache.c
@@ -35,7 +35,7 @@
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND
-#define WINBINDD_CACHE_VERSION 1
+#define WINBINDD_CACHE_VERSION 2
#define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
extern struct winbindd_methods reconnect_methods;
@@ -96,6 +96,7 @@ struct winbind_cache {
struct cache_entry {
NTSTATUS status;
uint32 sequence_number;
+ uint64 timeout;
uint8 *data;
uint32 len, ofs;
};
@@ -205,6 +206,21 @@ static bool centry_check_bytes(struct cache_entry *centry, size_t nbytes)
}
/*
+ pull a uint64 from a cache entry
+*/
+static uint64 centry_uint64(struct cache_entry *centry)
+{
+ uint64 ret;
+
+ if (!centry_check_bytes(centry, 8)) {
+ smb_panic_fn("centry_uint64");
+ }
+ ret = BVAL(centry->data, centry->ofs);
+ centry->ofs += 8;
+ return ret;
+}
+
+/*
pull a uint32 from a cache entry
*/
static uint32 centry_uint32(struct cache_entry *centry)
@@ -596,9 +612,10 @@ static bool centry_expired(struct winbindd_domain *domain, const char *keystr, s
}
/* if the server is down or the cache entry is not older than the
- current sequence number then it is OK */
- if (wcache_server_down(domain) ||
- centry->sequence_number == domain->sequence_number) {
+ current sequence number or it did not timeout then it is OK */
+ if (wcache_server_down(domain)
+ || (centry->sequence_number == domain->sequence_number
+ && centry->timeout > time(NULL))) {
DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
keystr, domain->name ));
return false;
@@ -629,15 +646,17 @@ static struct cache_entry *wcache_fetch_raw(char *kstr)
centry->len = data.dsize;
centry->ofs = 0;
- if (centry->len < 8) {
+ if (centry->len < 16) {
/* huh? corrupt cache? */
- DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr));
+ DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s "
+ "(len < 16)?\n", kstr));
centry_free(centry);
return NULL;
}
centry->status = centry_ntstatus(centry);
centry->sequence_number = centry_uint32(centry);
+ centry->timeout = centry_uint64(centry);
return centry;
}
@@ -746,6 +765,16 @@ static void centry_expand(struct cache_entry *centry, uint32 len)
}
/*
+ push a uint64 into a centry
+*/
+static void centry_put_uint64(struct cache_entry *centry, uint64 v)
+{
+ centry_expand(centry, 8);
+ SBVAL(centry->data, centry->ofs, v);
+ centry->ofs += 8;
+}
+
+/*
push a uint32 into a centry
*/
static void centry_put_uint32(struct cache_entry *centry, uint32 v)
@@ -866,8 +895,10 @@ struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status
centry->data = SMB_XMALLOC_ARRAY(uint8, centry->len);
centry->ofs = 0;
centry->sequence_number = domain->sequence_number;
+ centry->timeout = lp_winbind_cache_time() + time(NULL);
centry_put_ntstatus(centry, status);
centry_put_uint32(centry, centry->sequence_number);
+ centry_put_uint64(centry, centry->timeout);
return centry;
}
@@ -3484,9 +3515,10 @@ static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA dat
centry->len = data.dsize;
centry->ofs = 0;
- if (centry->len < 8) {
+ if (centry->len < 16) {
/* huh? corrupt cache? */
- DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr));
+ DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
+ "(len < 16) ?\n", kstr));
centry_free(centry);
state->bad_entry = true;
state->success = false;
@@ -3495,6 +3527,7 @@ static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA dat
centry->status = NT_STATUS(centry_uint32(centry));
centry->sequence_number = centry_uint32(centry);
+ centry->timeout = centry_uint64(centry);
return centry;
}
@@ -4699,12 +4732,13 @@ bool wcache_fetch_ndr(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
if (data.dptr == NULL) {
return false;
}
- if (data.dsize < 4) {
+ if (data.dsize < 12) {
goto fail;
}
if (!is_domain_offline(domain)) {
uint32_t entry_seqnum, dom_seqnum, last_check;
+ uint64_t entry_timeout;
if (!wcache_fetch_seqnum(domain->name, &dom_seqnum,
&last_check)) {
@@ -4716,15 +4750,20 @@ bool wcache_fetch_ndr(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
(int)entry_seqnum));
goto fail;
}
+ entry_timeout = BVAL(data.dptr, 4);
+ if (entry_timeout > time(NULL)) {
+ DEBUG(10, ("Entry has timed out\n"));
+ goto fail;
+ }
}
- resp->data = (uint8_t *)talloc_memdup(mem_ctx, data.dptr + 4,
- data.dsize - 4);
+ resp->data = (uint8_t *)talloc_memdup(mem_ctx, data.dptr + 12,
+ data.dsize - 12);
if (resp->data == NULL) {
DEBUG(10, ("talloc failed\n"));
goto fail;
}
- resp->length = data.dsize - 4;
+ resp->length = data.dsize - 12;
ret = true;
fail:
@@ -4737,6 +4776,7 @@ void wcache_store_ndr(struct winbindd_domain *domain, uint32_t opnum,
{
TDB_DATA key, data;
uint32_t dom_seqnum, last_check;
+ uint64_t timeout;
if (!wcache_opnum_cacheable(opnum) ||
is_my_own_sam_domain(domain) ||
@@ -4758,14 +4798,17 @@ void wcache_store_ndr(struct winbindd_domain *domain, uint32_t opnum,
return;
}
- data.dsize = resp->length + 4;
+ timeout = time(NULL) + lp_winbind_cache_time();
+
+ data.dsize = resp->length + 12;
data.dptr = talloc_array(key.dptr, uint8_t, data.dsize);
if (data.dptr == NULL) {
goto done;
}
SIVAL(data.dptr, 0, dom_seqnum);
- memcpy(data.dptr+4, resp->data, resp->length);
+ SBVAL(data.dptr, 4, timeout);
+ memcpy(data.dptr + 12, resp->data, resp->length);
tdb_store(wcache->tdb, key, data, 0);