r17143: svn merge -r17091:17138 ../SAMBA_3_0_23/
[Samba.git] / source / nsswitch / winbindd_cache.c
blobb267a3f770517425e3e2fe8ae73824038b1de58f
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind cache backend functions
6 Copyright (C) Andrew Tridgell 2001
7 Copyright (C) Gerald Carter 2003
8 Copyright (C) Volker Lendecke 2005
9 Copyright (C) Guenther Deschner 2005
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include "includes.h"
27 #include "winbindd.h"
29 #undef DBGC_CLASS
30 #define DBGC_CLASS DBGC_WINBIND
32 /* Global online/offline state - False when online. winbindd starts up online
33 and sets this to true if the first query fails and there's an entry in
34 the cache tdb telling us to stay offline. */
36 static BOOL global_winbindd_offline_state;
38 struct winbind_cache {
39 TDB_CONTEXT *tdb;
42 struct cache_entry {
43 NTSTATUS status;
44 uint32 sequence_number;
45 uint8 *data;
46 uint32 len, ofs;
49 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
51 static struct winbind_cache *wcache;
53 void winbindd_check_cache_size(time_t t)
55 static time_t last_check_time;
56 struct stat st;
58 if (last_check_time == (time_t)0)
59 last_check_time = t;
61 if (t - last_check_time < 60 && t - last_check_time > 0)
62 return;
64 if (wcache == NULL || wcache->tdb == NULL) {
65 DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
66 return;
69 if (fstat(wcache->tdb->fd, &st) == -1) {
70 DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno) ));
71 return;
74 if (st.st_size > WINBINDD_MAX_CACHE_SIZE) {
75 DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
76 (unsigned long)st.st_size,
77 (unsigned long)WINBINDD_MAX_CACHE_SIZE));
78 wcache_flush_cache();
82 /* get the winbind_cache structure */
83 static struct winbind_cache *get_cache(struct winbindd_domain *domain)
85 struct winbind_cache *ret = wcache;
86 #ifdef HAVE_ADS
87 struct winbindd_domain *our_domain = domain;
88 #endif
90 /* we have to know what type of domain we are dealing with first */
92 if ( !domain->initialized )
93 set_dc_type_and_flags( domain );
95 /*
96 OK. listen up becasue I'm only going to say this once.
97 We have the following scenarios to consider
98 (a) trusted AD domains on a Samba DC,
99 (b) trusted AD domains and we are joined to a non-kerberos domain
100 (c) trusted AD domains and we are joined to a kerberos (AD) domain
102 For (a) we can always contact the trusted domain using krb5
103 since we have the domain trust account password
105 For (b) we can only use RPC since we have no way of
106 getting a krb5 ticket in our own domain
108 For (c) we can always use krb5 since we have a kerberos trust
110 --jerry
113 if (!domain->backend) {
114 extern struct winbindd_methods reconnect_methods;
115 #ifdef HAVE_ADS
116 extern struct winbindd_methods ads_methods;
118 /* find our domain first so we can figure out if we
119 are joined to a kerberized domain */
121 if ( !domain->primary )
122 our_domain = find_our_domain();
124 if ( (our_domain->active_directory || IS_DC) && domain->active_directory ) {
125 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain->name));
126 domain->backend = &ads_methods;
127 } else {
128 #endif /* HAVE_ADS */
129 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain->name));
130 domain->backend = &reconnect_methods;
131 #ifdef HAVE_ADS
133 #endif /* HAVE_ADS */
136 if (ret)
137 return ret;
139 ret = SMB_XMALLOC_P(struct winbind_cache);
140 ZERO_STRUCTP(ret);
142 wcache = ret;
143 wcache_flush_cache();
145 return ret;
149 free a centry structure
151 static void centry_free(struct cache_entry *centry)
153 if (!centry)
154 return;
155 SAFE_FREE(centry->data);
156 free(centry);
160 pull a uint32 from a cache entry
162 static uint32 centry_uint32(struct cache_entry *centry)
164 uint32 ret;
165 if (centry->len - centry->ofs < 4) {
166 DEBUG(0,("centry corruption? needed 4 bytes, have %d\n",
167 centry->len - centry->ofs));
168 smb_panic("centry_uint32");
170 ret = IVAL(centry->data, centry->ofs);
171 centry->ofs += 4;
172 return ret;
176 pull a uint16 from a cache entry
178 static uint16 centry_uint16(struct cache_entry *centry)
180 uint16 ret;
181 if (centry->len - centry->ofs < 2) {
182 DEBUG(0,("centry corruption? needed 2 bytes, have %d\n",
183 centry->len - centry->ofs));
184 smb_panic("centry_uint16");
186 ret = CVAL(centry->data, centry->ofs);
187 centry->ofs += 2;
188 return ret;
192 pull a uint8 from a cache entry
194 static uint8 centry_uint8(struct cache_entry *centry)
196 uint8 ret;
197 if (centry->len - centry->ofs < 1) {
198 DEBUG(0,("centry corruption? needed 1 bytes, have %d\n",
199 centry->len - centry->ofs));
200 smb_panic("centry_uint32");
202 ret = CVAL(centry->data, centry->ofs);
203 centry->ofs += 1;
204 return ret;
208 pull a NTTIME from a cache entry
210 static NTTIME centry_nttime(struct cache_entry *centry)
212 NTTIME ret;
213 if (centry->len - centry->ofs < 8) {
214 DEBUG(0,("centry corruption? needed 8 bytes, have %d\n",
215 centry->len - centry->ofs));
216 smb_panic("centry_nttime");
218 ret.low = IVAL(centry->data, centry->ofs);
219 centry->ofs += 4;
220 ret.high = IVAL(centry->data, centry->ofs);
221 centry->ofs += 4;
222 return ret;
226 pull a time_t from a cache entry
228 static time_t centry_time(struct cache_entry *centry)
230 time_t ret;
231 if (centry->len - centry->ofs < sizeof(time_t)) {
232 DEBUG(0,("centry corruption? needed %u bytes, have %u\n",
233 (unsigned int)sizeof(time_t), (unsigned int)(centry->len - centry->ofs)));
234 smb_panic("centry_time");
236 ret = IVAL(centry->data, centry->ofs); /* FIXME: correct ? */
237 centry->ofs += sizeof(time_t);
238 return ret;
241 /* pull a string from a cache entry, using the supplied
242 talloc context
244 static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
246 uint32 len;
247 char *ret;
249 len = centry_uint8(centry);
251 if (len == 0xFF) {
252 /* a deliberate NULL string */
253 return NULL;
256 if (centry->len - centry->ofs < len) {
257 DEBUG(0,("centry corruption? needed %d bytes, have %d\n",
258 len, centry->len - centry->ofs));
259 smb_panic("centry_string");
262 ret = TALLOC(mem_ctx, len+1);
263 if (!ret) {
264 smb_panic("centry_string out of memory\n");
266 memcpy(ret,centry->data + centry->ofs, len);
267 ret[len] = 0;
268 centry->ofs += len;
269 return ret;
272 /* pull a string from a cache entry, using the supplied
273 talloc context
275 static BOOL centry_sid(struct cache_entry *centry, TALLOC_CTX *mem_ctx, DOM_SID *sid)
277 char *sid_string;
278 sid_string = centry_string(centry, mem_ctx);
279 if ((sid_string == NULL) || (!string_to_sid(sid, sid_string))) {
280 return False;
282 return True;
285 /* the server is considered down if it can't give us a sequence number */
286 static BOOL wcache_server_down(struct winbindd_domain *domain)
288 BOOL ret;
290 if (!wcache->tdb)
291 return False;
293 ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
295 if (ret)
296 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
297 domain->name ));
298 return ret;
301 static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
303 TDB_DATA data;
304 fstring key;
305 uint32 time_diff;
307 if (!wcache->tdb) {
308 DEBUG(10,("fetch_cache_seqnum: tdb == NULL\n"));
309 return NT_STATUS_UNSUCCESSFUL;
312 fstr_sprintf( key, "SEQNUM/%s", domain->name );
314 data = tdb_fetch_bystring( wcache->tdb, key );
315 if ( !data.dptr || data.dsize!=8 ) {
316 DEBUG(10,("fetch_cache_seqnum: invalid data size key [%s]\n", key ));
317 return NT_STATUS_UNSUCCESSFUL;
320 domain->sequence_number = IVAL(data.dptr, 0);
321 domain->last_seq_check = IVAL(data.dptr, 4);
323 SAFE_FREE(data.dptr);
325 /* have we expired? */
327 time_diff = now - domain->last_seq_check;
328 if ( time_diff > lp_winbind_cache_time() ) {
329 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
330 domain->name, domain->sequence_number,
331 (uint32)domain->last_seq_check));
332 return NT_STATUS_UNSUCCESSFUL;
335 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
336 domain->name, domain->sequence_number,
337 (uint32)domain->last_seq_check));
339 return NT_STATUS_OK;
342 static NTSTATUS store_cache_seqnum( struct winbindd_domain *domain )
344 TDB_DATA data, key;
345 fstring key_str;
346 char buf[8];
348 if (!wcache->tdb) {
349 DEBUG(10,("store_cache_seqnum: tdb == NULL\n"));
350 return NT_STATUS_UNSUCCESSFUL;
353 fstr_sprintf( key_str, "SEQNUM/%s", domain->name );
354 key.dptr = key_str;
355 key.dsize = strlen(key_str)+1;
357 SIVAL(buf, 0, domain->sequence_number);
358 SIVAL(buf, 4, domain->last_seq_check);
359 data.dptr = buf;
360 data.dsize = 8;
362 if ( tdb_store( wcache->tdb, key, data, TDB_REPLACE) == -1 ) {
363 DEBUG(10,("store_cache_seqnum: tdb_store fail key [%s]\n", key_str ));
364 return NT_STATUS_UNSUCCESSFUL;
367 DEBUG(10,("store_cache_seqnum: success [%s][%u @ %u]\n",
368 domain->name, domain->sequence_number,
369 (uint32)domain->last_seq_check));
371 return NT_STATUS_OK;
375 refresh the domain sequence number. If force is True
376 then always refresh it, no matter how recently we fetched it
379 static void refresh_sequence_number(struct winbindd_domain *domain, BOOL force)
381 NTSTATUS status;
382 unsigned time_diff;
383 time_t t = time(NULL);
384 unsigned cache_time = lp_winbind_cache_time();
386 get_cache( domain );
388 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
389 /* trying to reconnect is expensive, don't do it too often */
390 if (domain->sequence_number == DOM_SEQUENCE_NONE) {
391 cache_time *= 8;
393 #endif
395 time_diff = t - domain->last_seq_check;
397 /* see if we have to refetch the domain sequence number */
398 if (!force && (time_diff < cache_time)) {
399 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
400 goto done;
403 /* try to get the sequence number from the tdb cache first */
404 /* this will update the timestamp as well */
406 status = fetch_cache_seqnum( domain, t );
407 if ( NT_STATUS_IS_OK(status) )
408 goto done;
410 /* important! make sure that we know if this is a native
411 mode domain or not */
413 status = domain->backend->sequence_number(domain, &domain->sequence_number);
415 if (!NT_STATUS_IS_OK(status)) {
416 domain->sequence_number = DOM_SEQUENCE_NONE;
419 domain->last_status = status;
420 domain->last_seq_check = time(NULL);
422 /* save the new sequence number ni the cache */
423 store_cache_seqnum( domain );
425 done:
426 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
427 domain->name, domain->sequence_number));
429 return;
433 decide if a cache entry has expired
435 static BOOL centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
437 /* If we've been told to be offline - stay in that state... */
438 if (lp_winbind_offline_logon() && global_winbindd_offline_state) {
439 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
440 keystr, domain->name ));
441 return False;
444 /* when the domain is offline and we havent checked in the last 30
445 * seconds if it has become online again, return the cached entry.
446 * This deals with transient offline states... */
448 if (!domain->online &&
449 !NT_STATUS_IS_OK(check_negative_conn_cache(domain->name, domain->dcname))) {
450 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
451 keystr, domain->name ));
452 return False;
455 /* if the server is OK and our cache entry came from when it was down then
456 the entry is invalid */
457 if ((domain->sequence_number != DOM_SEQUENCE_NONE) &&
458 (centry->sequence_number == DOM_SEQUENCE_NONE)) {
459 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
460 keystr, domain->name ));
461 return True;
464 /* if the server is down or the cache entry is not older than the
465 current sequence number then it is OK */
466 if (wcache_server_down(domain) ||
467 centry->sequence_number == domain->sequence_number) {
468 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
469 keystr, domain->name ));
470 return False;
473 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
474 keystr, domain->name ));
476 /* it's expired */
477 return True;
480 static struct cache_entry *wcache_fetch_raw(char *kstr)
482 TDB_DATA data;
483 struct cache_entry *centry;
484 TDB_DATA key;
486 key.dptr = kstr;
487 key.dsize = strlen(kstr);
488 data = tdb_fetch(wcache->tdb, key);
489 if (!data.dptr) {
490 /* a cache miss */
491 return NULL;
494 centry = SMB_XMALLOC_P(struct cache_entry);
495 centry->data = (unsigned char *)data.dptr;
496 centry->len = data.dsize;
497 centry->ofs = 0;
499 if (centry->len < 8) {
500 /* huh? corrupt cache? */
501 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr));
502 centry_free(centry);
503 return NULL;
506 centry->status = NT_STATUS(centry_uint32(centry));
507 centry->sequence_number = centry_uint32(centry);
509 return centry;
513 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
514 number and return status
516 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
517 struct winbindd_domain *domain,
518 const char *format, ...) PRINTF_ATTRIBUTE(3,4);
519 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
520 struct winbindd_domain *domain,
521 const char *format, ...)
523 va_list ap;
524 char *kstr;
525 struct cache_entry *centry;
527 extern BOOL opt_nocache;
529 if (opt_nocache) {
530 return NULL;
533 refresh_sequence_number(domain, False);
535 va_start(ap, format);
536 smb_xvasprintf(&kstr, format, ap);
537 va_end(ap);
539 centry = wcache_fetch_raw(kstr);
540 if (centry == NULL) {
541 free(kstr);
542 return NULL;
545 if (centry_expired(domain, kstr, centry)) {
547 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
548 kstr, domain->name ));
550 centry_free(centry);
551 free(kstr);
552 return NULL;
555 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
556 kstr, domain->name ));
558 free(kstr);
559 return centry;
563 make sure we have at least len bytes available in a centry
565 static void centry_expand(struct cache_entry *centry, uint32 len)
567 if (centry->len - centry->ofs >= len)
568 return;
569 centry->len *= 2;
570 centry->data = SMB_REALLOC(centry->data, centry->len);
571 if (!centry->data) {
572 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
573 smb_panic("out of memory in centry_expand");
578 push a uint32 into a centry
580 static void centry_put_uint32(struct cache_entry *centry, uint32 v)
582 centry_expand(centry, 4);
583 SIVAL(centry->data, centry->ofs, v);
584 centry->ofs += 4;
588 push a uint16 into a centry
590 static void centry_put_uint16(struct cache_entry *centry, uint16 v)
592 centry_expand(centry, 2);
593 SIVAL(centry->data, centry->ofs, v);
594 centry->ofs += 2;
598 push a uint8 into a centry
600 static void centry_put_uint8(struct cache_entry *centry, uint8 v)
602 centry_expand(centry, 1);
603 SCVAL(centry->data, centry->ofs, v);
604 centry->ofs += 1;
608 push a string into a centry
610 static void centry_put_string(struct cache_entry *centry, const char *s)
612 int len;
614 if (!s) {
615 /* null strings are marked as len 0xFFFF */
616 centry_put_uint8(centry, 0xFF);
617 return;
620 len = strlen(s);
621 /* can't handle more than 254 char strings. Truncating is probably best */
622 if (len > 254) {
623 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len));
624 len = 254;
626 centry_put_uint8(centry, len);
627 centry_expand(centry, len);
628 memcpy(centry->data + centry->ofs, s, len);
629 centry->ofs += len;
632 static void centry_put_sid(struct cache_entry *centry, const DOM_SID *sid)
634 fstring sid_string;
635 centry_put_string(centry, sid_to_string(sid_string, sid));
639 push a NTTIME into a centry
641 static void centry_put_nttime(struct cache_entry *centry, NTTIME nt)
643 centry_expand(centry, 8);
644 SIVAL(centry->data, centry->ofs, nt.low);
645 centry->ofs += 4;
646 SIVAL(centry->data, centry->ofs, nt.high);
647 centry->ofs += 4;
651 push a time_t into a centry
653 static void centry_put_time(struct cache_entry *centry, time_t t)
655 centry_expand(centry, sizeof(time_t));
656 SIVAL(centry->data, centry->ofs, t); /* FIXME: is this correct ?? */
657 centry->ofs += sizeof(time_t);
661 start a centry for output. When finished, call centry_end()
663 struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status)
665 struct cache_entry *centry;
667 if (!wcache->tdb)
668 return NULL;
670 centry = SMB_XMALLOC_P(struct cache_entry);
672 centry->len = 8192; /* reasonable default */
673 centry->data = SMB_XMALLOC_ARRAY(uint8, centry->len);
674 centry->ofs = 0;
675 centry->sequence_number = domain->sequence_number;
676 centry_put_uint32(centry, NT_STATUS_V(status));
677 centry_put_uint32(centry, centry->sequence_number);
678 return centry;
682 finish a centry and write it to the tdb
684 static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
685 static void centry_end(struct cache_entry *centry, const char *format, ...)
687 va_list ap;
688 char *kstr;
689 TDB_DATA key, data;
691 va_start(ap, format);
692 smb_xvasprintf(&kstr, format, ap);
693 va_end(ap);
695 key.dptr = kstr;
696 key.dsize = strlen(kstr);
697 data.dptr = (char *)centry->data;
698 data.dsize = centry->ofs;
700 tdb_store(wcache->tdb, key, data, TDB_REPLACE);
701 free(kstr);
704 static void wcache_save_name_to_sid(struct winbindd_domain *domain,
705 NTSTATUS status, const char *domain_name,
706 const char *name, const DOM_SID *sid,
707 enum SID_NAME_USE type)
709 struct cache_entry *centry;
710 fstring uname;
712 centry = centry_start(domain, status);
713 if (!centry)
714 return;
715 centry_put_uint32(centry, type);
716 centry_put_sid(centry, sid);
717 fstrcpy(uname, name);
718 strupper_m(uname);
719 centry_end(centry, "NS/%s/%s", domain_name, uname);
720 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s\n", domain_name, uname,
721 sid_string_static(sid)));
722 centry_free(centry);
725 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
726 const DOM_SID *sid, const char *domain_name, const char *name, enum SID_NAME_USE type)
728 struct cache_entry *centry;
729 fstring sid_string;
731 centry = centry_start(domain, status);
732 if (!centry)
733 return;
734 if (NT_STATUS_IS_OK(status)) {
735 centry_put_uint32(centry, type);
736 centry_put_string(centry, domain_name);
737 centry_put_string(centry, name);
739 centry_end(centry, "SN/%s", sid_to_string(sid_string, sid));
740 DEBUG(10,("wcache_save_sid_to_name: %s -> %s\n", sid_string, name));
741 centry_free(centry);
745 static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status, WINBIND_USERINFO *info)
747 struct cache_entry *centry;
748 fstring sid_string;
750 centry = centry_start(domain, status);
751 if (!centry)
752 return;
753 centry_put_string(centry, info->acct_name);
754 centry_put_string(centry, info->full_name);
755 centry_put_string(centry, info->homedir);
756 centry_put_string(centry, info->shell);
757 centry_put_sid(centry, &info->user_sid);
758 centry_put_sid(centry, &info->group_sid);
759 centry_end(centry, "U/%s", sid_to_string(sid_string, &info->user_sid));
760 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
761 centry_free(centry);
764 static void wcache_save_lockout_policy(struct winbindd_domain *domain, NTSTATUS status, SAM_UNK_INFO_12 *lockout_policy)
766 struct cache_entry *centry;
768 centry = centry_start(domain, status);
769 if (!centry)
770 return;
772 centry_put_nttime(centry, lockout_policy->duration);
773 centry_put_nttime(centry, lockout_policy->reset_count);
774 centry_put_uint16(centry, lockout_policy->bad_attempt_lockout);
776 centry_end(centry, "LOC_POL/%s", domain->name);
778 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
780 centry_free(centry);
783 static void wcache_save_password_policy(struct winbindd_domain *domain, NTSTATUS status, SAM_UNK_INFO_1 *policy)
785 struct cache_entry *centry;
787 centry = centry_start(domain, status);
788 if (!centry)
789 return;
791 centry_put_uint16(centry, policy->min_length_password);
792 centry_put_uint16(centry, policy->password_history);
793 centry_put_uint32(centry, policy->password_properties);
794 centry_put_nttime(centry, policy->expire);
795 centry_put_nttime(centry, policy->min_passwordage);
797 centry_end(centry, "PWD_POL/%s", domain->name);
799 DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
801 centry_free(centry);
804 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const DOM_SID *sid)
806 struct winbind_cache *cache = get_cache(domain);
807 TDB_DATA data;
808 fstring key_str;
809 uint32 rid;
811 if (!cache->tdb) {
812 return NT_STATUS_INTERNAL_DB_ERROR;
815 if (is_null_sid(sid)) {
816 return NT_STATUS_INVALID_SID;
819 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
820 return NT_STATUS_INVALID_SID;
823 fstr_sprintf(key_str, "CRED/%s", sid_string_static(sid));
825 data = tdb_fetch(cache->tdb, make_tdb_data(key_str, strlen(key_str)));
826 if (!data.dptr) {
827 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
830 SAFE_FREE(data.dptr);
831 return NT_STATUS_OK;
834 /* Lookup creds for a SID */
835 NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
836 TALLOC_CTX *mem_ctx,
837 const DOM_SID *sid,
838 const uint8 **cached_nt_pass)
840 struct winbind_cache *cache = get_cache(domain);
841 struct cache_entry *centry = NULL;
842 NTSTATUS status;
843 time_t t;
844 uint32 rid;
846 if (!cache->tdb) {
847 return NT_STATUS_INTERNAL_DB_ERROR;
850 if (is_null_sid(sid)) {
851 return NT_STATUS_INVALID_SID;
854 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
855 return NT_STATUS_INVALID_SID;
858 centry = wcache_fetch(cache, domain, "CRED/%s", sid_string_static(sid));
860 if (!centry) {
861 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
862 sid_string_static(sid)));
863 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
866 t = centry_time(centry);
867 *cached_nt_pass = (const uint8 *)centry_string(centry, mem_ctx);
869 #if DEBUG_PASSWORD
870 dump_data(100, (const char *)cached_nt_pass, NT_HASH_LEN);
871 #endif
872 status = centry->status;
874 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
875 sid_string_static(sid), nt_errstr(status) ));
877 centry_free(centry);
878 return status;
881 NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
882 TALLOC_CTX *mem_ctx,
883 const DOM_SID *sid,
884 const uint8 nt_pass[NT_HASH_LEN])
886 struct cache_entry *centry;
887 fstring sid_string;
888 uint32 rid;
890 if (is_null_sid(sid)) {
891 return NT_STATUS_INVALID_SID;
894 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
895 return NT_STATUS_INVALID_SID;
898 centry = centry_start(domain, NT_STATUS_OK);
899 if (!centry) {
900 return NT_STATUS_INTERNAL_DB_ERROR;
903 #if DEBUG_PASSWORD
904 dump_data(100, (const char *)nt_pass, NT_HASH_LEN);
905 #endif
907 centry_put_time(centry, time(NULL));
908 centry_put_string(centry, (const char *)nt_pass);
909 centry_end(centry, "CRED/%s", sid_to_string(sid_string, sid));
911 DEBUG(10,("wcache_save_creds: %s\n", sid_string));
913 centry_free(centry);
915 return NT_STATUS_OK;
919 /* Query display info. This is the basic user list fn */
920 static NTSTATUS query_user_list(struct winbindd_domain *domain,
921 TALLOC_CTX *mem_ctx,
922 uint32 *num_entries,
923 WINBIND_USERINFO **info)
925 struct winbind_cache *cache = get_cache(domain);
926 struct cache_entry *centry = NULL;
927 NTSTATUS status;
928 unsigned int i, retry;
930 if (!cache->tdb)
931 goto do_query;
933 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
934 if (!centry)
935 goto do_query;
937 *num_entries = centry_uint32(centry);
939 if (*num_entries == 0)
940 goto do_cached;
942 (*info) = TALLOC_ARRAY(mem_ctx, WINBIND_USERINFO, *num_entries);
943 if (! (*info))
944 smb_panic("query_user_list out of memory");
945 for (i=0; i<(*num_entries); i++) {
946 (*info)[i].acct_name = centry_string(centry, mem_ctx);
947 (*info)[i].full_name = centry_string(centry, mem_ctx);
948 (*info)[i].homedir = centry_string(centry, mem_ctx);
949 (*info)[i].shell = centry_string(centry, mem_ctx);
950 centry_sid(centry, mem_ctx, &(*info)[i].user_sid);
951 centry_sid(centry, mem_ctx, &(*info)[i].group_sid);
954 do_cached:
955 status = centry->status;
957 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
958 domain->name, nt_errstr(status) ));
960 centry_free(centry);
961 return status;
963 do_query:
964 *num_entries = 0;
965 *info = NULL;
967 /* Return status value returned by seq number check */
969 if (!NT_STATUS_IS_OK(domain->last_status))
970 return domain->last_status;
972 /* Put the query_user_list() in a retry loop. There appears to be
973 * some bug either with Windows 2000 or Samba's handling of large
974 * rpc replies. This manifests itself as sudden disconnection
975 * at a random point in the enumeration of a large (60k) user list.
976 * The retry loop simply tries the operation again. )-: It's not
977 * pretty but an acceptable workaround until we work out what the
978 * real problem is. */
980 retry = 0;
981 do {
983 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
984 domain->name ));
986 status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
987 if (!NT_STATUS_IS_OK(status))
988 DEBUG(3, ("query_user_list: returned 0x%08x, "
989 "retrying\n", NT_STATUS_V(status)));
990 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
991 DEBUG(3, ("query_user_list: flushing "
992 "connection cache\n"));
993 invalidate_cm_connection(&domain->conn);
996 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
997 (retry++ < 5));
999 /* and save it */
1000 refresh_sequence_number(domain, False);
1001 centry = centry_start(domain, status);
1002 if (!centry)
1003 goto skip_save;
1004 centry_put_uint32(centry, *num_entries);
1005 for (i=0; i<(*num_entries); i++) {
1006 centry_put_string(centry, (*info)[i].acct_name);
1007 centry_put_string(centry, (*info)[i].full_name);
1008 centry_put_string(centry, (*info)[i].homedir);
1009 centry_put_string(centry, (*info)[i].shell);
1010 centry_put_sid(centry, &(*info)[i].user_sid);
1011 centry_put_sid(centry, &(*info)[i].group_sid);
1012 if (domain->backend->consistent) {
1013 /* when the backend is consistent we can pre-prime some mappings */
1014 wcache_save_name_to_sid(domain, NT_STATUS_OK,
1015 domain->name,
1016 (*info)[i].acct_name,
1017 &(*info)[i].user_sid,
1018 SID_NAME_USER);
1019 wcache_save_sid_to_name(domain, NT_STATUS_OK,
1020 &(*info)[i].user_sid,
1021 domain->name,
1022 (*info)[i].acct_name,
1023 SID_NAME_USER);
1024 wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
1027 centry_end(centry, "UL/%s", domain->name);
1028 centry_free(centry);
1030 skip_save:
1031 return status;
1034 /* list all domain groups */
1035 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
1036 TALLOC_CTX *mem_ctx,
1037 uint32 *num_entries,
1038 struct acct_info **info)
1040 struct winbind_cache *cache = get_cache(domain);
1041 struct cache_entry *centry = NULL;
1042 NTSTATUS status;
1043 unsigned int i;
1045 if (!cache->tdb)
1046 goto do_query;
1048 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1049 if (!centry)
1050 goto do_query;
1052 *num_entries = centry_uint32(centry);
1054 if (*num_entries == 0)
1055 goto do_cached;
1057 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1058 if (! (*info))
1059 smb_panic("enum_dom_groups out of memory");
1060 for (i=0; i<(*num_entries); i++) {
1061 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1062 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1063 (*info)[i].rid = centry_uint32(centry);
1066 do_cached:
1067 status = centry->status;
1069 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1070 domain->name, nt_errstr(status) ));
1072 centry_free(centry);
1073 return status;
1075 do_query:
1076 *num_entries = 0;
1077 *info = NULL;
1079 /* Return status value returned by seq number check */
1081 if (!NT_STATUS_IS_OK(domain->last_status))
1082 return domain->last_status;
1084 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1085 domain->name ));
1087 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1089 /* and save it */
1090 refresh_sequence_number(domain, False);
1091 centry = centry_start(domain, status);
1092 if (!centry)
1093 goto skip_save;
1094 centry_put_uint32(centry, *num_entries);
1095 for (i=0; i<(*num_entries); i++) {
1096 centry_put_string(centry, (*info)[i].acct_name);
1097 centry_put_string(centry, (*info)[i].acct_desc);
1098 centry_put_uint32(centry, (*info)[i].rid);
1100 centry_end(centry, "GL/%s/domain", domain->name);
1101 centry_free(centry);
1103 skip_save:
1104 return status;
1107 /* list all domain groups */
1108 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
1109 TALLOC_CTX *mem_ctx,
1110 uint32 *num_entries,
1111 struct acct_info **info)
1113 struct winbind_cache *cache = get_cache(domain);
1114 struct cache_entry *centry = NULL;
1115 NTSTATUS status;
1116 unsigned int i;
1118 if (!cache->tdb)
1119 goto do_query;
1121 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1122 if (!centry)
1123 goto do_query;
1125 *num_entries = centry_uint32(centry);
1127 if (*num_entries == 0)
1128 goto do_cached;
1130 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1131 if (! (*info))
1132 smb_panic("enum_dom_groups out of memory");
1133 for (i=0; i<(*num_entries); i++) {
1134 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1135 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1136 (*info)[i].rid = centry_uint32(centry);
1139 do_cached:
1141 /* If we are returning cached data and the domain controller
1142 is down then we don't know whether the data is up to date
1143 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1144 indicate this. */
1146 if (wcache_server_down(domain)) {
1147 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1148 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1149 } else
1150 status = centry->status;
1152 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1153 domain->name, nt_errstr(status) ));
1155 centry_free(centry);
1156 return status;
1158 do_query:
1159 *num_entries = 0;
1160 *info = NULL;
1162 /* Return status value returned by seq number check */
1164 if (!NT_STATUS_IS_OK(domain->last_status))
1165 return domain->last_status;
1167 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1168 domain->name ));
1170 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1172 /* and save it */
1173 refresh_sequence_number(domain, False);
1174 centry = centry_start(domain, status);
1175 if (!centry)
1176 goto skip_save;
1177 centry_put_uint32(centry, *num_entries);
1178 for (i=0; i<(*num_entries); i++) {
1179 centry_put_string(centry, (*info)[i].acct_name);
1180 centry_put_string(centry, (*info)[i].acct_desc);
1181 centry_put_uint32(centry, (*info)[i].rid);
1183 centry_end(centry, "GL/%s/local", domain->name);
1184 centry_free(centry);
1186 skip_save:
1187 return status;
1190 /* convert a single name to a sid in a domain */
1191 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
1192 TALLOC_CTX *mem_ctx,
1193 const char *domain_name,
1194 const char *name,
1195 DOM_SID *sid,
1196 enum SID_NAME_USE *type)
1198 struct winbind_cache *cache = get_cache(domain);
1199 struct cache_entry *centry = NULL;
1200 NTSTATUS status;
1201 fstring uname;
1203 if (!cache->tdb)
1204 goto do_query;
1206 fstrcpy(uname, name);
1207 strupper_m(uname);
1208 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1209 if (!centry)
1210 goto do_query;
1211 *type = (enum SID_NAME_USE)centry_uint32(centry);
1212 status = centry->status;
1213 if (NT_STATUS_IS_OK(status)) {
1214 centry_sid(centry, mem_ctx, sid);
1217 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: %s\n",
1218 domain->name, nt_errstr(status) ));
1220 centry_free(centry);
1221 return status;
1223 do_query:
1224 ZERO_STRUCTP(sid);
1226 /* If the seq number check indicated that there is a problem
1227 * with this DC, then return that status... except for
1228 * access_denied. This is special because the dc may be in
1229 * "restrict anonymous = 1" mode, in which case it will deny
1230 * most unauthenticated operations, but *will* allow the LSA
1231 * name-to-sid that we try as a fallback. */
1233 if (!(NT_STATUS_IS_OK(domain->last_status)
1234 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1235 return domain->last_status;
1237 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1238 domain->name ));
1240 status = domain->backend->name_to_sid(domain, mem_ctx, domain_name, name, sid, type);
1242 /* and save it */
1243 if (domain->online || !is_null_sid(sid)) {
1244 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1247 if (NT_STATUS_IS_OK(status)) {
1248 strupper_m(CONST_DISCARD(char *,domain_name));
1249 strlower_m(CONST_DISCARD(char *,name));
1250 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1253 return status;
1256 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1257 given */
1258 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
1259 TALLOC_CTX *mem_ctx,
1260 const DOM_SID *sid,
1261 char **domain_name,
1262 char **name,
1263 enum SID_NAME_USE *type)
1265 struct winbind_cache *cache = get_cache(domain);
1266 struct cache_entry *centry = NULL;
1267 NTSTATUS status;
1268 fstring sid_string;
1270 if (!cache->tdb)
1271 goto do_query;
1273 centry = wcache_fetch(cache, domain, "SN/%s", sid_to_string(sid_string, sid));
1274 if (!centry)
1275 goto do_query;
1276 if (NT_STATUS_IS_OK(centry->status)) {
1277 *type = (enum SID_NAME_USE)centry_uint32(centry);
1278 *domain_name = centry_string(centry, mem_ctx);
1279 *name = centry_string(centry, mem_ctx);
1281 status = centry->status;
1283 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: %s\n",
1284 domain->name, nt_errstr(status) ));
1286 centry_free(centry);
1287 return status;
1289 do_query:
1290 *name = NULL;
1291 *domain_name = NULL;
1293 /* If the seq number check indicated that there is a problem
1294 * with this DC, then return that status... except for
1295 * access_denied. This is special because the dc may be in
1296 * "restrict anonymous = 1" mode, in which case it will deny
1297 * most unauthenticated operations, but *will* allow the LSA
1298 * sid-to-name that we try as a fallback. */
1300 if (!(NT_STATUS_IS_OK(domain->last_status)
1301 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1302 return domain->last_status;
1304 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1305 domain->name ));
1307 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1309 /* and save it */
1310 refresh_sequence_number(domain, False);
1311 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1313 /* We can't save the name to sid mapping here, as with sid history a
1314 * later name2sid would give the wrong sid. */
1316 return status;
1319 /* Lookup user information from a rid */
1320 static NTSTATUS query_user(struct winbindd_domain *domain,
1321 TALLOC_CTX *mem_ctx,
1322 const DOM_SID *user_sid,
1323 WINBIND_USERINFO *info)
1325 struct winbind_cache *cache = get_cache(domain);
1326 struct cache_entry *centry = NULL;
1327 NTSTATUS status;
1329 if (!cache->tdb)
1330 goto do_query;
1332 centry = wcache_fetch(cache, domain, "U/%s", sid_string_static(user_sid));
1334 /* If we have an access denied cache entry and a cached info3 in the
1335 samlogon cache then do a query. This will force the rpc back end
1336 to return the info3 data. */
1338 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1339 netsamlogon_cache_have(user_sid)) {
1340 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1341 domain->last_status = NT_STATUS_OK;
1342 centry_free(centry);
1343 goto do_query;
1346 if (!centry)
1347 goto do_query;
1349 info->acct_name = centry_string(centry, mem_ctx);
1350 info->full_name = centry_string(centry, mem_ctx);
1351 info->homedir = centry_string(centry, mem_ctx);
1352 info->shell = centry_string(centry, mem_ctx);
1353 centry_sid(centry, mem_ctx, &info->user_sid);
1354 centry_sid(centry, mem_ctx, &info->group_sid);
1355 status = centry->status;
1357 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: %s\n",
1358 domain->name, nt_errstr(status) ));
1360 centry_free(centry);
1361 return status;
1363 do_query:
1364 ZERO_STRUCTP(info);
1366 /* Return status value returned by seq number check */
1368 if (!NT_STATUS_IS_OK(domain->last_status))
1369 return domain->last_status;
1371 DEBUG(10,("sid_to_name: [Cached] - doing backend query for info for domain %s\n",
1372 domain->name ));
1374 status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
1376 /* and save it */
1377 refresh_sequence_number(domain, False);
1378 wcache_save_user(domain, status, info);
1380 return status;
1384 /* Lookup groups a user is a member of. */
1385 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
1386 TALLOC_CTX *mem_ctx,
1387 const DOM_SID *user_sid,
1388 uint32 *num_groups, DOM_SID **user_gids)
1390 struct winbind_cache *cache = get_cache(domain);
1391 struct cache_entry *centry = NULL;
1392 NTSTATUS status;
1393 unsigned int i;
1394 fstring sid_string;
1396 if (!cache->tdb)
1397 goto do_query;
1399 centry = wcache_fetch(cache, domain, "UG/%s", sid_to_string(sid_string, user_sid));
1401 /* If we have an access denied cache entry and a cached info3 in the
1402 samlogon cache then do a query. This will force the rpc back end
1403 to return the info3 data. */
1405 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1406 netsamlogon_cache_have(user_sid)) {
1407 DEBUG(10, ("lookup_usergroups: cached access denied and have cached info3\n"));
1408 domain->last_status = NT_STATUS_OK;
1409 centry_free(centry);
1410 goto do_query;
1413 if (!centry)
1414 goto do_query;
1416 *num_groups = centry_uint32(centry);
1418 if (*num_groups == 0)
1419 goto do_cached;
1421 (*user_gids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
1422 if (! (*user_gids))
1423 smb_panic("lookup_usergroups out of memory");
1424 for (i=0; i<(*num_groups); i++) {
1425 centry_sid(centry, mem_ctx, &(*user_gids)[i]);
1428 do_cached:
1429 status = centry->status;
1431 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status: %s\n",
1432 domain->name, nt_errstr(status) ));
1434 centry_free(centry);
1435 return status;
1437 do_query:
1438 (*num_groups) = 0;
1439 (*user_gids) = NULL;
1441 /* Return status value returned by seq number check */
1443 if (!NT_STATUS_IS_OK(domain->last_status))
1444 return domain->last_status;
1446 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
1447 domain->name ));
1449 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
1451 /* and save it */
1452 refresh_sequence_number(domain, False);
1453 centry = centry_start(domain, status);
1454 if (!centry)
1455 goto skip_save;
1456 centry_put_uint32(centry, *num_groups);
1457 for (i=0; i<(*num_groups); i++) {
1458 centry_put_sid(centry, &(*user_gids)[i]);
1460 centry_end(centry, "UG/%s", sid_to_string(sid_string, user_sid));
1461 centry_free(centry);
1463 skip_save:
1464 return status;
1467 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
1468 TALLOC_CTX *mem_ctx,
1469 uint32 num_sids, const DOM_SID *sids,
1470 uint32 *num_aliases, uint32 **alias_rids)
1472 struct winbind_cache *cache = get_cache(domain);
1473 struct cache_entry *centry = NULL;
1474 NTSTATUS status;
1475 char *sidlist = talloc_strdup(mem_ctx, "");
1476 int i;
1478 if (!cache->tdb)
1479 goto do_query;
1481 if (num_sids == 0) {
1482 *num_aliases = 0;
1483 *alias_rids = NULL;
1484 return NT_STATUS_OK;
1487 /* We need to cache indexed by the whole list of SIDs, the aliases
1488 * resulting might come from any of the SIDs. */
1490 for (i=0; i<num_sids; i++) {
1491 sidlist = talloc_asprintf(mem_ctx, "%s/%s", sidlist,
1492 sid_string_static(&sids[i]));
1493 if (sidlist == NULL)
1494 return NT_STATUS_NO_MEMORY;
1497 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
1499 if (!centry)
1500 goto do_query;
1502 *num_aliases = centry_uint32(centry);
1503 *alias_rids = NULL;
1505 (*alias_rids) = TALLOC_ARRAY(mem_ctx, uint32, *num_aliases);
1507 if ((*num_aliases != 0) && ((*alias_rids) == NULL)) {
1508 centry_free(centry);
1509 return NT_STATUS_NO_MEMORY;
1512 for (i=0; i<(*num_aliases); i++)
1513 (*alias_rids)[i] = centry_uint32(centry);
1515 status = centry->status;
1517 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
1518 "status %s\n", domain->name, nt_errstr(status)));
1520 centry_free(centry);
1521 return status;
1523 do_query:
1524 (*num_aliases) = 0;
1525 (*alias_rids) = NULL;
1527 if (!NT_STATUS_IS_OK(domain->last_status))
1528 return domain->last_status;
1530 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
1531 "for domain %s\n", domain->name ));
1533 status = domain->backend->lookup_useraliases(domain, mem_ctx,
1534 num_sids, sids,
1535 num_aliases, alias_rids);
1537 /* and save it */
1538 refresh_sequence_number(domain, False);
1539 centry = centry_start(domain, status);
1540 if (!centry)
1541 goto skip_save;
1542 centry_put_uint32(centry, *num_aliases);
1543 for (i=0; i<(*num_aliases); i++)
1544 centry_put_uint32(centry, (*alias_rids)[i]);
1545 centry_end(centry, "UA%s", sidlist);
1546 centry_free(centry);
1548 skip_save:
1549 return status;
1553 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1554 TALLOC_CTX *mem_ctx,
1555 const DOM_SID *group_sid, uint32 *num_names,
1556 DOM_SID **sid_mem, char ***names,
1557 uint32 **name_types)
1559 struct winbind_cache *cache = get_cache(domain);
1560 struct cache_entry *centry = NULL;
1561 NTSTATUS status;
1562 unsigned int i;
1563 fstring sid_string;
1565 if (!cache->tdb)
1566 goto do_query;
1568 centry = wcache_fetch(cache, domain, "GM/%s", sid_to_string(sid_string, group_sid));
1569 if (!centry)
1570 goto do_query;
1572 *num_names = centry_uint32(centry);
1574 if (*num_names == 0)
1575 goto do_cached;
1577 (*sid_mem) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_names);
1578 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_names);
1579 (*name_types) = TALLOC_ARRAY(mem_ctx, uint32, *num_names);
1581 if (! (*sid_mem) || ! (*names) || ! (*name_types)) {
1582 smb_panic("lookup_groupmem out of memory");
1585 for (i=0; i<(*num_names); i++) {
1586 centry_sid(centry, mem_ctx, &(*sid_mem)[i]);
1587 (*names)[i] = centry_string(centry, mem_ctx);
1588 (*name_types)[i] = centry_uint32(centry);
1591 do_cached:
1592 status = centry->status;
1594 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status: %s\n",
1595 domain->name, nt_errstr(status)));
1597 centry_free(centry);
1598 return status;
1600 do_query:
1601 (*num_names) = 0;
1602 (*sid_mem) = NULL;
1603 (*names) = NULL;
1604 (*name_types) = NULL;
1606 /* Return status value returned by seq number check */
1608 if (!NT_STATUS_IS_OK(domain->last_status))
1609 return domain->last_status;
1611 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
1612 domain->name ));
1614 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid, num_names,
1615 sid_mem, names, name_types);
1617 /* and save it */
1618 refresh_sequence_number(domain, False);
1619 centry = centry_start(domain, status);
1620 if (!centry)
1621 goto skip_save;
1622 centry_put_uint32(centry, *num_names);
1623 for (i=0; i<(*num_names); i++) {
1624 centry_put_sid(centry, &(*sid_mem)[i]);
1625 centry_put_string(centry, (*names)[i]);
1626 centry_put_uint32(centry, (*name_types)[i]);
1628 centry_end(centry, "GM/%s", sid_to_string(sid_string, group_sid));
1629 centry_free(centry);
1631 skip_save:
1632 return status;
1635 /* find the sequence number for a domain */
1636 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
1638 refresh_sequence_number(domain, False);
1640 *seq = domain->sequence_number;
1642 return NT_STATUS_OK;
1645 /* enumerate trusted domains
1646 * (we need to have the list of trustdoms in the cache when we go offline) -
1647 * Guenther */
1648 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1649 TALLOC_CTX *mem_ctx,
1650 uint32 *num_domains,
1651 char ***names,
1652 char ***alt_names,
1653 DOM_SID **dom_sids)
1655 struct winbind_cache *cache = get_cache(domain);
1656 struct cache_entry *centry = NULL;
1657 NTSTATUS status;
1658 int i;
1660 if (!cache->tdb)
1661 goto do_query;
1663 centry = wcache_fetch(cache, domain, "TRUSTDOMS/%s", domain->name);
1665 if (!centry) {
1666 goto do_query;
1669 *num_domains = centry_uint32(centry);
1671 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
1672 (*alt_names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
1673 (*dom_sids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
1675 if (! (*dom_sids) || ! (*names) || ! (*alt_names)) {
1676 smb_panic("trusted_domains out of memory");
1679 for (i=0; i<(*num_domains); i++) {
1680 (*names)[i] = centry_string(centry, mem_ctx);
1681 (*alt_names)[i] = centry_string(centry, mem_ctx);
1682 centry_sid(centry, mem_ctx, &(*dom_sids)[i]);
1685 status = centry->status;
1687 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
1688 domain->name, *num_domains, nt_errstr(status) ));
1690 centry_free(centry);
1691 return status;
1693 do_query:
1694 (*num_domains) = 0;
1695 (*dom_sids) = NULL;
1696 (*names) = NULL;
1697 (*alt_names) = NULL;
1699 /* Return status value returned by seq number check */
1701 if (!NT_STATUS_IS_OK(domain->last_status))
1702 return domain->last_status;
1704 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
1705 domain->name ));
1707 status = domain->backend->trusted_domains(domain, mem_ctx, num_domains,
1708 names, alt_names, dom_sids);
1710 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
1711 * so that the generic centry handling still applies correctly -
1712 * Guenther*/
1714 if (!NT_STATUS_IS_ERR(status)) {
1715 status = NT_STATUS_OK;
1718 /* and save it */
1719 refresh_sequence_number(domain, False);
1721 centry = centry_start(domain, status);
1722 if (!centry)
1723 goto skip_save;
1725 centry_put_uint32(centry, *num_domains);
1727 for (i=0; i<(*num_domains); i++) {
1728 centry_put_string(centry, (*names)[i]);
1729 centry_put_string(centry, (*alt_names)[i]);
1730 centry_put_sid(centry, &(*dom_sids)[i]);
1733 centry_end(centry, "TRUSTDOMS/%s", domain->name);
1735 centry_free(centry);
1737 skip_save:
1738 return status;
1741 /* get lockout policy */
1742 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
1743 TALLOC_CTX *mem_ctx,
1744 SAM_UNK_INFO_12 *policy){
1745 struct winbind_cache *cache = get_cache(domain);
1746 struct cache_entry *centry = NULL;
1747 NTSTATUS status;
1749 if (!cache->tdb)
1750 goto do_query;
1752 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
1754 if (!centry)
1755 goto do_query;
1757 policy->duration = centry_nttime(centry);
1758 policy->reset_count = centry_nttime(centry);
1759 policy->bad_attempt_lockout = centry_uint16(centry);
1761 status = centry->status;
1763 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
1764 domain->name, nt_errstr(status) ));
1766 centry_free(centry);
1767 return status;
1769 do_query:
1770 ZERO_STRUCTP(policy);
1772 /* Return status value returned by seq number check */
1774 if (!NT_STATUS_IS_OK(domain->last_status))
1775 return domain->last_status;
1777 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
1778 domain->name ));
1780 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
1782 /* and save it */
1783 refresh_sequence_number(domain, False);
1784 wcache_save_lockout_policy(domain, status, policy);
1786 return status;
1789 /* get password policy */
1790 static NTSTATUS password_policy(struct winbindd_domain *domain,
1791 TALLOC_CTX *mem_ctx,
1792 SAM_UNK_INFO_1 *policy)
1794 struct winbind_cache *cache = get_cache(domain);
1795 struct cache_entry *centry = NULL;
1796 NTSTATUS status;
1798 if (!cache->tdb)
1799 goto do_query;
1801 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
1803 if (!centry)
1804 goto do_query;
1806 policy->min_length_password = centry_uint16(centry);
1807 policy->password_history = centry_uint16(centry);
1808 policy->password_properties = centry_uint32(centry);
1809 policy->expire = centry_nttime(centry);
1810 policy->min_passwordage = centry_nttime(centry);
1812 status = centry->status;
1814 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
1815 domain->name, nt_errstr(status) ));
1817 centry_free(centry);
1818 return status;
1820 do_query:
1821 ZERO_STRUCTP(policy);
1823 /* Return status value returned by seq number check */
1825 if (!NT_STATUS_IS_OK(domain->last_status))
1826 return domain->last_status;
1828 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
1829 domain->name ));
1831 status = domain->backend->password_policy(domain, mem_ctx, policy);
1833 /* and save it */
1834 refresh_sequence_number(domain, False);
1835 wcache_save_password_policy(domain, status, policy);
1837 return status;
1841 /* Invalidate cached user and group lists coherently */
1843 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
1844 void *state)
1846 if (strncmp(kbuf.dptr, "UL/", 3) == 0 ||
1847 strncmp(kbuf.dptr, "GL/", 3) == 0)
1848 tdb_delete(the_tdb, kbuf);
1850 return 0;
1853 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
1855 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
1856 NET_USER_INFO_3 *info3)
1858 struct winbind_cache *cache;
1860 if (!domain)
1861 return;
1863 cache = get_cache(domain);
1864 netsamlogon_clear_cached_user(cache->tdb, info3);
1867 void wcache_invalidate_cache(void)
1869 struct winbindd_domain *domain;
1871 for (domain = domain_list(); domain; domain = domain->next) {
1872 struct winbind_cache *cache = get_cache(domain);
1874 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
1875 "entries for %s\n", domain->name));
1876 if (cache)
1877 tdb_traverse(cache->tdb, traverse_fn, NULL);
1881 static BOOL init_wcache(void)
1883 if (wcache == NULL) {
1884 wcache = SMB_XMALLOC_P(struct winbind_cache);
1885 ZERO_STRUCTP(wcache);
1888 if (wcache->tdb != NULL)
1889 return True;
1891 /* when working offline we must not clear the cache on restart */
1892 wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
1893 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
1894 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
1895 O_RDWR|O_CREAT, 0600);
1897 if (wcache->tdb == NULL) {
1898 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
1899 return False;
1902 return True;
1905 void cache_store_response(pid_t pid, struct winbindd_response *response)
1907 fstring key_str;
1909 if (!init_wcache())
1910 return;
1912 DEBUG(10, ("Storing response for pid %d, len %d\n",
1913 pid, response->length));
1915 fstr_sprintf(key_str, "DR/%d", pid);
1916 if (tdb_store(wcache->tdb, string_tdb_data(key_str),
1917 make_tdb_data((void *)response, sizeof(*response)),
1918 TDB_REPLACE) == -1)
1919 return;
1921 if (response->length == sizeof(*response))
1922 return;
1924 /* There's extra data */
1926 DEBUG(10, ("Storing extra data: len=%d\n",
1927 (int)(response->length - sizeof(*response))));
1929 fstr_sprintf(key_str, "DE/%d", pid);
1930 if (tdb_store(wcache->tdb, string_tdb_data(key_str),
1931 make_tdb_data(response->extra_data.data,
1932 response->length - sizeof(*response)),
1933 TDB_REPLACE) == 0)
1934 return;
1936 /* We could not store the extra data, make sure the tdb does not
1937 * contain a main record with wrong dangling extra data */
1939 fstr_sprintf(key_str, "DR/%d", pid);
1940 tdb_delete(wcache->tdb, string_tdb_data(key_str));
1942 return;
1945 BOOL cache_retrieve_response(pid_t pid, struct winbindd_response * response)
1947 TDB_DATA data;
1948 fstring key_str;
1950 if (!init_wcache())
1951 return False;
1953 DEBUG(10, ("Retrieving response for pid %d\n", pid));
1955 fstr_sprintf(key_str, "DR/%d", pid);
1956 data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
1958 if (data.dptr == NULL)
1959 return False;
1961 if (data.dsize != sizeof(*response))
1962 return False;
1964 memcpy(response, data.dptr, data.dsize);
1965 SAFE_FREE(data.dptr);
1967 if (response->length == sizeof(*response)) {
1968 response->extra_data.data = NULL;
1969 return True;
1972 /* There's extra data */
1974 DEBUG(10, ("Retrieving extra data length=%d\n",
1975 (int)(response->length - sizeof(*response))));
1977 fstr_sprintf(key_str, "DE/%d", pid);
1978 data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
1980 if (data.dptr == NULL) {
1981 DEBUG(0, ("Did not find extra data\n"));
1982 return False;
1985 if (data.dsize != (response->length - sizeof(*response))) {
1986 DEBUG(0, ("Invalid extra data length: %d\n", (int)data.dsize));
1987 SAFE_FREE(data.dptr);
1988 return False;
1991 dump_data(11, data.dptr, data.dsize);
1993 response->extra_data.data = data.dptr;
1994 return True;
1997 void cache_cleanup_response(pid_t pid)
1999 fstring key_str;
2001 if (!init_wcache())
2002 return;
2004 fstr_sprintf(key_str, "DR/%d", pid);
2005 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2007 fstr_sprintf(key_str, "DE/%d", pid);
2008 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2010 return;
2014 BOOL lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
2015 const char **domain_name, const char **name,
2016 enum SID_NAME_USE *type)
2018 struct winbindd_domain *domain;
2019 struct winbind_cache *cache;
2020 struct cache_entry *centry = NULL;
2021 NTSTATUS status;
2023 domain = find_lookup_domain_from_sid(sid);
2024 if (domain == NULL) {
2025 return False;
2028 cache = get_cache(domain);
2030 if (cache->tdb == NULL) {
2031 return False;
2034 centry = wcache_fetch(cache, domain, "SN/%s", sid_string_static(sid));
2035 if (centry == NULL) {
2036 return False;
2039 if (NT_STATUS_IS_OK(centry->status)) {
2040 *type = (enum SID_NAME_USE)centry_uint32(centry);
2041 *domain_name = centry_string(centry, mem_ctx);
2042 *name = centry_string(centry, mem_ctx);
2045 status = centry->status;
2046 centry_free(centry);
2047 return NT_STATUS_IS_OK(status);
2050 BOOL lookup_cached_name(TALLOC_CTX *mem_ctx,
2051 const char *domain_name,
2052 const char *name,
2053 DOM_SID *sid,
2054 enum SID_NAME_USE *type)
2056 struct winbindd_domain *domain;
2057 struct winbind_cache *cache;
2058 struct cache_entry *centry = NULL;
2059 NTSTATUS status;
2060 fstring uname;
2062 domain = find_lookup_domain_from_name(domain_name);
2063 if (domain == NULL) {
2064 return False;
2067 cache = get_cache(domain);
2069 if (cache->tdb == NULL) {
2070 return False;
2073 fstrcpy(uname, name);
2074 strupper_m(uname);
2076 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
2077 if (centry == NULL) {
2078 return False;
2081 if (NT_STATUS_IS_OK(centry->status)) {
2082 *type = (enum SID_NAME_USE)centry_uint32(centry);
2083 centry_sid(centry, mem_ctx, sid);
2086 status = centry->status;
2087 centry_free(centry);
2089 return NT_STATUS_IS_OK(status);
2092 void cache_name2sid(struct winbindd_domain *domain,
2093 const char *domain_name, const char *name,
2094 enum SID_NAME_USE type, const DOM_SID *sid)
2096 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
2097 sid, type);
2100 /* delete all centries that don't have NT_STATUS_OK set */
2101 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
2102 TDB_DATA dbuf, void *state)
2104 struct cache_entry *centry;
2106 centry = wcache_fetch_raw(kbuf.dptr);
2107 if (!centry) {
2108 return 0;
2111 if (!NT_STATUS_IS_OK(centry->status)) {
2112 DEBUG(10,("deleting centry %s\n", kbuf.dptr));
2113 tdb_delete(the_tdb, kbuf);
2116 centry_free(centry);
2117 return 0;
2120 /* flush the cache */
2121 void wcache_flush_cache(void)
2123 extern BOOL opt_nocache;
2125 if (!wcache)
2126 return;
2127 if (wcache->tdb) {
2128 tdb_close(wcache->tdb);
2129 wcache->tdb = NULL;
2131 if (opt_nocache)
2132 return;
2134 /* when working offline we must not clear the cache on restart */
2135 wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
2136 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2137 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
2138 O_RDWR|O_CREAT, 0600);
2140 if (!wcache->tdb) {
2141 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2142 return;
2145 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
2147 DEBUG(10,("wcache_flush_cache success\n"));
2150 /* Count cached creds */
2152 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2153 void *state)
2155 int *cred_count = (int*)state;
2157 if (strncmp(kbuf.dptr, "CRED/", 5) == 0) {
2158 (*cred_count)++;
2160 return 0;
2163 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
2165 struct winbind_cache *cache = get_cache(domain);
2167 *count = 0;
2169 if (!cache->tdb) {
2170 return NT_STATUS_INTERNAL_DB_ERROR;
2173 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
2175 return NT_STATUS_OK;
2178 struct cred_list {
2179 struct cred_list *prev, *next;
2180 TDB_DATA key;
2181 fstring name;
2182 time_t created;
2184 static struct cred_list *wcache_cred_list;
2186 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2187 void *state)
2189 struct cred_list *cred;
2191 if (strncmp(kbuf.dptr, "CRED/", 5) == 0) {
2193 cred = SMB_MALLOC_P(struct cred_list);
2194 if (cred == NULL) {
2195 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2196 return -1;
2199 ZERO_STRUCTP(cred);
2201 /* save a copy of the key */
2203 fstrcpy(cred->name, kbuf.dptr);
2204 DLIST_ADD(wcache_cred_list, cred);
2207 return 0;
2210 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const DOM_SID *sid)
2212 struct winbind_cache *cache = get_cache(domain);
2213 NTSTATUS status;
2214 int ret;
2215 struct cred_list *cred, *oldest = NULL;
2217 if (!cache->tdb) {
2218 return NT_STATUS_INTERNAL_DB_ERROR;
2221 /* we possibly already have an entry */
2222 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
2224 fstring key_str;
2226 DEBUG(11,("we already have an entry, deleting that\n"));
2228 fstr_sprintf(key_str, "CRED/%s", sid_string_static(sid));
2230 tdb_delete(cache->tdb, string_tdb_data(key_str));
2232 return NT_STATUS_OK;
2235 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
2236 if (ret == 0) {
2237 return NT_STATUS_OK;
2238 } else if ((ret == -1) || (wcache_cred_list == NULL)) {
2239 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2242 ZERO_STRUCTP(oldest);
2244 for (cred = wcache_cred_list; cred; cred = cred->next) {
2246 TDB_DATA data;
2247 time_t t;
2249 data = tdb_fetch(cache->tdb, make_tdb_data(cred->name, strlen(cred->name)));
2250 if (!data.dptr) {
2251 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
2252 cred->name));
2253 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
2254 goto done;
2257 t = IVAL(data.dptr, 0);
2258 SAFE_FREE(data.dptr);
2260 if (!oldest) {
2261 oldest = SMB_MALLOC_P(struct cred_list);
2262 if (oldest == NULL) {
2263 status = NT_STATUS_NO_MEMORY;
2264 goto done;
2267 fstrcpy(oldest->name, cred->name);
2268 oldest->created = t;
2269 continue;
2272 if (t < oldest->created) {
2273 fstrcpy(oldest->name, cred->name);
2274 oldest->created = t;
2278 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
2279 status = NT_STATUS_OK;
2280 } else {
2281 status = NT_STATUS_UNSUCCESSFUL;
2283 done:
2284 SAFE_FREE(wcache_cred_list);
2285 SAFE_FREE(oldest);
2287 return status;
2290 /* Change the global online/offline state. */
2291 BOOL set_global_winbindd_state_offline(void)
2293 TDB_DATA data;
2294 int err;
2296 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
2298 /* Only go offline if someone has created
2299 the key "WINBINDD_OFFLINE" in the cache tdb. */
2301 if (wcache == NULL || wcache->tdb == NULL) {
2302 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
2303 return False;
2306 if (!lp_winbind_offline_logon()) {
2307 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
2308 return False;
2311 if (global_winbindd_offline_state) {
2312 /* Already offline. */
2313 return True;
2316 wcache->tdb->ecode = 0;
2318 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
2320 /* As this is a key with no data we don't need to free, we
2321 check for existence by looking at tdb_err. */
2323 err = tdb_error(wcache->tdb);
2325 if (err == TDB_ERR_NOEXIST) {
2326 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
2327 return False;
2328 } else {
2329 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
2330 global_winbindd_offline_state = True;
2331 return True;
2335 void set_global_winbindd_state_online(void)
2337 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
2339 if (!lp_winbind_offline_logon()) {
2340 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
2341 return;
2344 if (!global_winbindd_offline_state) {
2345 /* Already online. */
2346 return;
2348 global_winbindd_offline_state = False;
2350 if (!wcache->tdb) {
2351 return;
2354 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
2355 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
2358 BOOL get_global_winbindd_state_online(void)
2360 return global_winbindd_offline_state;
2363 /* the cache backend methods are exposed via this structure */
2364 struct winbindd_methods cache_methods = {
2365 True,
2366 query_user_list,
2367 enum_dom_groups,
2368 enum_local_groups,
2369 name_to_sid,
2370 sid_to_name,
2371 query_user,
2372 lookup_usergroups,
2373 lookup_useraliases,
2374 lookup_groupmem,
2375 sequence_number,
2376 lockout_policy,
2377 password_policy,
2378 trusted_domains