r11684: freezing 3.0.21rc1 (current with SAMBA_3_0 r11667)
[Samba.git] / source / nsswitch / winbindd_cache.c
blob83ded01d4ea90a6923723fdca933328fda60e797
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
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 struct winbind_cache {
33 TDB_CONTEXT *tdb;
36 struct cache_entry {
37 NTSTATUS status;
38 uint32 sequence_number;
39 uint8 *data;
40 uint32 len, ofs;
43 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
45 static struct winbind_cache *wcache;
47 /* flush the cache */
48 void wcache_flush_cache(void)
50 extern BOOL opt_nocache;
52 if (!wcache)
53 return;
54 if (wcache->tdb) {
55 tdb_close(wcache->tdb);
56 wcache->tdb = NULL;
58 if (opt_nocache)
59 return;
61 wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 5000,
62 TDB_CLEAR_IF_FIRST, O_RDWR|O_CREAT, 0600);
64 if (!wcache->tdb) {
65 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
67 DEBUG(10,("wcache_flush_cache success\n"));
70 void winbindd_check_cache_size(time_t t)
72 static time_t last_check_time;
73 struct stat st;
75 if (last_check_time == (time_t)0)
76 last_check_time = t;
78 if (t - last_check_time < 60 && t - last_check_time > 0)
79 return;
81 if (wcache == NULL || wcache->tdb == NULL) {
82 DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
83 return;
86 if (fstat(wcache->tdb->fd, &st) == -1) {
87 DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno) ));
88 return;
91 if (st.st_size > WINBINDD_MAX_CACHE_SIZE) {
92 DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
93 (unsigned long)st.st_size,
94 (unsigned long)WINBINDD_MAX_CACHE_SIZE));
95 wcache_flush_cache();
99 /* get the winbind_cache structure */
100 static struct winbind_cache *get_cache(struct winbindd_domain *domain)
102 struct winbind_cache *ret = wcache;
103 struct winbindd_domain *our_domain = domain;
105 /* we have to know what type of domain we are dealing with first */
107 if ( !domain->initialized )
108 set_dc_type_and_flags( domain );
111 OK. listen up becasue I'm only going to say this once.
112 We have the following scenarios to consider
113 (a) trusted AD domains on a Samba DC,
114 (b) trusted AD domains and we are joined to a non-kerberos domain
115 (c) trusted AD domains and we are joined to a kerberos (AD) domain
117 For (a) we can always contact the trusted domain using krb5
118 since we have the domain trust account password
120 For (b) we can only use RPC since we have no way of
121 getting a krb5 ticket in our own domain
123 For (c) we can always use krb5 since we have a kerberos trust
125 --jerry
128 if (!domain->backend) {
129 extern struct winbindd_methods reconnect_methods;
130 #ifdef HAVE_ADS
131 extern struct winbindd_methods ads_methods;
133 /* find our domain first so we can figure out if we
134 are joined to a kerberized domain */
136 if ( !domain->primary )
137 our_domain = find_our_domain();
139 if ( (our_domain->active_directory || IS_DC) && domain->active_directory ) {
140 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain->name));
141 domain->backend = &ads_methods;
142 } else {
143 #endif /* HAVE_ADS */
144 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain->name));
145 domain->backend = &reconnect_methods;
146 #ifdef HAVE_ADS
148 #endif /* HAVE_ADS */
151 if (ret)
152 return ret;
154 ret = SMB_XMALLOC_P(struct winbind_cache);
155 ZERO_STRUCTP(ret);
157 wcache = ret;
158 wcache_flush_cache();
160 return ret;
164 free a centry structure
166 static void centry_free(struct cache_entry *centry)
168 if (!centry)
169 return;
170 SAFE_FREE(centry->data);
171 free(centry);
175 pull a uint32 from a cache entry
177 static uint32 centry_uint32(struct cache_entry *centry)
179 uint32 ret;
180 if (centry->len - centry->ofs < 4) {
181 DEBUG(0,("centry corruption? needed 4 bytes, have %d\n",
182 centry->len - centry->ofs));
183 smb_panic("centry_uint32");
185 ret = IVAL(centry->data, centry->ofs);
186 centry->ofs += 4;
187 return ret;
191 pull a uint8 from a cache entry
193 static uint8 centry_uint8(struct cache_entry *centry)
195 uint8 ret;
196 if (centry->len - centry->ofs < 1) {
197 DEBUG(0,("centry corruption? needed 1 bytes, have %d\n",
198 centry->len - centry->ofs));
199 smb_panic("centry_uint32");
201 ret = CVAL(centry->data, centry->ofs);
202 centry->ofs += 1;
203 return ret;
206 /* pull a string from a cache entry, using the supplied
207 talloc context
209 static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
211 uint32 len;
212 char *ret;
214 len = centry_uint8(centry);
216 if (len == 0xFF) {
217 /* a deliberate NULL string */
218 return NULL;
221 if (centry->len - centry->ofs < len) {
222 DEBUG(0,("centry corruption? needed %d bytes, have %d\n",
223 len, centry->len - centry->ofs));
224 smb_panic("centry_string");
227 if (mem_ctx != NULL)
228 ret = TALLOC(mem_ctx, len+1);
229 else
230 ret = SMB_MALLOC(len+1);
231 if (!ret) {
232 smb_panic("centry_string out of memory\n");
234 memcpy(ret,centry->data + centry->ofs, len);
235 ret[len] = 0;
236 centry->ofs += len;
237 return ret;
240 /* pull a string from a cache entry, using the supplied
241 talloc context
243 static BOOL centry_sid(struct cache_entry *centry, DOM_SID *sid)
245 char *sid_string;
246 sid_string = centry_string(centry, NULL);
247 if (!string_to_sid(sid, sid_string)) {
248 return False;
250 SAFE_FREE(sid_string);
251 return True;
254 /* the server is considered down if it can't give us a sequence number */
255 static BOOL wcache_server_down(struct winbindd_domain *domain)
257 BOOL ret;
259 if (!wcache->tdb)
260 return False;
262 ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
264 if (ret)
265 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
266 domain->name ));
267 return ret;
270 static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
272 TDB_DATA data;
273 fstring key;
274 uint32 time_diff;
276 if (!wcache->tdb) {
277 DEBUG(10,("fetch_cache_seqnum: tdb == NULL\n"));
278 return NT_STATUS_UNSUCCESSFUL;
281 fstr_sprintf( key, "SEQNUM/%s", domain->name );
283 data = tdb_fetch_bystring( wcache->tdb, key );
284 if ( !data.dptr || data.dsize!=8 ) {
285 DEBUG(10,("fetch_cache_seqnum: invalid data size key [%s]\n", key ));
286 return NT_STATUS_UNSUCCESSFUL;
289 domain->sequence_number = IVAL(data.dptr, 0);
290 domain->last_seq_check = IVAL(data.dptr, 4);
292 SAFE_FREE(data.dptr);
294 /* have we expired? */
296 time_diff = now - domain->last_seq_check;
297 if ( time_diff > lp_winbind_cache_time() ) {
298 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
299 domain->name, domain->sequence_number,
300 (uint32)domain->last_seq_check));
301 return NT_STATUS_UNSUCCESSFUL;
304 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
305 domain->name, domain->sequence_number,
306 (uint32)domain->last_seq_check));
308 return NT_STATUS_OK;
311 static NTSTATUS store_cache_seqnum( struct winbindd_domain *domain )
313 TDB_DATA data, key;
314 fstring key_str;
315 char buf[8];
317 if (!wcache->tdb) {
318 DEBUG(10,("store_cache_seqnum: tdb == NULL\n"));
319 return NT_STATUS_UNSUCCESSFUL;
322 fstr_sprintf( key_str, "SEQNUM/%s", domain->name );
323 key.dptr = key_str;
324 key.dsize = strlen(key_str)+1;
326 SIVAL(buf, 0, domain->sequence_number);
327 SIVAL(buf, 4, domain->last_seq_check);
328 data.dptr = buf;
329 data.dsize = 8;
331 if ( tdb_store( wcache->tdb, key, data, TDB_REPLACE) == -1 ) {
332 DEBUG(10,("store_cache_seqnum: tdb_store fail key [%s]\n", key_str ));
333 return NT_STATUS_UNSUCCESSFUL;
336 DEBUG(10,("store_cache_seqnum: success [%s][%u @ %u]\n",
337 domain->name, domain->sequence_number,
338 (uint32)domain->last_seq_check));
340 return NT_STATUS_OK;
344 refresh the domain sequence number. If force is True
345 then always refresh it, no matter how recently we fetched it
348 static void refresh_sequence_number(struct winbindd_domain *domain, BOOL force)
350 NTSTATUS status;
351 unsigned time_diff;
352 time_t t = time(NULL);
353 unsigned cache_time = lp_winbind_cache_time();
355 get_cache( domain );
357 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
358 /* trying to reconnect is expensive, don't do it too often */
359 if (domain->sequence_number == DOM_SEQUENCE_NONE) {
360 cache_time *= 8;
362 #endif
364 time_diff = t - domain->last_seq_check;
366 /* see if we have to refetch the domain sequence number */
367 if (!force && (time_diff < cache_time)) {
368 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
369 goto done;
372 /* try to get the sequence number from the tdb cache first */
373 /* this will update the timestamp as well */
375 status = fetch_cache_seqnum( domain, t );
376 if ( NT_STATUS_IS_OK(status) )
377 goto done;
379 /* important! make sure that we know if this is a native
380 mode domain or not */
382 status = domain->backend->sequence_number(domain, &domain->sequence_number);
384 if (!NT_STATUS_IS_OK(status)) {
385 domain->sequence_number = DOM_SEQUENCE_NONE;
388 domain->last_status = status;
389 domain->last_seq_check = time(NULL);
391 /* save the new sequence number ni the cache */
392 store_cache_seqnum( domain );
394 done:
395 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
396 domain->name, domain->sequence_number));
398 return;
402 decide if a cache entry has expired
404 static BOOL centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
406 /* if the server is OK and our cache entry came from when it was down then
407 the entry is invalid */
408 if (domain->sequence_number != DOM_SEQUENCE_NONE &&
409 centry->sequence_number == DOM_SEQUENCE_NONE) {
410 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
411 keystr, domain->name ));
412 return True;
415 /* if the server is down or the cache entry is not older than the
416 current sequence number then it is OK */
417 if (wcache_server_down(domain) ||
418 centry->sequence_number == domain->sequence_number) {
419 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
420 keystr, domain->name ));
421 return False;
424 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
425 keystr, domain->name ));
427 /* it's expired */
428 return True;
432 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
433 number and return status
435 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
436 struct winbindd_domain *domain,
437 const char *format, ...) PRINTF_ATTRIBUTE(3,4);
438 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
439 struct winbindd_domain *domain,
440 const char *format, ...)
442 va_list ap;
443 char *kstr;
444 TDB_DATA data;
445 struct cache_entry *centry;
446 TDB_DATA key;
448 refresh_sequence_number(domain, False);
450 va_start(ap, format);
451 smb_xvasprintf(&kstr, format, ap);
452 va_end(ap);
454 key.dptr = kstr;
455 key.dsize = strlen(kstr);
456 data = tdb_fetch(wcache->tdb, key);
457 if (!data.dptr) {
458 /* a cache miss */
459 free(kstr);
460 return NULL;
463 centry = SMB_XMALLOC_P(struct cache_entry);
464 centry->data = (unsigned char *)data.dptr;
465 centry->len = data.dsize;
466 centry->ofs = 0;
468 if (centry->len < 8) {
469 /* huh? corrupt cache? */
470 DEBUG(10,("wcache_fetch: Corrupt cache for key %s domain %s (len < 8) ?\n",
471 kstr, domain->name ));
472 centry_free(centry);
473 free(kstr);
474 return NULL;
477 centry->status = NT_STATUS(centry_uint32(centry));
478 centry->sequence_number = centry_uint32(centry);
480 if (centry_expired(domain, kstr, centry)) {
482 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
483 kstr, domain->name ));
485 centry_free(centry);
486 free(kstr);
487 return NULL;
490 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
491 kstr, domain->name ));
493 free(kstr);
494 return centry;
498 make sure we have at least len bytes available in a centry
500 static void centry_expand(struct cache_entry *centry, uint32 len)
502 uint8 *p;
503 if (centry->len - centry->ofs >= len)
504 return;
505 centry->len *= 2;
506 p = SMB_REALLOC(centry->data, centry->len);
507 if (!p) {
508 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
509 smb_panic("out of memory in centry_expand");
511 centry->data = p;
515 push a uint32 into a centry
517 static void centry_put_uint32(struct cache_entry *centry, uint32 v)
519 centry_expand(centry, 4);
520 SIVAL(centry->data, centry->ofs, v);
521 centry->ofs += 4;
525 push a uint8 into a centry
527 static void centry_put_uint8(struct cache_entry *centry, uint8 v)
529 centry_expand(centry, 1);
530 SCVAL(centry->data, centry->ofs, v);
531 centry->ofs += 1;
535 push a string into a centry
537 static void centry_put_string(struct cache_entry *centry, const char *s)
539 int len;
541 if (!s) {
542 /* null strings are marked as len 0xFFFF */
543 centry_put_uint8(centry, 0xFF);
544 return;
547 len = strlen(s);
548 /* can't handle more than 254 char strings. Truncating is probably best */
549 if (len > 254)
550 len = 254;
551 centry_put_uint8(centry, len);
552 centry_expand(centry, len);
553 memcpy(centry->data + centry->ofs, s, len);
554 centry->ofs += len;
557 static void centry_put_sid(struct cache_entry *centry, const DOM_SID *sid)
559 fstring sid_string;
560 centry_put_string(centry, sid_to_string(sid_string, sid));
564 start a centry for output. When finished, call centry_end()
566 struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status)
568 struct cache_entry *centry;
570 if (!wcache->tdb)
571 return NULL;
573 centry = SMB_XMALLOC_P(struct cache_entry);
575 centry->len = 8192; /* reasonable default */
576 centry->data = SMB_XMALLOC_ARRAY(uint8, centry->len);
577 centry->ofs = 0;
578 centry->sequence_number = domain->sequence_number;
579 centry_put_uint32(centry, NT_STATUS_V(status));
580 centry_put_uint32(centry, centry->sequence_number);
581 return centry;
585 finish a centry and write it to the tdb
587 static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
588 static void centry_end(struct cache_entry *centry, const char *format, ...)
590 va_list ap;
591 char *kstr;
592 TDB_DATA key, data;
594 va_start(ap, format);
595 smb_xvasprintf(&kstr, format, ap);
596 va_end(ap);
598 key.dptr = kstr;
599 key.dsize = strlen(kstr);
600 data.dptr = (char *)centry->data;
601 data.dsize = centry->ofs;
603 tdb_store(wcache->tdb, key, data, TDB_REPLACE);
604 free(kstr);
607 static void wcache_save_name_to_sid(struct winbindd_domain *domain,
608 NTSTATUS status, const char *domain_name,
609 const char *name, const DOM_SID *sid,
610 enum SID_NAME_USE type)
612 struct cache_entry *centry;
613 fstring uname;
615 centry = centry_start(domain, status);
616 if (!centry)
617 return;
618 centry_put_uint32(centry, type);
619 centry_put_sid(centry, sid);
620 fstrcpy(uname, name);
621 strupper_m(uname);
622 centry_end(centry, "NS/%s/%s", domain_name, uname);
623 DEBUG(10,("wcache_save_name_to_sid: %s -> %s\n", uname,
624 sid_string_static(sid)));
625 centry_free(centry);
628 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
629 const DOM_SID *sid, const char *domain_name, const char *name, enum SID_NAME_USE type)
631 struct cache_entry *centry;
632 fstring sid_string;
634 centry = centry_start(domain, status);
635 if (!centry)
636 return;
637 if (NT_STATUS_IS_OK(status)) {
638 centry_put_uint32(centry, type);
639 centry_put_string(centry, domain_name);
640 centry_put_string(centry, name);
642 centry_end(centry, "SN/%s", sid_to_string(sid_string, sid));
643 DEBUG(10,("wcache_save_sid_to_name: %s -> %s\n", sid_string, name));
644 centry_free(centry);
648 static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status, WINBIND_USERINFO *info)
650 struct cache_entry *centry;
651 fstring sid_string;
653 centry = centry_start(domain, status);
654 if (!centry)
655 return;
656 centry_put_string(centry, info->acct_name);
657 centry_put_string(centry, info->full_name);
658 centry_put_string(centry, info->homedir);
659 centry_put_string(centry, info->shell);
660 centry_put_sid(centry, &info->user_sid);
661 centry_put_sid(centry, &info->group_sid);
662 centry_end(centry, "U/%s", sid_to_string(sid_string, &info->user_sid));
663 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
664 centry_free(centry);
668 /* Query display info. This is the basic user list fn */
669 static NTSTATUS query_user_list(struct winbindd_domain *domain,
670 TALLOC_CTX *mem_ctx,
671 uint32 *num_entries,
672 WINBIND_USERINFO **info)
674 struct winbind_cache *cache = get_cache(domain);
675 struct cache_entry *centry = NULL;
676 NTSTATUS status;
677 unsigned int i, retry;
679 if (!cache->tdb)
680 goto do_query;
682 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
683 if (!centry)
684 goto do_query;
686 *num_entries = centry_uint32(centry);
688 if (*num_entries == 0)
689 goto do_cached;
691 (*info) = TALLOC_ARRAY(mem_ctx, WINBIND_USERINFO, *num_entries);
692 if (! (*info))
693 smb_panic("query_user_list out of memory");
694 for (i=0; i<(*num_entries); i++) {
695 (*info)[i].acct_name = centry_string(centry, mem_ctx);
696 (*info)[i].full_name = centry_string(centry, mem_ctx);
697 (*info)[i].homedir = centry_string(centry, mem_ctx);
698 (*info)[i].shell = centry_string(centry, mem_ctx);
699 centry_sid(centry, &(*info)[i].user_sid);
700 centry_sid(centry, &(*info)[i].group_sid);
703 do_cached:
704 status = centry->status;
706 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status %s\n",
707 domain->name, get_friendly_nt_error_msg(status) ));
709 centry_free(centry);
710 return status;
712 do_query:
713 *num_entries = 0;
714 *info = NULL;
716 /* Return status value returned by seq number check */
718 if (!NT_STATUS_IS_OK(domain->last_status))
719 return domain->last_status;
721 /* Put the query_user_list() in a retry loop. There appears to be
722 * some bug either with Windows 2000 or Samba's handling of large
723 * rpc replies. This manifests itself as sudden disconnection
724 * at a random point in the enumeration of a large (60k) user list.
725 * The retry loop simply tries the operation again. )-: It's not
726 * pretty but an acceptable workaround until we work out what the
727 * real problem is. */
729 retry = 0;
730 do {
732 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
733 domain->name ));
735 status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
736 if (!NT_STATUS_IS_OK(status))
737 DEBUG(3, ("query_user_list: returned 0x%08x, "
738 "retrying\n", NT_STATUS_V(status)));
739 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
740 DEBUG(3, ("query_user_list: flushing "
741 "connection cache\n"));
742 invalidate_cm_connection(&domain->conn);
745 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
746 (retry++ < 5));
748 /* and save it */
749 refresh_sequence_number(domain, False);
750 centry = centry_start(domain, status);
751 if (!centry)
752 goto skip_save;
753 centry_put_uint32(centry, *num_entries);
754 for (i=0; i<(*num_entries); i++) {
755 centry_put_string(centry, (*info)[i].acct_name);
756 centry_put_string(centry, (*info)[i].full_name);
757 centry_put_string(centry, (*info)[i].homedir);
758 centry_put_string(centry, (*info)[i].shell);
759 centry_put_sid(centry, &(*info)[i].user_sid);
760 centry_put_sid(centry, &(*info)[i].group_sid);
761 if (domain->backend->consistent) {
762 /* when the backend is consistent we can pre-prime some mappings */
763 wcache_save_name_to_sid(domain, NT_STATUS_OK,
764 domain->name,
765 (*info)[i].acct_name,
766 &(*info)[i].user_sid,
767 SID_NAME_USER);
768 wcache_save_sid_to_name(domain, NT_STATUS_OK,
769 &(*info)[i].user_sid,
770 domain->name,
771 (*info)[i].acct_name,
772 SID_NAME_USER);
773 wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
776 centry_end(centry, "UL/%s", domain->name);
777 centry_free(centry);
779 skip_save:
780 return status;
783 /* list all domain groups */
784 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
785 TALLOC_CTX *mem_ctx,
786 uint32 *num_entries,
787 struct acct_info **info)
789 struct winbind_cache *cache = get_cache(domain);
790 struct cache_entry *centry = NULL;
791 NTSTATUS status;
792 unsigned int i;
794 if (!cache->tdb)
795 goto do_query;
797 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
798 if (!centry)
799 goto do_query;
801 *num_entries = centry_uint32(centry);
803 if (*num_entries == 0)
804 goto do_cached;
806 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
807 if (! (*info))
808 smb_panic("enum_dom_groups out of memory");
809 for (i=0; i<(*num_entries); i++) {
810 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
811 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
812 (*info)[i].rid = centry_uint32(centry);
815 do_cached:
816 status = centry->status;
818 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status %s\n",
819 domain->name, get_friendly_nt_error_msg(status) ));
821 centry_free(centry);
822 return status;
824 do_query:
825 *num_entries = 0;
826 *info = NULL;
828 /* Return status value returned by seq number check */
830 if (!NT_STATUS_IS_OK(domain->last_status))
831 return domain->last_status;
833 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
834 domain->name ));
836 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
838 /* and save it */
839 refresh_sequence_number(domain, False);
840 centry = centry_start(domain, status);
841 if (!centry)
842 goto skip_save;
843 centry_put_uint32(centry, *num_entries);
844 for (i=0; i<(*num_entries); i++) {
845 centry_put_string(centry, (*info)[i].acct_name);
846 centry_put_string(centry, (*info)[i].acct_desc);
847 centry_put_uint32(centry, (*info)[i].rid);
849 centry_end(centry, "GL/%s/domain", domain->name);
850 centry_free(centry);
852 skip_save:
853 return status;
856 /* list all domain groups */
857 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
858 TALLOC_CTX *mem_ctx,
859 uint32 *num_entries,
860 struct acct_info **info)
862 struct winbind_cache *cache = get_cache(domain);
863 struct cache_entry *centry = NULL;
864 NTSTATUS status;
865 unsigned int i;
867 if (!cache->tdb)
868 goto do_query;
870 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
871 if (!centry)
872 goto do_query;
874 *num_entries = centry_uint32(centry);
876 if (*num_entries == 0)
877 goto do_cached;
879 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
880 if (! (*info))
881 smb_panic("enum_dom_groups out of memory");
882 for (i=0; i<(*num_entries); i++) {
883 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
884 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
885 (*info)[i].rid = centry_uint32(centry);
888 do_cached:
890 /* If we are returning cached data and the domain controller
891 is down then we don't know whether the data is up to date
892 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
893 indicate this. */
895 if (wcache_server_down(domain)) {
896 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
897 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
898 } else
899 status = centry->status;
901 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status %s\n",
902 domain->name, get_friendly_nt_error_msg(status) ));
904 centry_free(centry);
905 return status;
907 do_query:
908 *num_entries = 0;
909 *info = NULL;
911 /* Return status value returned by seq number check */
913 if (!NT_STATUS_IS_OK(domain->last_status))
914 return domain->last_status;
916 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
917 domain->name ));
919 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
921 /* and save it */
922 refresh_sequence_number(domain, False);
923 centry = centry_start(domain, status);
924 if (!centry)
925 goto skip_save;
926 centry_put_uint32(centry, *num_entries);
927 for (i=0; i<(*num_entries); i++) {
928 centry_put_string(centry, (*info)[i].acct_name);
929 centry_put_string(centry, (*info)[i].acct_desc);
930 centry_put_uint32(centry, (*info)[i].rid);
932 centry_end(centry, "GL/%s/local", domain->name);
933 centry_free(centry);
935 skip_save:
936 return status;
939 /* convert a single name to a sid in a domain */
940 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
941 TALLOC_CTX *mem_ctx,
942 const char *domain_name,
943 const char *name,
944 DOM_SID *sid,
945 enum SID_NAME_USE *type)
947 struct winbind_cache *cache = get_cache(domain);
948 struct cache_entry *centry = NULL;
949 NTSTATUS status;
950 fstring uname;
952 if (!cache->tdb)
953 goto do_query;
955 fstrcpy(uname, name);
956 strupper_m(uname);
957 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
958 if (!centry)
959 goto do_query;
960 *type = (enum SID_NAME_USE)centry_uint32(centry);
961 centry_sid(centry, sid);
962 status = centry->status;
964 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status %s\n",
965 domain->name, get_friendly_nt_error_msg(status) ));
967 centry_free(centry);
968 return status;
970 do_query:
971 ZERO_STRUCTP(sid);
973 /* If the seq number check indicated that there is a problem
974 * with this DC, then return that status... except for
975 * access_denied. This is special because the dc may be in
976 * "restrict anonymous = 1" mode, in which case it will deny
977 * most unauthenticated operations, but *will* allow the LSA
978 * name-to-sid that we try as a fallback. */
980 if (!(NT_STATUS_IS_OK(domain->last_status)
981 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
982 return domain->last_status;
984 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
985 domain->name ));
987 status = domain->backend->name_to_sid(domain, mem_ctx, domain_name, name, sid, type);
989 /* and save it */
990 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
992 /* We can't save the sid to name mapping as we don't know the
993 correct case of the name without looking it up */
995 return status;
998 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
999 given */
1000 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
1001 TALLOC_CTX *mem_ctx,
1002 const DOM_SID *sid,
1003 char **domain_name,
1004 char **name,
1005 enum SID_NAME_USE *type)
1007 struct winbind_cache *cache = get_cache(domain);
1008 struct cache_entry *centry = NULL;
1009 NTSTATUS status;
1010 fstring sid_string;
1012 if (!cache->tdb)
1013 goto do_query;
1015 centry = wcache_fetch(cache, domain, "SN/%s", sid_to_string(sid_string, sid));
1016 if (!centry)
1017 goto do_query;
1018 if (NT_STATUS_IS_OK(centry->status)) {
1019 *type = (enum SID_NAME_USE)centry_uint32(centry);
1020 *domain_name = centry_string(centry, mem_ctx);
1021 *name = centry_string(centry, mem_ctx);
1023 status = centry->status;
1025 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status %s\n",
1026 domain->name, get_friendly_nt_error_msg(status) ));
1028 centry_free(centry);
1029 return status;
1031 do_query:
1032 *name = NULL;
1033 *domain_name = NULL;
1035 /* If the seq number check indicated that there is a problem
1036 * with this DC, then return that status... except for
1037 * access_denied. This is special because the dc may be in
1038 * "restrict anonymous = 1" mode, in which case it will deny
1039 * most unauthenticated operations, but *will* allow the LSA
1040 * sid-to-name that we try as a fallback. */
1042 if (!(NT_STATUS_IS_OK(domain->last_status)
1043 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1044 return domain->last_status;
1046 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1047 domain->name ));
1049 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1051 /* and save it */
1052 refresh_sequence_number(domain, False);
1053 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1055 /* We can't save the name to sid mapping here, as with sid history a
1056 * later name2sid would give the wrong sid. */
1058 return status;
1061 /* Lookup user information from a rid */
1062 static NTSTATUS query_user(struct winbindd_domain *domain,
1063 TALLOC_CTX *mem_ctx,
1064 const DOM_SID *user_sid,
1065 WINBIND_USERINFO *info)
1067 struct winbind_cache *cache = get_cache(domain);
1068 struct cache_entry *centry = NULL;
1069 NTSTATUS status;
1071 if (!cache->tdb)
1072 goto do_query;
1074 centry = wcache_fetch(cache, domain, "U/%s", sid_string_static(user_sid));
1076 /* If we have an access denied cache entry and a cached info3 in the
1077 samlogon cache then do a query. This will force the rpc back end
1078 to return the info3 data. */
1080 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1081 netsamlogon_cache_have(user_sid)) {
1082 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1083 domain->last_status = NT_STATUS_OK;
1084 centry_free(centry);
1085 goto do_query;
1088 if (!centry)
1089 goto do_query;
1091 info->acct_name = centry_string(centry, mem_ctx);
1092 info->full_name = centry_string(centry, mem_ctx);
1093 info->homedir = centry_string(centry, mem_ctx);
1094 info->shell = centry_string(centry, mem_ctx);
1095 centry_sid(centry, &info->user_sid);
1096 centry_sid(centry, &info->group_sid);
1097 status = centry->status;
1099 DEBUG(10,("query_user: [Cached] - cached info for domain %s status %s\n",
1100 domain->name, get_friendly_nt_error_msg(status) ));
1102 centry_free(centry);
1103 return status;
1105 do_query:
1106 ZERO_STRUCTP(info);
1108 /* Return status value returned by seq number check */
1110 if (!NT_STATUS_IS_OK(domain->last_status))
1111 return domain->last_status;
1113 DEBUG(10,("sid_to_name: [Cached] - doing backend query for info for domain %s\n",
1114 domain->name ));
1116 status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
1118 /* and save it */
1119 refresh_sequence_number(domain, False);
1120 wcache_save_user(domain, status, info);
1122 return status;
1126 /* Lookup groups a user is a member of. */
1127 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
1128 TALLOC_CTX *mem_ctx,
1129 const DOM_SID *user_sid,
1130 uint32 *num_groups, DOM_SID **user_gids)
1132 struct winbind_cache *cache = get_cache(domain);
1133 struct cache_entry *centry = NULL;
1134 NTSTATUS status;
1135 unsigned int i;
1136 fstring sid_string;
1138 if (!cache->tdb)
1139 goto do_query;
1141 centry = wcache_fetch(cache, domain, "UG/%s", sid_to_string(sid_string, user_sid));
1143 /* If we have an access denied cache entry and a cached info3 in the
1144 samlogon cache then do a query. This will force the rpc back end
1145 to return the info3 data. */
1147 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1148 netsamlogon_cache_have(user_sid)) {
1149 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1150 domain->last_status = NT_STATUS_OK;
1151 centry_free(centry);
1152 goto do_query;
1155 if (!centry)
1156 goto do_query;
1158 *num_groups = centry_uint32(centry);
1160 if (*num_groups == 0)
1161 goto do_cached;
1163 (*user_gids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
1164 if (! (*user_gids))
1165 smb_panic("lookup_usergroups out of memory");
1166 for (i=0; i<(*num_groups); i++) {
1167 centry_sid(centry, &(*user_gids)[i]);
1170 do_cached:
1171 status = centry->status;
1173 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status %s\n",
1174 domain->name, get_friendly_nt_error_msg(status) ));
1176 centry_free(centry);
1177 return status;
1179 do_query:
1180 (*num_groups) = 0;
1181 (*user_gids) = NULL;
1183 /* Return status value returned by seq number check */
1185 if (!NT_STATUS_IS_OK(domain->last_status))
1186 return domain->last_status;
1188 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
1189 domain->name ));
1191 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
1193 /* and save it */
1194 refresh_sequence_number(domain, False);
1195 centry = centry_start(domain, status);
1196 if (!centry)
1197 goto skip_save;
1198 centry_put_uint32(centry, *num_groups);
1199 for (i=0; i<(*num_groups); i++) {
1200 centry_put_sid(centry, &(*user_gids)[i]);
1202 centry_end(centry, "UG/%s", sid_to_string(sid_string, user_sid));
1203 centry_free(centry);
1205 skip_save:
1206 return status;
1209 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
1210 TALLOC_CTX *mem_ctx,
1211 uint32 num_sids, const DOM_SID *sids,
1212 uint32 *num_aliases, uint32 **alias_rids)
1214 struct winbind_cache *cache = get_cache(domain);
1215 struct cache_entry *centry = NULL;
1216 NTSTATUS status;
1217 char *sidlist = talloc_strdup(mem_ctx, "");
1218 int i;
1220 if (!cache->tdb)
1221 goto do_query;
1223 if (num_sids == 0) {
1224 *num_aliases = 0;
1225 *alias_rids = NULL;
1226 return NT_STATUS_OK;
1229 /* We need to cache indexed by the whole list of SIDs, the aliases
1230 * resulting might come from any of the SIDs. */
1232 for (i=0; i<num_sids; i++) {
1233 sidlist = talloc_asprintf(mem_ctx, "%s/%s", sidlist,
1234 sid_string_static(&sids[i]));
1235 if (sidlist == NULL)
1236 return NT_STATUS_NO_MEMORY;
1239 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
1241 if (!centry)
1242 goto do_query;
1244 *num_aliases = centry_uint32(centry);
1245 *alias_rids = NULL;
1247 (*alias_rids) = TALLOC_ARRAY(mem_ctx, uint32, *num_aliases);
1249 if ((*num_aliases != 0) && ((*alias_rids) == NULL))
1250 return NT_STATUS_NO_MEMORY;
1252 for (i=0; i<(*num_aliases); i++)
1253 (*alias_rids)[i] = centry_uint32(centry);
1255 status = centry->status;
1257 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain %s "
1258 "status %s\n", domain->name,
1259 get_friendly_nt_error_msg(status)));
1261 centry_free(centry);
1262 return status;
1264 do_query:
1265 (*num_aliases) = 0;
1266 (*alias_rids) = NULL;
1268 if (!NT_STATUS_IS_OK(domain->last_status))
1269 return domain->last_status;
1271 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
1272 "for domain %s\n", domain->name ));
1274 status = domain->backend->lookup_useraliases(domain, mem_ctx,
1275 num_sids, sids,
1276 num_aliases, alias_rids);
1278 /* and save it */
1279 refresh_sequence_number(domain, False);
1280 centry = centry_start(domain, status);
1281 if (!centry)
1282 goto skip_save;
1283 centry_put_uint32(centry, *num_aliases);
1284 for (i=0; i<(*num_aliases); i++)
1285 centry_put_uint32(centry, (*alias_rids)[i]);
1286 centry_end(centry, "UA%s", sidlist);
1287 centry_free(centry);
1289 skip_save:
1290 return status;
1294 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1295 TALLOC_CTX *mem_ctx,
1296 const DOM_SID *group_sid, uint32 *num_names,
1297 DOM_SID **sid_mem, char ***names,
1298 uint32 **name_types)
1300 struct winbind_cache *cache = get_cache(domain);
1301 struct cache_entry *centry = NULL;
1302 NTSTATUS status;
1303 unsigned int i;
1304 fstring sid_string;
1306 if (!cache->tdb)
1307 goto do_query;
1309 centry = wcache_fetch(cache, domain, "GM/%s", sid_to_string(sid_string, group_sid));
1310 if (!centry)
1311 goto do_query;
1313 *num_names = centry_uint32(centry);
1315 if (*num_names == 0)
1316 goto do_cached;
1318 (*sid_mem) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_names);
1319 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_names);
1320 (*name_types) = TALLOC_ARRAY(mem_ctx, uint32, *num_names);
1322 if (! (*sid_mem) || ! (*names) || ! (*name_types)) {
1323 smb_panic("lookup_groupmem out of memory");
1326 for (i=0; i<(*num_names); i++) {
1327 centry_sid(centry, &(*sid_mem)[i]);
1328 (*names)[i] = centry_string(centry, mem_ctx);
1329 (*name_types)[i] = centry_uint32(centry);
1332 do_cached:
1333 status = centry->status;
1335 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status %s\n",
1336 domain->name, get_friendly_nt_error_msg(status) ));
1338 centry_free(centry);
1339 return status;
1341 do_query:
1342 (*num_names) = 0;
1343 (*sid_mem) = NULL;
1344 (*names) = NULL;
1345 (*name_types) = NULL;
1347 /* Return status value returned by seq number check */
1349 if (!NT_STATUS_IS_OK(domain->last_status))
1350 return domain->last_status;
1352 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
1353 domain->name ));
1355 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid, num_names,
1356 sid_mem, names, name_types);
1358 /* and save it */
1359 refresh_sequence_number(domain, False);
1360 centry = centry_start(domain, status);
1361 if (!centry)
1362 goto skip_save;
1363 centry_put_uint32(centry, *num_names);
1364 for (i=0; i<(*num_names); i++) {
1365 centry_put_sid(centry, &(*sid_mem)[i]);
1366 centry_put_string(centry, (*names)[i]);
1367 centry_put_uint32(centry, (*name_types)[i]);
1369 centry_end(centry, "GM/%s", sid_to_string(sid_string, group_sid));
1370 centry_free(centry);
1372 skip_save:
1373 return status;
1376 /* find the sequence number for a domain */
1377 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
1379 refresh_sequence_number(domain, False);
1381 *seq = domain->sequence_number;
1383 return NT_STATUS_OK;
1386 /* enumerate trusted domains */
1387 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1388 TALLOC_CTX *mem_ctx,
1389 uint32 *num_domains,
1390 char ***names,
1391 char ***alt_names,
1392 DOM_SID **dom_sids)
1394 get_cache(domain);
1396 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
1397 domain->name ));
1399 /* we don't cache this call */
1400 return domain->backend->trusted_domains(domain, mem_ctx, num_domains,
1401 names, alt_names, dom_sids);
1404 /* find the alternate names for the domain, if any */
1405 static NTSTATUS alternate_name(struct winbindd_domain *domain)
1407 get_cache(domain);
1409 DEBUG(10,("alternate_name: [Cached] - doing backend query for info for domain %s\n",
1410 domain->name ));
1412 /* we don't cache this call */
1413 return domain->backend->alternate_name(domain);
1416 /* Invalidate cached user and group lists coherently */
1418 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
1419 void *state)
1421 if (strncmp(kbuf.dptr, "UL/", 3) == 0 ||
1422 strncmp(kbuf.dptr, "GL/", 3) == 0)
1423 tdb_delete(the_tdb, kbuf);
1425 return 0;
1428 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
1430 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
1431 NET_USER_INFO_3 *info3)
1433 struct winbind_cache *cache;
1435 if (!domain)
1436 return;
1438 cache = get_cache(domain);
1439 netsamlogon_clear_cached_user(cache->tdb, info3);
1442 void wcache_invalidate_cache(void)
1444 struct winbindd_domain *domain;
1446 for (domain = domain_list(); domain; domain = domain->next) {
1447 struct winbind_cache *cache = get_cache(domain);
1449 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
1450 "entries for %s\n", domain->name));
1451 if (cache)
1452 tdb_traverse(cache->tdb, traverse_fn, NULL);
1456 /* the ADS backend methods are exposed via this structure */
1457 struct winbindd_methods cache_methods = {
1458 True,
1459 query_user_list,
1460 enum_dom_groups,
1461 enum_local_groups,
1462 name_to_sid,
1463 sid_to_name,
1464 query_user,
1465 lookup_usergroups,
1466 lookup_useraliases,
1467 lookup_groupmem,
1468 sequence_number,
1469 trusted_domains,
1470 alternate_name
1473 static BOOL init_wcache(void)
1475 if (wcache == NULL) {
1476 wcache = SMB_XMALLOC_P(struct winbind_cache);
1477 ZERO_STRUCTP(wcache);
1480 if (wcache->tdb != NULL)
1481 return True;
1483 wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 5000,
1484 TDB_CLEAR_IF_FIRST, O_RDWR|O_CREAT, 0600);
1486 if (wcache->tdb == NULL) {
1487 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
1488 return False;
1491 return True;
1494 void cache_store_response(pid_t pid, struct winbindd_response *response)
1496 fstring key_str;
1498 if (!init_wcache())
1499 return;
1501 DEBUG(10, ("Storing response for pid %d, len %d\n",
1502 pid, response->length));
1504 fstr_sprintf(key_str, "DR/%d", pid);
1505 if (tdb_store(wcache->tdb, string_tdb_data(key_str),
1506 make_tdb_data((void *)response, sizeof(*response)),
1507 TDB_REPLACE) == -1)
1508 return;
1510 if (response->length == sizeof(*response))
1511 return;
1513 /* There's extra data */
1515 DEBUG(10, ("Storing extra data: len=%d\n",
1516 (int)(response->length - sizeof(*response))));
1518 fstr_sprintf(key_str, "DE/%d", pid);
1519 if (tdb_store(wcache->tdb, string_tdb_data(key_str),
1520 make_tdb_data(response->extra_data,
1521 response->length - sizeof(*response)),
1522 TDB_REPLACE) == 0)
1523 return;
1525 /* We could not store the extra data, make sure the tdb does not
1526 * contain a main record with wrong dangling extra data */
1528 fstr_sprintf(key_str, "DR/%d", pid);
1529 tdb_delete(wcache->tdb, string_tdb_data(key_str));
1531 return;
1534 BOOL cache_retrieve_response(pid_t pid, struct winbindd_response * response)
1536 TDB_DATA data;
1537 fstring key_str;
1539 if (!init_wcache())
1540 return False;
1542 DEBUG(10, ("Retrieving response for pid %d\n", pid));
1544 fstr_sprintf(key_str, "DR/%d", pid);
1545 data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
1547 if (data.dptr == NULL)
1548 return False;
1550 if (data.dsize != sizeof(*response))
1551 return False;
1553 memcpy(response, data.dptr, data.dsize);
1554 SAFE_FREE(data.dptr);
1556 if (response->length == sizeof(*response)) {
1557 response->extra_data = NULL;
1558 return True;
1561 /* There's extra data */
1563 DEBUG(10, ("Retrieving extra data length=%d\n",
1564 (int)(response->length - sizeof(*response))));
1566 fstr_sprintf(key_str, "DE/%d", pid);
1567 data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
1569 if (data.dptr == NULL) {
1570 DEBUG(0, ("Did not find extra data\n"));
1571 return False;
1574 if (data.dsize != (response->length - sizeof(*response))) {
1575 DEBUG(0, ("Invalid extra data length: %d\n", (int)data.dsize));
1576 SAFE_FREE(data.dptr);
1577 return False;
1580 dump_data(11, data.dptr, data.dsize);
1582 response->extra_data = data.dptr;
1583 return True;
1586 BOOL lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
1587 const char **domain_name, const char **name,
1588 enum SID_NAME_USE *type)
1590 struct winbindd_domain *domain;
1591 struct winbind_cache *cache;
1592 struct cache_entry *centry = NULL;
1593 NTSTATUS status;
1595 domain = find_lookup_domain_from_sid(sid);
1596 if (domain == NULL) {
1597 return False;
1600 cache = get_cache(domain);
1602 if (cache->tdb == NULL) {
1603 return False;
1606 centry = wcache_fetch(cache, domain, "SN/%s", sid_string_static(sid));
1607 if (centry == NULL) {
1608 return False;
1611 if (NT_STATUS_IS_OK(centry->status)) {
1612 *type = (enum SID_NAME_USE)centry_uint32(centry);
1613 *domain_name = centry_string(centry, mem_ctx);
1614 *name = centry_string(centry, mem_ctx);
1617 status = centry->status;
1618 centry_free(centry);
1619 return NT_STATUS_IS_OK(status);
1622 void cache_sid2name(struct winbindd_domain *domain, const DOM_SID *sid,
1623 const char *domain_name, const char *name,
1624 enum SID_NAME_USE type)
1626 wcache_save_sid_to_name(domain, NT_STATUS_OK, sid, domain_name,
1627 name, type);