From 57b3d32c8d87c4273d30d73fe2bfd3de0178945d Mon Sep 17 00:00:00 2001 From: Christian Ambach Date: Thu, 4 Nov 2010 17:10:25 +0100 Subject: 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. --- source3/winbindd/winbindd_cache.c | 71 +++++++++++++++++++++++++++++++-------- 1 file changed, 57 insertions(+), 14 deletions(-) (limited to 'source3/winbindd') 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; }; @@ -204,6 +205,21 @@ static bool centry_check_bytes(struct cache_entry *centry, size_t nbytes) return true; } +/* + 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 */ @@ -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; } @@ -745,6 +764,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 */ @@ -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); -- cgit