/*
- Unix SMB/Netbios implementation.
- Version 2.0
+ Unix SMB/CIFS implementation.
- Winbind daemon - caching related functions
+ Winbind cache backend functions
- Copyright (C) Tim Potter 2000
+ Copyright (C) Andrew Tridgell 2001
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "winbindd.h"
-#define CACHE_TYPE_USER "USR"
-#define CACHE_TYPE_GROUP "GRP"
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
-/* Initialise caching system */
-
-static TDB_CONTEXT *cache_tdb;
+struct winbind_cache {
+ TDB_CONTEXT *tdb;
+};
-struct cache_rec {
- uint32 seq_num;
- time_t mod_time;
+struct cache_entry {
+ NTSTATUS status;
+ uint32 sequence_number;
+ uint8 *data;
+ uint32 len, ofs;
};
-void winbindd_cache_init(void)
+#define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
+
+static struct winbind_cache *wcache;
+
+/* flush the cache */
+void wcache_flush_cache(void)
{
- /* Open tdb cache */
+ extern BOOL opt_nocache;
+
+ if (!wcache)
+ return;
+ if (wcache->tdb) {
+ tdb_close(wcache->tdb);
+ wcache->tdb = NULL;
+ }
+ if (opt_nocache)
+ return;
+
+ wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 5000,
+ TDB_CLEAR_IF_FIRST, O_RDWR|O_CREAT, 0600);
- if (!(cache_tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 0,
- TDB_NOLOCK, O_RDWR | O_CREAT | O_TRUNC,
- 0600))) {
- DEBUG(0, ("Unable to open tdb cache - user and group caching "
- "disabled\n"));
+ if (!wcache->tdb) {
+ DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
}
+ DEBUG(10,("wcache_flush_cache success\n"));
}
-/* get the domain sequence number, possibly re-fetching */
-static uint32 cached_sequence_number(char *domain_name)
+void winbindd_check_cache_size(time_t t)
{
- fstring keystr;
- TDB_DATA dbuf;
- struct cache_rec rec;
- time_t t = time(NULL);
+ static time_t last_check_time;
+ struct stat st;
- snprintf(keystr, sizeof(keystr), "CACHESEQ/%s", domain_name);
- dbuf = tdb_fetch_by_string(cache_tdb, keystr);
- if (!dbuf.dptr || dbuf.dsize != sizeof(rec)) {
- goto refetch;
- }
- memcpy(&rec, dbuf.dptr, sizeof(rec));
- SAFE_FREE(dbuf.dptr);
+ if (last_check_time == (time_t)0)
+ last_check_time = t;
- if (t < (rec.mod_time + lp_winbind_cache_time())) {
- DEBUG(3,("cached sequence number for %s is %u\n",
- domain_name, (unsigned)rec.seq_num));
- return rec.seq_num;
+ if (t - last_check_time < 60 && t - last_check_time > 0)
+ return;
+
+ if (wcache == NULL || wcache->tdb == NULL) {
+ DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
+ return;
}
- refetch:
- rec.seq_num = domain_sequence_number(domain_name);
- rec.mod_time = t;
- tdb_store_by_string(cache_tdb, keystr, &rec, sizeof(rec));
+ if (fstat(wcache->tdb->fd, &st) == -1) {
+ DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno) ));
+ return;
+ }
- return rec.seq_num;
+ if (st.st_size > WINBINDD_MAX_CACHE_SIZE) {
+ DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
+ (unsigned long)st.st_size,
+ (unsigned long)WINBINDD_MAX_CACHE_SIZE));
+ wcache_flush_cache();
+ }
}
-/* Check whether a seq_num for a cached item has expired */
-static BOOL cache_domain_expired(char *domain_name, uint32 seq_num)
+/* get the winbind_cache structure */
+static struct winbind_cache *get_cache(struct winbindd_domain *domain)
{
- if (cached_sequence_number(domain_name) != seq_num) {
- DEBUG(3,("seq %u for %s has expired\n", (unsigned)seq_num,
- domain_name));
- return True;
+ struct winbind_cache *ret = wcache;
+
+ if (!domain->backend) {
+ extern struct winbindd_methods msrpc_methods;
+ switch (lp_security()) {
+#ifdef HAVE_ADS
+ case SEC_ADS: {
+ extern struct winbindd_methods ads_methods;
+ domain->backend = &ads_methods;
+ break;
+ }
+#endif
+ default:
+ domain->backend = &msrpc_methods;
+ }
}
- return False;
+
+ if (ret)
+ return ret;
+
+ ret = smb_xmalloc(sizeof(*ret));
+ ZERO_STRUCTP(ret);
+
+ wcache = ret;
+ wcache_flush_cache();
+
+ return ret;
}
-static void set_cache_sequence_number(char *domain_name, char *cache_type,
- char *subkey)
+/*
+ free a centry structure
+*/
+static void centry_free(struct cache_entry *centry)
{
- fstring keystr;
+ if (!centry)
+ return;
+ SAFE_FREE(centry->data);
+ free(centry);
+}
- snprintf(keystr, sizeof(keystr),"CACHESEQ %s/%s/%s",
- domain_name, cache_type, subkey?subkey:"");
+/*
+ pull a uint32 from a cache entry
+*/
+static uint32 centry_uint32(struct cache_entry *centry)
+{
+ uint32 ret;
+ if (centry->len - centry->ofs < 4) {
+ DEBUG(0,("centry corruption? needed 4 bytes, have %d\n",
+ centry->len - centry->ofs));
+ smb_panic("centry_uint32");
+ }
+ ret = IVAL(centry->data, centry->ofs);
+ centry->ofs += 4;
+ return ret;
+}
- tdb_store_int(cache_tdb, keystr, cached_sequence_number(domain_name));
+/*
+ pull a uint8 from a cache entry
+*/
+static uint8 centry_uint8(struct cache_entry *centry)
+{
+ uint8 ret;
+ if (centry->len - centry->ofs < 1) {
+ DEBUG(0,("centry corruption? needed 1 bytes, have %d\n",
+ centry->len - centry->ofs));
+ smb_panic("centry_uint32");
+ }
+ ret = CVAL(centry->data, centry->ofs);
+ centry->ofs += 1;
+ return ret;
}
-static uint32 get_cache_sequence_number(char *domain_name, char *cache_type,
- char *subkey)
+/* pull a string from a cache entry, using the supplied
+ talloc context
+*/
+static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
{
- fstring keystr;
- uint32 seq_num;
+ uint32 len;
+ char *ret;
- snprintf(keystr, sizeof(keystr), "CACHESEQ %s/%s/%s",
- domain_name, cache_type, subkey?subkey:"");
- seq_num = (uint32)tdb_fetch_int(cache_tdb, keystr);
+ len = centry_uint8(centry);
- DEBUG(3,("%s is %u\n", keystr, (unsigned)seq_num));
+ if (len == 0xFF) {
+ /* a deliberate NULL string */
+ return NULL;
+ }
- return seq_num;
-}
+ if (centry->len - centry->ofs < len) {
+ DEBUG(0,("centry corruption? needed %d bytes, have %d\n",
+ len, centry->len - centry->ofs));
+ smb_panic("centry_string");
+ }
-/* Fill the user or group cache with supplied data */
+ ret = talloc(mem_ctx, len+1);
+ if (!ret) {
+ smb_panic("centry_string out of memory\n");
+ }
+ memcpy(ret,centry->data + centry->ofs, len);
+ ret[len] = 0;
+ centry->ofs += len;
+ return ret;
+}
-static void store_cache(char *domain_name, char *cache_type,
- void *sam_entries, int buflen)
+/* pull a string from a cache entry, using the supplied
+ talloc context
+*/
+static DOM_SID *centry_sid(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
{
- fstring keystr;
+ DOM_SID *sid;
+ char *sid_string;
- if (lp_winbind_cache_time() == 0) return;
+ sid = talloc(mem_ctx, sizeof(*sid));
+ if (!sid)
+ return NULL;
+
+ sid_string = centry_string(centry, mem_ctx);
+ if (!string_to_sid(sid, sid_string)) {
+ return NULL;
+ }
+ return sid;
+}
- /* Error check */
- if (!sam_entries || buflen == 0) return;
+/* the server is considered down if it can't give us a sequence number */
+static BOOL wcache_server_down(struct winbindd_domain *domain)
+{
+ BOOL ret;
- /* Store data as a mega-huge chunk in the tdb */
- snprintf(keystr, sizeof(keystr), "%s CACHE DATA/%s", cache_type,
- domain_name);
+ if (!wcache->tdb)
+ return False;
- tdb_store_by_string(cache_tdb, keystr, sam_entries, buflen);
+ ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
- /* Stamp cache with current seq number */
- set_cache_sequence_number(domain_name, cache_type, NULL);
+ if (ret)
+ DEBUG(10,("wcache_server_down: server for Domain %s down\n",
+ domain->name ));
+ return ret;
}
-/* Fill the user cache with supplied data */
+static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
+{
+ TDB_DATA data;
+ fstring key;
+ uint32 time_diff;
+
+ if (!wcache->tdb) {
+ DEBUG(10,("fetch_cache_seqnum: tdb == NULL\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ snprintf( key, sizeof(key), "SEQNUM/%s", domain->name );
+
+ data = tdb_fetch_by_string( wcache->tdb, key );
+ if ( !data.dptr || data.dsize!=8 ) {
+ DEBUG(10,("fetch_cache_seqnum: invalid data size key [%s]\n", key ));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ domain->sequence_number = IVAL(data.dptr, 0);
+ domain->last_seq_check = IVAL(data.dptr, 4);
+
+ /* have we expired? */
+
+ time_diff = now - domain->last_seq_check;
+ if ( 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));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
+ domain->name, domain->sequence_number,
+ (uint32)domain->last_seq_check));
+
+ return NT_STATUS_OK;
+}
-void winbindd_store_user_cache(char *domain,
- struct getpwent_user *sam_entries,
- int num_sam_entries)
+static NTSTATUS store_cache_seqnum( struct winbindd_domain *domain )
{
- DEBUG(3, ("storing user cache %s/%d entries\n", domain,
- num_sam_entries));
+ TDB_DATA data, key;
+ fstring key_str;
+ char buf[8];
+
+ if (!wcache->tdb) {
+ DEBUG(10,("store_cache_seqnum: tdb == NULL\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ snprintf( key_str, sizeof(key_str), "SEQNUM/%s", domain->name );
+ key.dptr = key_str;
+ key.dsize = strlen(key_str)+1;
+
+ SIVAL(buf, 0, domain->sequence_number);
+ SIVAL(buf, 4, domain->last_seq_check);
+ data.dptr = buf;
+ data.dsize = 8;
+
+ if ( tdb_store( wcache->tdb, key, data, TDB_REPLACE) == -1 ) {
+ DEBUG(10,("store_cache_seqnum: tdb_store fail key [%s]\n", key_str ));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
- store_cache(domain, CACHE_TYPE_USER, sam_entries,
- num_sam_entries * sizeof(struct getpwent_user));
+ DEBUG(10,("store_cache_seqnum: success [%s][%u @ %u]\n",
+ domain->name, domain->sequence_number,
+ (uint32)domain->last_seq_check));
+
+ return NT_STATUS_OK;
}
-/* Fill the group cache with supplied data */
+/*
+ refresh the domain sequence number. If force is True
+ then always refresh it, no matter how recently we fetched it
+*/
-void winbindd_store_group_cache(char *domain,
- struct acct_info *sam_entries,
- int num_sam_entries)
+static void refresh_sequence_number(struct winbindd_domain *domain, BOOL force)
{
- DEBUG(0, ("storing group cache %s/%d entries\n", domain,
- num_sam_entries));
+ NTSTATUS status;
+ unsigned time_diff;
+ time_t t = time(NULL);
+ unsigned cache_time = lp_winbind_cache_time();
+
+ /* trying to reconnect is expensive, don't do it too often */
+ if (domain->sequence_number == DOM_SEQUENCE_NONE) {
+ cache_time *= 8;
+ }
+
+ time_diff = t - domain->last_seq_check;
+
+ /* see if we have to refetch the domain sequence number */
+ if (!force && (time_diff < cache_time)) {
+ DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
+ return;
+ }
+
+ /* try to get the sequence number from the tdb cache first */
+ /* this will update the timestamp as well */
+
+ status = fetch_cache_seqnum( domain, t );
+ if ( NT_STATUS_IS_OK(status) )
+ goto done;
+
+ status = domain->backend->sequence_number(domain, &domain->sequence_number);
- store_cache(domain, CACHE_TYPE_GROUP, sam_entries,
- num_sam_entries * sizeof(struct acct_info));
+ if (!NT_STATUS_IS_OK(status)) {
+ domain->sequence_number = DOM_SEQUENCE_NONE;
+ }
+
+ domain->last_seq_check = time(NULL);
+
+ /* save the new sequence number ni the cache */
+ store_cache_seqnum( domain );
+
+done:
+ DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
+ domain->name, domain->sequence_number));
+
+ return;
}
-static void store_cache_entry(char *domain, char *cache_type, char *name,
- void *buf, int len)
+/*
+ decide if a cache entry has expired
+*/
+static BOOL centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
{
- fstring keystr;
+ /* if the server is OK and our cache entry came from when it was down then
+ the entry is invalid */
+ if (domain->sequence_number != DOM_SEQUENCE_NONE &&
+ centry->sequence_number == DOM_SEQUENCE_NONE) {
+ DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
+ keystr, domain->name ));
+ return True;
+ }
+
+ /* 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) {
+ DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
+ keystr, domain->name ));
+ return False;
+ }
- /* Create key for store */
- snprintf(keystr, sizeof(keystr), "%s/%s/%s", cache_type, domain, name);
+ DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
+ keystr, domain->name ));
- /* Store it */
- tdb_store_by_string(cache_tdb, keystr, buf, len);
+ /* it's expired */
+ return True;
}
-/* Fill a user info cache entry */
-
-void winbindd_store_user_cache_entry(char *domain, char *user_name,
- struct winbindd_pw *pw)
+/*
+ fetch an entry from the cache, with a varargs key. auto-fetch the sequence
+ number and return status
+*/
+static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
+ struct winbindd_domain *domain,
+ const char *format, ...) PRINTF_ATTRIBUTE(3,4);
+static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
+ struct winbindd_domain *domain,
+ const char *format, ...)
{
- if (lp_winbind_cache_time() == 0) return;
+ va_list ap;
+ char *kstr;
+ TDB_DATA data;
+ struct cache_entry *centry;
+ TDB_DATA key;
- store_cache_entry(domain, CACHE_TYPE_USER, user_name, pw,
- sizeof(struct winbindd_pw));
+ refresh_sequence_number(domain, False);
- set_cache_sequence_number(domain, CACHE_TYPE_USER, user_name);
+ va_start(ap, format);
+ smb_xvasprintf(&kstr, format, ap);
+ va_end(ap);
+
+ key.dptr = kstr;
+ key.dsize = strlen(kstr);
+ data = tdb_fetch(wcache->tdb, key);
+ if (!data.dptr) {
+ /* a cache miss */
+ free(kstr);
+ return NULL;
+ }
+
+ centry = smb_xmalloc(sizeof(*centry));
+ centry->data = data.dptr;
+ centry->len = data.dsize;
+ centry->ofs = 0;
+
+ if (centry->len < 8) {
+ /* huh? corrupt cache? */
+ DEBUG(10,("wcache_fetch: Corrupt cache for key %s domain %s (len < 8) ?\n",
+ kstr, domain->name ));
+ centry_free(centry);
+ free(kstr);
+ return NULL;
+ }
+
+ centry->status = NT_STATUS(centry_uint32(centry));
+ centry->sequence_number = centry_uint32(centry);
+
+ if (centry_expired(domain, kstr, centry)) {
+ extern BOOL opt_dual_daemon;
+
+ DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
+ kstr, domain->name ));
+
+ if (opt_dual_daemon) {
+ extern BOOL background_process;
+ background_process = True;
+ DEBUG(10,("wcache_fetch: background processing expired entry %s for domain %s\n",
+ kstr, domain->name ));
+ } else {
+ centry_free(centry);
+ free(kstr);
+ return NULL;
+ }
+ }
+
+ DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
+ kstr, domain->name ));
+
+ free(kstr);
+ return centry;
}
-/* Fill a user uid cache entry */
+/*
+ make sure we have at least len bytes available in a centry
+*/
+static void centry_expand(struct cache_entry *centry, uint32 len)
+{
+ uint8 *p;
+ if (centry->len - centry->ofs >= len)
+ return;
+ centry->len *= 2;
+ p = realloc(centry->data, centry->len);
+ if (!p) {
+ DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
+ smb_panic("out of memory in centry_expand");
+ }
+ centry->data = p;
+}
-void winbindd_store_uid_cache_entry(char *domain, uid_t uid,
- struct winbindd_pw *pw)
+/*
+ push a uint32 into a centry
+*/
+static void centry_put_uint32(struct cache_entry *centry, uint32 v)
{
- fstring uidstr;
+ centry_expand(centry, 4);
+ SIVAL(centry->data, centry->ofs, v);
+ centry->ofs += 4;
+}
- if (lp_winbind_cache_time() == 0) return;
+/*
+ push a uint8 into a centry
+*/
+static void centry_put_uint8(struct cache_entry *centry, uint8 v)
+{
+ centry_expand(centry, 1);
+ SCVAL(centry->data, centry->ofs, v);
+ centry->ofs += 1;
+}
- snprintf(uidstr, sizeof(uidstr), "#%u", (unsigned)uid);
+/*
+ push a string into a centry
+ */
+static void centry_put_string(struct cache_entry *centry, const char *s)
+{
+ int len;
- DEBUG(3, ("storing uid cache entry %s/%s\n", domain, uidstr));
+ if (!s) {
+ /* null strings are marked as len 0xFFFF */
+ centry_put_uint8(centry, 0xFF);
+ return;
+ }
- store_cache_entry(domain, CACHE_TYPE_USER, uidstr, pw,
- sizeof(struct winbindd_pw));
+ len = strlen(s);
+ /* can't handle more than 254 char strings. Truncating is probably best */
+ if (len > 254)
+ len = 254;
+ centry_put_uint8(centry, len);
+ centry_expand(centry, len);
+ memcpy(centry->data + centry->ofs, s, len);
+ centry->ofs += len;
+}
- set_cache_sequence_number(domain, CACHE_TYPE_USER, uidstr);
+static void centry_put_sid(struct cache_entry *centry, const DOM_SID *sid)
+{
+ fstring sid_string;
+ centry_put_string(centry, sid_to_string(sid_string, sid));
}
-/* Fill a group info cache entry */
-void winbindd_store_group_cache_entry(char *domain, char *group_name,
- struct winbindd_gr *gr, void *extra_data,
- int extra_data_len)
+/*
+ start a centry for output. When finished, call centry_end()
+*/
+struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status)
{
- fstring keystr;
+ struct cache_entry *centry;
- if (lp_winbind_cache_time() == 0) return;
+ if (!wcache->tdb)
+ return NULL;
- DEBUG(3, ("storing group cache entry %s/%s\n", domain, group_name));
+ centry = smb_xmalloc(sizeof(*centry));
- /* Fill group data */
+ centry->len = 8192; /* reasonable default */
+ centry->data = smb_xmalloc(centry->len);
+ centry->ofs = 0;
+ centry->sequence_number = domain->sequence_number;
+ centry_put_uint32(centry, NT_STATUS_V(status));
+ centry_put_uint32(centry, centry->sequence_number);
+ return centry;
+}
- store_cache_entry(domain, CACHE_TYPE_GROUP, group_name, gr,
- sizeof(struct winbindd_gr));
+/*
+ finish a centry and write it to the tdb
+*/
+static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
+static void centry_end(struct cache_entry *centry, const char *format, ...)
+{
+ va_list ap;
+ char *kstr;
+ TDB_DATA key, data;
- /* Fill extra data */
+ va_start(ap, format);
+ smb_xvasprintf(&kstr, format, ap);
+ va_end(ap);
- snprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP,
- domain, group_name);
- tdb_store_by_string(cache_tdb, keystr, extra_data, extra_data_len);
+ key.dptr = kstr;
+ key.dsize = strlen(kstr);
+ data.dptr = centry->data;
+ data.dsize = centry->ofs;
+
+ tdb_store(wcache->tdb, key, data, TDB_REPLACE);
+ free(kstr);
+}
+
+static void wcache_save_name_to_sid(struct winbindd_domain *domain,
+ NTSTATUS status,
+ const char *name, DOM_SID *sid,
+ enum SID_NAME_USE type)
+{
+ struct cache_entry *centry;
+ fstring uname;
+ fstring sid_string;
+
+ centry = centry_start(domain, status);
+ if (!centry)
+ return;
+ centry_put_sid(centry, sid);
+ fstrcpy(uname, name);
+ strupper(uname);
+ centry_end(centry, "NS/%s", sid_to_string(sid_string, sid));
+ DEBUG(10,("wcache_save_name_to_sid: %s -> %s\n", uname, sid_string));
+ centry_free(centry);
+}
- set_cache_sequence_number(domain, CACHE_TYPE_GROUP, group_name);
+static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
+ DOM_SID *sid, const char *name, enum SID_NAME_USE type)
+{
+ struct cache_entry *centry;
+ fstring sid_string;
+
+ centry = centry_start(domain, status);
+ if (!centry)
+ return;
+ if (NT_STATUS_IS_OK(status)) {
+ centry_put_uint32(centry, type);
+ centry_put_string(centry, name);
+ }
+ centry_end(centry, "SN/%s", sid_to_string(sid_string, sid));
+ DEBUG(10,("wcache_save_sid_to_name: %s -> %s\n", sid_string, name));
+ centry_free(centry);
}
-/* Fill a group info cache entry */
-void winbindd_store_gid_cache_entry(char *domain, gid_t gid,
- struct winbindd_gr *gr, void *extra_data,
- int extra_data_len)
+static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status, WINBIND_USERINFO *info)
{
- fstring keystr;
- fstring gidstr;
+ struct cache_entry *centry;
+ fstring sid_string;
+
+ centry = centry_start(domain, status);
+ if (!centry)
+ return;
+ centry_put_string(centry, info->acct_name);
+ centry_put_string(centry, info->full_name);
+ centry_put_sid(centry, info->user_sid);
+ centry_put_sid(centry, info->group_sid);
+ centry_end(centry, "U/%s", sid_to_string(sid_string, info->user_sid));
+ DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
+ centry_free(centry);
+}
- snprintf(gidstr, sizeof(gidstr), "#%u", (unsigned)gid);
- if (lp_winbind_cache_time() == 0) return;
+/* 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,
+ WINBIND_USERINFO **info)
+{
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+ unsigned int i, retry;
- DEBUG(3, ("storing gid cache entry %s/%s\n", domain, gidstr));
+ if (!cache->tdb)
+ goto do_query;
- /* Fill group data */
+ centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
+ if (!centry)
+ goto do_query;
+
+ *num_entries = centry_uint32(centry);
+
+ if (*num_entries == 0)
+ goto do_cached;
+
+ (*info) = talloc(mem_ctx, sizeof(**info) * (*num_entries));
+ if (! (*info))
+ smb_panic("query_user_list out of 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].user_sid = centry_sid(centry, mem_ctx);
+ (*info)[i].group_sid = centry_sid(centry, mem_ctx);
+ }
- store_cache_entry(domain, CACHE_TYPE_GROUP, gidstr, gr,
- sizeof(struct winbindd_gr));
+do_cached:
+ status = centry->status;
- /* Fill extra data */
+ DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status %s\n",
+ domain->name, get_friendly_nt_error_msg(status) ));
- snprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP,
- domain, gidstr);
+ centry_free(centry);
+ return status;
- tdb_store_by_string(cache_tdb, keystr, extra_data, extra_data_len);
+do_query:
+ *num_entries = 0;
+ *info = NULL;
- set_cache_sequence_number(domain, CACHE_TYPE_GROUP, gidstr);
+ if (wcache_server_down(domain)) {
+ return NT_STATUS_SERVER_DISABLED;
+ }
+
+ /* Put the query_user_list() in a retry loop. There appears to be
+ * some bug either with Windows 2000 or Samba's handling of large
+ * rpc replies. This manifests itself as sudden disconnection
+ * at a random point in the enumeration of a large (60k) user list.
+ * The retry loop simply tries the operation again. )-: It's not
+ * pretty but an acceptable workaround until we work out what the
+ * real problem is. */
+
+ retry = 0;
+ do {
+
+ 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);
+ if (!NT_STATUS_IS_OK(status))
+ DEBUG(3, ("query_user_list: returned 0x%08x, retrying\n", NT_STATUS_V(status)));
+ if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL)) {
+ DEBUG(3, ("query_user_list: flushing connection cache\n"));
+ winbindd_cm_flush();
+ }
+
+ } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) && (retry++ < 5));
+
+ /* and save it */
+ refresh_sequence_number(domain, False);
+ 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_sid(centry, (*info)[i].user_sid);
+ centry_put_sid(centry, (*info)[i].group_sid);
+ if (domain->backend->consistent) {
+ /* when the backend is consistent we can pre-prime some mappings */
+ wcache_save_name_to_sid(domain, NT_STATUS_OK,
+ (*info)[i].acct_name,
+ (*info)[i].user_sid,
+ SID_NAME_USER);
+ wcache_save_sid_to_name(domain, NT_STATUS_OK,
+ (*info)[i].user_sid,
+ (*info)[i].acct_name,
+ SID_NAME_USER);
+ wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
+ }
+ }
+ centry_end(centry, "UL/%s", domain->name);
+ centry_free(centry);
+
+skip_save:
+ return status;
}
-/* Fetch some cached user or group data */
-static BOOL fetch_cache(char *domain_name, char *cache_type,
- void **sam_entries, int *buflen)
+/* list all domain groups */
+static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ struct acct_info **info)
{
- TDB_DATA data;
- fstring keystr;
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+ unsigned int i;
- if (lp_winbind_cache_time() == 0) return False;
+ if (!cache->tdb)
+ goto do_query;
- /* Parameter check */
- if (!sam_entries || !buflen) {
- return False;
+ centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
+ if (!centry)
+ goto do_query;
+
+ *num_entries = centry_uint32(centry);
+
+ if (*num_entries == 0)
+ goto do_cached;
+
+ (*info) = talloc(mem_ctx, sizeof(**info) * (*num_entries));
+ if (! (*info))
+ smb_panic("enum_dom_groups out of memory");
+ for (i=0; i<(*num_entries); i++) {
+ fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
+ fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
+ (*info)[i].rid = centry_uint32(centry);
}
- /* Check cache data is current */
- if (cache_domain_expired(domain_name,
- get_cache_sequence_number(domain_name,
- cache_type,
- NULL))) {
- return False;
+do_cached:
+ status = centry->status;
+
+ DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status %s\n",
+ domain->name, get_friendly_nt_error_msg(status) ));
+
+ centry_free(centry);
+ return status;
+
+do_query:
+ *num_entries = 0;
+ *info = NULL;
+
+ if (wcache_server_down(domain)) {
+ return NT_STATUS_SERVER_DISABLED;
}
-
- /* Create key */
- snprintf(keystr, sizeof(keystr), "%s CACHE DATA/%s", cache_type,
- domain_name);
-
- /* Fetch cache information */
- data = tdb_fetch_by_string(cache_tdb, keystr);
-
- if (!data.dptr) return False;
- /* Copy across cached data. We can save a memcpy() by directly
- assigning the data.dptr to the sam_entries pointer. It will
- be freed by the end{pw,gr}ent() function. */
-
- *sam_entries = (struct acct_info *)data.dptr;
- *buflen = data.dsize;
-
- return True;
+ DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
+ domain->name ));
+
+ status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
+
+ /* and save it */
+ refresh_sequence_number(domain, False);
+ 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].acct_desc);
+ centry_put_uint32(centry, (*info)[i].rid);
+ }
+ centry_end(centry, "GL/%s/domain", domain->name);
+ centry_free(centry);
+
+skip_save:
+ return status;
}
-/* Return cached entries for a domain. Return false if there are no cached
- entries, or the cached information has expired for the domain. */
-
-BOOL winbindd_fetch_user_cache(char *domain_name,
- struct getpwent_user **sam_entries,
- int *num_entries)
+/* list all domain groups */
+static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_entries,
+ struct acct_info **info)
{
- BOOL result;
- int buflen;
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+ unsigned int i;
- result = fetch_cache(domain_name, CACHE_TYPE_USER,
- (void **)sam_entries, &buflen);
+ if (!cache->tdb)
+ goto do_query;
- *num_entries = buflen / sizeof(struct getpwent_user);
+ centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
+ if (!centry)
+ goto do_query;
- DEBUG(3, ("fetched %d cache entries for %s\n", *num_entries,
- domain_name));
+ *num_entries = centry_uint32(centry);
+
+ if (*num_entries == 0)
+ goto do_cached;
+
+ (*info) = talloc(mem_ctx, sizeof(**info) * (*num_entries));
+ if (! (*info))
+ smb_panic("enum_dom_groups out of memory");
+ for (i=0; i<(*num_entries); i++) {
+ fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
+ fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
+ (*info)[i].rid = centry_uint32(centry);
+ }
- return result;
-}
+do_cached:
-/* Return cached entries for a domain. Return false if there are no cached
- entries, or the cached information has expired for the domain. */
+ /* If we are returning cached data and the domain controller
+ is down then we don't know whether the data is up to date
+ or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
+ indicate this. */
-BOOL winbindd_fetch_group_cache(char *domain_name,
- struct acct_info **sam_entries,
- int *num_entries)
-{
- BOOL result;
- int buflen;
+ if (wcache_server_down(domain)) {
+ DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
+ status = NT_STATUS_MORE_PROCESSING_REQUIRED;
+ } else
+ status = centry->status;
- result = fetch_cache(domain_name, CACHE_TYPE_GROUP,
- (void **)sam_entries, &buflen);
+ DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status %s\n",
+ domain->name, get_friendly_nt_error_msg(status) ));
- *num_entries = buflen / sizeof(struct acct_info);
+ centry_free(centry);
+ return status;
- DEBUG(3, ("fetched %d cache entries for %s\n", *num_entries,
- domain_name));
+do_query:
+ *num_entries = 0;
+ *info = NULL;
- return result;
-}
+ if (wcache_server_down(domain)) {
+ return NT_STATUS_SERVER_DISABLED;
+ }
-static BOOL fetch_cache_entry(char *domain, char *cache_type, char *name,
- void *buf, int len)
-{
- TDB_DATA data;
- fstring keystr;
-
- /* Create key for lookup */
- snprintf(keystr, sizeof(keystr), "%s/%s/%s", cache_type, domain, name);
-
- /* Look up cache entry */
- data = tdb_fetch_by_string(cache_tdb, keystr);
- if (!data.dptr) return False;
-
- /* Copy found entry into buffer */
- memcpy((char *)buf, data.dptr, len < data.dsize ? len : data.dsize);
- SAFE_FREE(data.dptr);
- return True;
+ DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
+ domain->name ));
+
+ status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
+
+ /* and save it */
+ refresh_sequence_number(domain, False);
+ 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].acct_desc);
+ centry_put_uint32(centry, (*info)[i].rid);
+ }
+ centry_end(centry, "GL/%s/local", domain->name);
+ centry_free(centry);
+
+skip_save:
+ return status;
}
-/* Fetch an individual user cache entry */
-BOOL winbindd_fetch_user_cache_entry(char *domain_name, char *user,
- struct winbindd_pw *pw)
+/* 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 *name,
+ DOM_SID *sid,
+ enum SID_NAME_USE *type)
{
- uint32 seq_num;
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+ fstring uname;
+ DOM_SID *sid2;
+
+ if (!cache->tdb)
+ goto do_query;
+
+ fstrcpy(uname, name);
+ strupper(uname);
+ centry = wcache_fetch(cache, domain, "NS/%s/%s", domain->name, uname);
+ if (!centry)
+ goto do_query;
+ *type = centry_uint32(centry);
+ sid2 = centry_sid(centry, mem_ctx);
+ if (!sid2) {
+ ZERO_STRUCTP(sid);
+ } else {
+ sid_copy(sid, sid2);
+ }
+
+ status = centry->status;
- if (lp_winbind_cache_time() == 0) return False;
+ DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status %s\n",
+ domain->name, get_friendly_nt_error_msg(status) ));
- seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_USER,
- user);
- if (cache_domain_expired(domain_name, seq_num)) return False;
+ centry_free(centry);
+ return status;
+
+do_query:
+ ZERO_STRUCTP(sid);
+
+ if (wcache_server_down(domain)) {
+ return NT_STATUS_SERVER_DISABLED;
+ }
- return fetch_cache_entry(domain_name, CACHE_TYPE_USER, user, pw,
- sizeof(struct winbindd_pw));
+ DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
+ domain->name ));
+
+ status = domain->backend->name_to_sid(domain, mem_ctx, name, sid, type);
+
+ /* and save it */
+ wcache_save_name_to_sid(domain, status, name, sid, *type);
+
+ /* We can't save the sid to name mapping as we don't know the
+ correct case of the name without looking it up */
+
+ return status;
}
-/* Fetch an individual uid cache entry */
-BOOL winbindd_fetch_uid_cache_entry(char *domain_name, uid_t uid,
- struct winbindd_pw *pw)
+/* 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,
+ DOM_SID *sid,
+ char **name,
+ enum SID_NAME_USE *type)
{
- fstring uidstr;
- uint32 seq_num;
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+ fstring sid_string;
+
+ if (!cache->tdb)
+ goto do_query;
+
+ centry = wcache_fetch(cache, domain, "SN/%s", sid_to_string(sid_string, sid));
+ if (!centry)
+ goto do_query;
+ if (NT_STATUS_IS_OK(centry->status)) {
+ *type = centry_uint32(centry);
+ *name = centry_string(centry, mem_ctx);
+ }
+ status = centry->status;
+
+ DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status %s\n",
+ domain->name, get_friendly_nt_error_msg(status) ));
- if (lp_winbind_cache_time() == 0) return False;
+ centry_free(centry);
+ return status;
- snprintf(uidstr, sizeof(uidstr), "#%u", (unsigned)uid);
- seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_USER,
- uidstr);
- if (cache_domain_expired(domain_name, seq_num)) return False;
+do_query:
+ *name = NULL;
- return fetch_cache_entry(domain_name, CACHE_TYPE_USER, uidstr, pw,
- sizeof(struct winbindd_pw));
+ if (wcache_server_down(domain)) {
+ return NT_STATUS_SERVER_DISABLED;
+ }
+
+ DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
+ domain->name ));
+
+ status = domain->backend->sid_to_name(domain, mem_ctx, sid, name, type);
+
+ /* and save it */
+ refresh_sequence_number(domain, False);
+ wcache_save_sid_to_name(domain, status, sid, *name, *type);
+ wcache_save_name_to_sid(domain, status, *name, sid, *type);
+
+ return status;
}
-/* Fetch an individual group cache entry. This function differs from the
- user cache code as we need to store the group membership data. */
-BOOL winbindd_fetch_group_cache_entry(char *domain_name, char *group,
- struct winbindd_gr *gr,
- void **extra_data, int *extra_data_len)
+/* Lookup user information from a rid */
+static NTSTATUS query_user(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ DOM_SID *user_sid,
+ WINBIND_USERINFO *info)
{
- TDB_DATA data;
- fstring keystr;
- uint32 seq_num;
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+ fstring sid_string;
- if (lp_winbind_cache_time() == 0) return False;
+ if (!cache->tdb)
+ goto do_query;
- seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_GROUP,
- group);
+ centry = wcache_fetch(cache, domain, "U/%s", sid_to_string(sid_string, user_sid));
+ if (!centry)
+ goto do_query;
- if (cache_domain_expired(domain_name, seq_num)) return False;
+ info->acct_name = centry_string(centry, mem_ctx);
+ info->full_name = centry_string(centry, mem_ctx);
+ info->user_sid = centry_sid(centry, mem_ctx);
+ info->group_sid = centry_sid(centry, mem_ctx);
+ status = centry->status;
- /* Fetch group data */
- if (!fetch_cache_entry(domain_name, CACHE_TYPE_GROUP, group, gr,
- sizeof(struct winbindd_gr))) {
- return False;
+ DEBUG(10,("query_user: [Cached] - cached info for domain %s status %s\n",
+ domain->name, get_friendly_nt_error_msg(status) ));
+
+ centry_free(centry);
+ return status;
+
+do_query:
+ ZERO_STRUCTP(info);
+
+ if (wcache_server_down(domain)) {
+ return NT_STATUS_SERVER_DISABLED;
}
- /* Fetch extra data */
- snprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP,
- domain_name, group);
+ DEBUG(10,("sid_to_name: [Cached] - doing backend query for info for domain %s\n",
+ domain->name ));
- data = tdb_fetch_by_string(cache_tdb, keystr);
+ status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
- if (!data.dptr) return False;
+ /* and save it */
+ refresh_sequence_number(domain, False);
+ wcache_save_user(domain, status, info);
- /* Extra data freed when data has been sent */
- if (extra_data) *extra_data = data.dptr;
- if (extra_data_len) *extra_data_len = data.dsize;
-
- return True;
+ return status;
}
-/* Fetch an individual gid cache entry. This function differs from the
- user cache code as we need to store the group membership data. */
+/* Lookup groups a user is a member of. */
+static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ DOM_SID *user_sid,
+ uint32 *num_groups, DOM_SID ***user_gids)
+{
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+ unsigned int i;
+ fstring sid_string;
+
+ if (!cache->tdb)
+ goto do_query;
+
+ centry = wcache_fetch(cache, domain, "UG/%s", sid_to_string(sid_string, user_sid));
+ if (!centry)
+ goto do_query;
+
+ *num_groups = centry_uint32(centry);
+
+ if (*num_groups == 0)
+ goto do_cached;
+
+ (*user_gids) = talloc(mem_ctx, sizeof(**user_gids) * (*num_groups));
+ if (! (*user_gids))
+ smb_panic("lookup_usergroups out of memory");
+ for (i=0; i<(*num_groups); i++) {
+ (*user_gids)[i] = centry_sid(centry, mem_ctx);
+ }
+
+do_cached:
+ status = centry->status;
+
+ DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status %s\n",
+ domain->name, get_friendly_nt_error_msg(status) ));
+
+ centry_free(centry);
+ return status;
+
+do_query:
+ (*num_groups) = 0;
+ (*user_gids) = NULL;
+
+ if (wcache_server_down(domain)) {
+ return NT_STATUS_SERVER_DISABLED;
+ }
+
+ DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
+ domain->name ));
+
+ status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
+
+ /* and save it */
+ refresh_sequence_number(domain, False);
+ centry = centry_start(domain, status);
+ if (!centry)
+ goto skip_save;
+ centry_put_uint32(centry, *num_groups);
+ for (i=0; i<(*num_groups); i++) {
+ centry_put_sid(centry, (*user_gids)[i]);
+ }
+ centry_end(centry, "UG/%s", sid_to_string(sid_string, user_sid));
+ centry_free(centry);
+
+skip_save:
+ return status;
+}
+
-BOOL winbindd_fetch_gid_cache_entry(char *domain_name, gid_t gid,
- struct winbindd_gr *gr,
- void **extra_data, int *extra_data_len)
+static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ DOM_SID *group_sid, uint32 *num_names,
+ DOM_SID ***sid_mem, char ***names,
+ uint32 **name_types)
{
- TDB_DATA data;
- fstring keystr;
- fstring gidstr;
- uint32 seq_num;
+ struct winbind_cache *cache = get_cache(domain);
+ struct cache_entry *centry = NULL;
+ NTSTATUS status;
+ unsigned int i;
+ fstring sid_string;
- snprintf(gidstr, sizeof(gidstr), "#%u", (unsigned)gid);
+ if (!cache->tdb)
+ goto do_query;
+
+ centry = wcache_fetch(cache, domain, "GM/%s", sid_to_string(sid_string, group_sid));
+ if (!centry)
+ goto do_query;
+
+ *num_names = centry_uint32(centry);
- if (lp_winbind_cache_time() == 0) return False;
+ if (*num_names == 0)
+ goto do_cached;
- seq_num = get_cache_sequence_number(domain_name, CACHE_TYPE_GROUP,
- gidstr);
+ (*sid_mem) = talloc(mem_ctx, sizeof(**sid_mem) * (*num_names));
+ (*names) = talloc(mem_ctx, sizeof(**names) * (*num_names));
+ (*name_types) = talloc(mem_ctx, sizeof(**name_types) * (*num_names));
- if (cache_domain_expired(domain_name, seq_num)) return False;
+ if (! (*sid_mem) || ! (*names) || ! (*name_types)) {
+ smb_panic("lookup_groupmem out of memory");
+ }
- /* Fetch group data */
- if (!fetch_cache_entry(domain_name, CACHE_TYPE_GROUP,
- gidstr, gr, sizeof(struct winbindd_gr))) {
- return False;
+ for (i=0; i<(*num_names); i++) {
+ (*sid_mem)[i] = centry_sid(centry, mem_ctx);
+ (*names)[i] = centry_string(centry, mem_ctx);
+ (*name_types)[i] = centry_uint32(centry);
}
- /* Fetch extra data */
- snprintf(keystr, sizeof(keystr), "%s/%s/%s DATA", CACHE_TYPE_GROUP,
- domain_name, gidstr);
- data = tdb_fetch_by_string(cache_tdb, keystr);
- if (!data.dptr) return False;
+do_cached:
+ status = centry->status;
- /* Extra data freed when data has been sent */
- if (extra_data) *extra_data = data.dptr;
- if (extra_data_len) *extra_data_len = data.dsize;
+ DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status %s\n",
+ domain->name, get_friendly_nt_error_msg(status) ));
- return True;
+ centry_free(centry);
+ return status;
+
+do_query:
+ (*num_names) = 0;
+ (*sid_mem) = NULL;
+ (*names) = NULL;
+ (*name_types) = NULL;
+
+
+ if (wcache_server_down(domain)) {
+ return NT_STATUS_SERVER_DISABLED;
+ }
+
+ DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
+ domain->name ));
+
+ status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid, num_names,
+ sid_mem, names, name_types);
+
+ /* and save it */
+ refresh_sequence_number(domain, False);
+ centry = centry_start(domain, status);
+ if (!centry)
+ goto skip_save;
+ centry_put_uint32(centry, *num_names);
+ for (i=0; i<(*num_names); i++) {
+ centry_put_sid(centry, (*sid_mem)[i]);
+ centry_put_string(centry, (*names)[i]);
+ centry_put_uint32(centry, (*name_types)[i]);
+ }
+ centry_end(centry, "GM/%s", sid_to_string(sid_string, group_sid));
+ centry_free(centry);
+
+skip_save:
+ return status;
+}
+
+/* find the sequence number for a domain */
+static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
+{
+ refresh_sequence_number(domain, False);
+
+ *seq = domain->sequence_number;
+
+ return NT_STATUS_OK;
}
-/* Flush cache data - easiest to just reopen the tdb */
-void winbindd_flush_cache(void)
+/* enumerate trusted domains */
+static NTSTATUS trusted_domains(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ uint32 *num_domains,
+ char ***names,
+ char ***alt_names,
+ DOM_SID **dom_sids)
{
- tdb_close(cache_tdb);
- winbindd_cache_init();
+ get_cache(domain);
+
+ DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
+ domain->name ));
+
+ /* we don't cache this call */
+ return domain->backend->trusted_domains(domain, mem_ctx, num_domains,
+ names, alt_names, dom_sids);
}
-/* Print cache status information */
-void winbindd_cache_dump_status(void)
+/* find the domain sid */
+static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
{
+ get_cache(domain);
+
+ DEBUG(10,("domain_sid: [Cached] - doing backend query for info for domain %s\n",
+ domain->name ));
+
+ /* we don't cache this call */
+ return domain->backend->domain_sid(domain, sid);
}
+
+/* find the alternate names for the domain, if any */
+static NTSTATUS alternate_name(struct winbindd_domain *domain)
+{
+ get_cache(domain);
+
+ DEBUG(10,("alternate_name: [Cached] - doing backend query for info for domain %s\n",
+ domain->name ));
+
+ /* we don't cache this call */
+ return domain->backend->alternate_name(domain);
+}
+
+/* the ADS 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,
+ query_user,
+ lookup_usergroups,
+ lookup_groupmem,
+ sequence_number,
+ trusted_domains,
+ domain_sid,
+ alternate_name
+};