ensure that 'available = no' works for [homes]; reported by Walter Haidinger
[Samba.git] / source / nsswitch / winbindd_cache.c
blob920b0d388d722cce73fbac11edda7b2cf22ca5cb
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind cache backend functions
6 Copyright (C) Andrew Tridgell 2001
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "winbindd.h"
25 struct winbind_cache {
26 struct winbindd_methods *backend;
27 TDB_CONTEXT *tdb;
30 struct cache_entry {
31 NTSTATUS status;
32 uint32 sequence_number;
33 uint8 *data;
34 uint32 len, ofs;
37 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
39 static struct winbind_cache *wcache;
41 /* flush the cache */
42 void wcache_flush_cache(void)
44 extern BOOL opt_nocache;
46 if (!wcache) return;
47 if (wcache->tdb) {
48 tdb_close(wcache->tdb);
49 wcache->tdb = NULL;
51 if (opt_nocache) return;
53 wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 5000,
54 TDB_DEFAULT, O_RDWR | O_CREAT | O_TRUNC, 0600);
56 if (!wcache->tdb) {
57 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
61 void winbindd_check_cache_size(time_t t)
63 static time_t last_check_time;
64 struct stat st;
66 if (last_check_time == (time_t)0)
67 last_check_time = t;
69 if (t - last_check_time < 60 && t - last_check_time > 0)
70 return;
72 if (wcache == NULL || wcache->tdb == NULL) {
73 DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
74 return;
77 if (fstat(wcache->tdb->fd, &st) == -1) {
78 DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno) ));
79 return;
82 if (st.st_size > WINBINDD_MAX_CACHE_SIZE) {
83 DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
84 (unsigned long)st.st_size,
85 (unsigned long)WINBINDD_MAX_CACHE_SIZE));
86 wcache_flush_cache();
90 /* get the winbind_cache structure */
91 static struct winbind_cache *get_cache(struct winbindd_domain *domain)
93 extern struct winbindd_methods msrpc_methods;
94 struct winbind_cache *ret = wcache;
96 if (ret) return ret;
98 ret = smb_xmalloc(sizeof(*ret));
99 ZERO_STRUCTP(ret);
100 switch (lp_security()) {
101 #ifdef HAVE_ADS
102 case SEC_ADS: {
103 extern struct winbindd_methods ads_methods;
104 ret->backend = &ads_methods;
105 break;
107 #endif
108 default:
109 ret->backend = &msrpc_methods;
112 wcache = ret;
113 wcache_flush_cache();
115 return ret;
119 free a centry structure
121 static void centry_free(struct cache_entry *centry)
123 if (!centry) return;
124 SAFE_FREE(centry->data);
125 free(centry);
130 pull a uint32 from a cache entry
132 static uint32 centry_uint32(struct cache_entry *centry)
134 uint32 ret;
135 if (centry->len - centry->ofs < 4) {
136 DEBUG(0,("centry corruption? needed 4 bytes, have %d\n",
137 centry->len - centry->ofs));
138 smb_panic("centry_uint32");
140 ret = IVAL(centry->data, centry->ofs);
141 centry->ofs += 4;
142 return ret;
146 pull a uint8 from a cache entry
148 static uint8 centry_uint8(struct cache_entry *centry)
150 uint8 ret;
151 if (centry->len - centry->ofs < 1) {
152 DEBUG(0,("centry corruption? needed 1 bytes, have %d\n",
153 centry->len - centry->ofs));
154 smb_panic("centry_uint32");
156 ret = CVAL(centry->data, centry->ofs);
157 centry->ofs += 1;
158 return ret;
161 /* pull a string from a cache entry, using the supplied
162 talloc context
164 static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
166 uint32 len;
167 char *ret;
169 len = centry_uint8(centry);
171 if (len == 0xFF) {
172 /* a deliberate NULL string */
173 return NULL;
176 if (centry->len - centry->ofs < len) {
177 DEBUG(0,("centry corruption? needed %d bytes, have %d\n",
178 len, centry->len - centry->ofs));
179 smb_panic("centry_string");
182 ret = talloc(mem_ctx, len+1);
183 if (!ret) {
184 smb_panic("centry_string out of memory\n");
186 memcpy(ret,centry->data + centry->ofs, len);
187 ret[len] = 0;
188 centry->ofs += len;
189 return ret;
192 /* the server is considered down if it can't give us a sequence number */
193 static BOOL wcache_server_down(struct winbindd_domain *domain)
195 if (!wcache->tdb) return False;
196 return (domain->sequence_number == DOM_SEQUENCE_NONE);
201 refresh the domain sequence number. If force is True
202 then always refresh it, no matter how recently we fetched it
204 static void refresh_sequence_number(struct winbindd_domain *domain, BOOL force)
206 NTSTATUS status;
207 unsigned time_diff;
209 time_diff = time(NULL) - domain->last_seq_check;
211 /* see if we have to refetch the domain sequence number */
212 if (!force && (time_diff < lp_winbind_cache_time())) {
213 return;
216 status = wcache->backend->sequence_number(domain, &domain->sequence_number);
218 if (!NT_STATUS_IS_OK(status))
219 DEBUG(10, ("refresh_sequence_number: backend returned 0x%08x\n",
220 NT_STATUS_V(status)));
222 /* Convert a NT_STATUS_UNSUCCESSFUL error to a
223 NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND. The former is
224 returned when we can't make an initial connection to
225 the domain controller. The latter is returned when we
226 can't fetch the sequence number on an already open
227 connection. */
229 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL))
230 status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
232 domain->last_status = status;
234 if (!NT_STATUS_IS_OK(status))
235 domain->sequence_number = DOM_SEQUENCE_NONE;
237 domain->last_seq_check = time(NULL);
239 DEBUG(10, ("refresh_sequence_number: seq number is now %d\n",
240 domain->sequence_number));
244 decide if a cache entry has expired
246 static BOOL centry_expired(struct winbindd_domain *domain, struct cache_entry *centry)
248 /* if the server is OK and our cache entry came from when it was down then
249 the entry is invalid */
250 if (domain->sequence_number != DOM_SEQUENCE_NONE &&
251 centry->sequence_number == DOM_SEQUENCE_NONE) {
252 return True;
255 /* if the server is down or the cache entry is not older than the
256 current sequence number then it is OK */
257 if (wcache_server_down(domain) ||
258 centry->sequence_number == domain->sequence_number) {
259 return False;
262 /* it's expired */
263 return True;
267 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
268 number and return status
270 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
271 struct winbindd_domain *domain,
272 const char *format, ...)
274 va_list ap;
275 char *kstr;
276 TDB_DATA data;
277 struct cache_entry *centry;
278 TDB_DATA key;
280 refresh_sequence_number(domain, False);
282 va_start(ap, format);
283 smb_xvasprintf(&kstr, format, ap);
284 va_end(ap);
286 key.dptr = kstr;
287 key.dsize = strlen(kstr);
288 data = tdb_fetch(wcache->tdb, key);
289 free(kstr);
290 if (!data.dptr) {
291 /* a cache miss */
292 return NULL;
295 centry = smb_xmalloc(sizeof(*centry));
296 centry->data = (uchar *)data.dptr;
297 centry->len = data.dsize;
298 centry->ofs = 0;
300 if (centry->len < 8) {
301 /* huh? corrupt cache? */
302 centry_free(centry);
303 return NULL;
306 centry->status = NT_STATUS(centry_uint32(centry));
307 centry->sequence_number = centry_uint32(centry);
309 if (centry_expired(domain, centry)) {
310 centry_free(centry);
311 return NULL;
314 return centry;
318 make sure we have at least len bytes available in a centry
320 static void centry_expand(struct cache_entry *centry, uint32 len)
322 uint8 *p;
323 if (centry->len - centry->ofs >= len) return;
324 centry->len *= 2;
325 p = realloc(centry->data, centry->len);
326 if (!p) {
327 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
328 smb_panic("out of memory in centry_expand");
330 centry->data = p;
334 push a uint32 into a centry
336 static void centry_put_uint32(struct cache_entry *centry, uint32 v)
338 centry_expand(centry, 4);
339 SIVAL(centry->data, centry->ofs, v);
340 centry->ofs += 4;
344 push a uint8 into a centry
346 static void centry_put_uint8(struct cache_entry *centry, uint8 v)
348 centry_expand(centry, 1);
349 SCVAL(centry->data, centry->ofs, v);
350 centry->ofs += 1;
354 push a string into a centry
356 static void centry_put_string(struct cache_entry *centry, const char *s)
358 int len;
360 if (!s) {
361 /* null strings are marked as len 0xFFFF */
362 centry_put_uint8(centry, 0xFF);
363 return;
366 len = strlen(s);
367 /* can't handle more than 254 char strings. Truncating is probably best */
368 if (len > 254) len = 254;
369 centry_put_uint8(centry, len);
370 centry_expand(centry, len);
371 memcpy(centry->data + centry->ofs, s, len);
372 centry->ofs += len;
376 start a centry for output. When finished, call centry_end()
378 struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status)
380 struct cache_entry *centry;
382 if (!wcache->tdb) return NULL;
384 centry = smb_xmalloc(sizeof(*centry));
386 centry->len = 8192; /* reasonable default */
387 centry->data = smb_xmalloc(centry->len);
388 centry->ofs = 0;
389 centry->sequence_number = domain->sequence_number;
390 centry_put_uint32(centry, NT_STATUS_V(status));
391 centry_put_uint32(centry, centry->sequence_number);
392 return centry;
396 finish a centry and write it to the tdb
398 static void centry_end(struct cache_entry *centry, const char *format, ...)
400 va_list ap;
401 char *kstr;
402 TDB_DATA key, data;
404 va_start(ap, format);
405 smb_xvasprintf(&kstr, format, ap);
406 va_end(ap);
408 key.dptr = kstr;
409 key.dsize = strlen(kstr);
410 data.dptr = (char *)centry->data;
411 data.dsize = centry->ofs;
413 tdb_store(wcache->tdb, key, data, TDB_REPLACE);
414 free(kstr);
417 /* form a sid from the domain plus rid */
418 static DOM_SID *form_sid(struct winbindd_domain *domain, uint32 rid)
420 static DOM_SID sid;
421 sid_copy(&sid, &domain->sid);
422 sid_append_rid(&sid, rid);
423 return &sid;
426 static void wcache_save_name_to_sid(struct winbindd_domain *domain, NTSTATUS status,
427 const char *name, DOM_SID *sid, enum SID_NAME_USE type)
429 struct cache_entry *centry;
430 uint32 len;
431 fstring uname;
433 centry = centry_start(domain, status);
434 if (!centry) return;
435 len = sid_size(sid);
436 centry_expand(centry, len);
437 centry_put_uint32(centry, type);
438 sid_linearize((char *)centry->data + centry->ofs, len, sid);
439 centry->ofs += len;
440 fstrcpy(uname, name);
441 strupper(uname);
442 centry_end(centry, "NS/%s/%s", domain->name, uname);
443 centry_free(centry);
446 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
447 DOM_SID *sid, const char *name, enum SID_NAME_USE type, uint32 rid)
449 struct cache_entry *centry;
451 centry = centry_start(domain, status);
452 if (!centry) return;
453 if (NT_STATUS_IS_OK(status)) {
454 centry_put_uint32(centry, type);
455 centry_put_string(centry, name);
457 centry_end(centry, "SN/%s/%d", domain->name, rid);
458 centry_free(centry);
462 static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status, WINBIND_USERINFO *info)
464 struct cache_entry *centry;
466 centry = centry_start(domain, status);
467 if (!centry) return;
468 centry_put_string(centry, info->acct_name);
469 centry_put_string(centry, info->full_name);
470 centry_put_uint32(centry, info->user_rid);
471 centry_put_uint32(centry, info->group_rid);
472 centry_end(centry, "U/%s/%d", domain->name, info->user_rid);
473 centry_free(centry);
477 /* Query display info. This is the basic user list fn */
478 static NTSTATUS query_user_list(struct winbindd_domain *domain,
479 TALLOC_CTX *mem_ctx,
480 uint32 *num_entries,
481 WINBIND_USERINFO **info)
483 struct winbind_cache *cache = get_cache(domain);
484 struct cache_entry *centry = NULL;
485 NTSTATUS status;
486 int i;
488 if (!cache->tdb) goto do_query;
490 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
491 if (!centry) goto do_query;
493 *num_entries = centry_uint32(centry);
495 if (*num_entries == 0) goto do_cached;
497 (*info) = talloc(mem_ctx, sizeof(**info) * (*num_entries));
498 if (! (*info)) smb_panic("query_user_list out of memory");
499 for (i=0; i<(*num_entries); i++) {
500 (*info)[i].acct_name = centry_string(centry, mem_ctx);
501 (*info)[i].full_name = centry_string(centry, mem_ctx);
502 (*info)[i].user_rid = centry_uint32(centry);
503 (*info)[i].group_rid = centry_uint32(centry);
506 do_cached:
508 /* If we are returning cached data and the domain controller
509 is down then we don't know whether the data is up to date
510 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
511 indicate this. */
513 if (wcache_server_down(domain)) {
514 DEBUG(10, ("query_user_list: returning cached user list and server was down\n"));
515 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
516 } else
517 status = centry->status;
519 centry_free(centry);
520 return status;
522 do_query:
523 *num_entries = 0;
524 *info = NULL;
526 /* Return status value returned by seq number check */
528 if (!NT_STATUS_IS_OK(domain->last_status))
529 return domain->last_status;
531 status = cache->backend->query_user_list(domain, mem_ctx, num_entries, info);
533 /* and save it */
534 refresh_sequence_number(domain, True);
535 centry = centry_start(domain, status);
536 if (!centry) goto skip_save;
537 centry_put_uint32(centry, *num_entries);
538 for (i=0; i<(*num_entries); i++) {
539 centry_put_string(centry, (*info)[i].acct_name);
540 centry_put_string(centry, (*info)[i].full_name);
541 centry_put_uint32(centry, (*info)[i].user_rid);
542 centry_put_uint32(centry, (*info)[i].group_rid);
543 if (cache->backend->consistent) {
544 /* when the backend is consistent we can pre-prime some mappings */
545 wcache_save_name_to_sid(domain, NT_STATUS_OK,
546 (*info)[i].acct_name,
547 form_sid(domain, (*info)[i].user_rid),
548 SID_NAME_USER);
549 wcache_save_sid_to_name(domain, NT_STATUS_OK,
550 form_sid(domain, (*info)[i].user_rid),
551 (*info)[i].acct_name,
552 SID_NAME_USER, (*info)[i].user_rid);
553 wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
556 centry_end(centry, "UL/%s", domain->name);
557 centry_free(centry);
559 skip_save:
560 return status;
563 /* list all domain groups */
564 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
565 TALLOC_CTX *mem_ctx,
566 uint32 *num_entries,
567 struct acct_info **info)
569 struct winbind_cache *cache = get_cache(domain);
570 struct cache_entry *centry = NULL;
571 NTSTATUS status;
572 int i;
574 if (!cache->tdb) goto do_query;
576 centry = wcache_fetch(cache, domain, "GL/%s", domain->name);
577 if (!centry) goto do_query;
579 *num_entries = centry_uint32(centry);
581 if (*num_entries == 0) goto do_cached;
583 (*info) = talloc(mem_ctx, sizeof(**info) * (*num_entries));
584 if (! (*info)) smb_panic("enum_dom_groups out of memory");
585 for (i=0; i<(*num_entries); i++) {
586 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
587 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
588 (*info)[i].rid = centry_uint32(centry);
591 do_cached:
593 /* If we are returning cached data and the domain controller
594 is down then we don't know whether the data is up to date
595 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
596 indicate this. */
598 if (wcache_server_down(domain)) {
599 DEBUG(10, ("query_user_list: returning cached user list and server was down\n"));
600 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
601 } else
602 status = centry->status;
604 centry_free(centry);
605 return status;
607 do_query:
608 *num_entries = 0;
609 *info = NULL;
611 /* Return status value returned by seq number check */
613 if (!NT_STATUS_IS_OK(domain->last_status))
614 return domain->last_status;
616 status = cache->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
618 /* and save it */
619 refresh_sequence_number(domain, True);
620 centry = centry_start(domain, status);
621 if (!centry) goto skip_save;
622 centry_put_uint32(centry, *num_entries);
623 for (i=0; i<(*num_entries); i++) {
624 centry_put_string(centry, (*info)[i].acct_name);
625 centry_put_string(centry, (*info)[i].acct_desc);
626 centry_put_uint32(centry, (*info)[i].rid);
628 centry_end(centry, "GL/%s", domain->name);
629 centry_free(centry);
631 skip_save:
632 return status;
636 /* convert a single name to a sid in a domain */
637 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
638 const char *name,
639 DOM_SID *sid,
640 enum SID_NAME_USE *type)
642 struct winbind_cache *cache = get_cache(domain);
643 struct cache_entry *centry = NULL;
644 NTSTATUS status;
645 fstring uname;
647 if (!cache->tdb) goto do_query;
649 fstrcpy(uname, name);
650 strupper(uname);
651 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain->name, uname);
652 if (!centry) goto do_query;
653 *type = centry_uint32(centry);
654 sid_parse((char *)centry->data + centry->ofs, centry->len - centry->ofs, sid);
656 status = centry->status;
657 centry_free(centry);
658 return status;
660 do_query:
661 ZERO_STRUCTP(sid);
663 /* Return status value returned by seq number check */
665 if (!NT_STATUS_IS_OK(domain->last_status))
666 return domain->last_status;
668 status = cache->backend->name_to_sid(domain, name, sid, type);
670 /* and save it */
671 wcache_save_name_to_sid(domain, status, name, sid, *type);
673 /* We can't save the sid to name mapping as we don't know the
674 correct case of the name without looking it up */
676 return status;
679 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
680 given */
681 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
682 TALLOC_CTX *mem_ctx,
683 DOM_SID *sid,
684 char **name,
685 enum SID_NAME_USE *type)
687 struct winbind_cache *cache = get_cache(domain);
688 struct cache_entry *centry = NULL;
689 NTSTATUS status;
690 uint32 rid = 0;
692 sid_peek_rid(sid, &rid);
694 if (!cache->tdb) goto do_query;
696 centry = wcache_fetch(cache, domain, "SN/%s/%d", domain->name, rid);
697 if (!centry) goto do_query;
698 if (NT_STATUS_IS_OK(centry->status)) {
699 *type = centry_uint32(centry);
700 *name = centry_string(centry, mem_ctx);
702 status = centry->status;
703 centry_free(centry);
704 return status;
706 do_query:
707 *name = NULL;
709 /* Return status value returned by seq number check */
711 if (!NT_STATUS_IS_OK(domain->last_status))
712 return domain->last_status;
714 status = cache->backend->sid_to_name(domain, mem_ctx, sid, name, type);
716 /* and save it */
717 refresh_sequence_number(domain, True);
718 wcache_save_sid_to_name(domain, status, sid, *name, *type, rid);
719 wcache_save_name_to_sid(domain, status, *name, sid, *type);
721 return status;
725 /* Lookup user information from a rid */
726 static NTSTATUS query_user(struct winbindd_domain *domain,
727 TALLOC_CTX *mem_ctx,
728 uint32 user_rid,
729 WINBIND_USERINFO *info)
731 struct winbind_cache *cache = get_cache(domain);
732 struct cache_entry *centry = NULL;
733 NTSTATUS status;
735 if (!cache->tdb) goto do_query;
737 centry = wcache_fetch(cache, domain, "U/%s/%d", domain->name, user_rid);
738 if (!centry) goto do_query;
740 info->acct_name = centry_string(centry, mem_ctx);
741 info->full_name = centry_string(centry, mem_ctx);
742 info->user_rid = centry_uint32(centry);
743 info->group_rid = centry_uint32(centry);
744 status = centry->status;
745 centry_free(centry);
746 return status;
748 do_query:
749 ZERO_STRUCTP(info);
751 /* Return status value returned by seq number check */
753 if (!NT_STATUS_IS_OK(domain->last_status))
754 return domain->last_status;
756 status = cache->backend->query_user(domain, mem_ctx, user_rid, info);
758 /* and save it */
759 refresh_sequence_number(domain, True);
760 wcache_save_user(domain, status, info);
762 return status;
766 /* Lookup groups a user is a member of. */
767 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
768 TALLOC_CTX *mem_ctx,
769 uint32 user_rid,
770 uint32 *num_groups, uint32 **user_gids)
772 struct winbind_cache *cache = get_cache(domain);
773 struct cache_entry *centry = NULL;
774 NTSTATUS status;
775 int i;
777 if (!cache->tdb) goto do_query;
779 centry = wcache_fetch(cache, domain, "UG/%s/%d", domain->name, user_rid);
780 if (!centry) goto do_query;
782 *num_groups = centry_uint32(centry);
784 if (*num_groups == 0) goto do_cached;
786 (*user_gids) = talloc(mem_ctx, sizeof(**user_gids) * (*num_groups));
787 if (! (*user_gids)) smb_panic("lookup_usergroups out of memory");
788 for (i=0; i<(*num_groups); i++) {
789 (*user_gids)[i] = centry_uint32(centry);
792 do_cached:
793 status = centry->status;
794 centry_free(centry);
795 return status;
797 do_query:
798 (*num_groups) = 0;
799 (*user_gids) = NULL;
801 /* Return status value returned by seq number check */
803 if (!NT_STATUS_IS_OK(domain->last_status))
804 return domain->last_status;
806 status = cache->backend->lookup_usergroups(domain, mem_ctx, user_rid, num_groups, user_gids);
808 /* and save it */
809 refresh_sequence_number(domain, True);
810 centry = centry_start(domain, status);
811 if (!centry) goto skip_save;
812 centry_put_uint32(centry, *num_groups);
813 for (i=0; i<(*num_groups); i++) {
814 centry_put_uint32(centry, (*user_gids)[i]);
816 centry_end(centry, "UG/%s/%d", domain->name, user_rid);
817 centry_free(centry);
819 skip_save:
820 return status;
824 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
825 TALLOC_CTX *mem_ctx,
826 uint32 group_rid, uint32 *num_names,
827 uint32 **rid_mem, char ***names,
828 uint32 **name_types)
830 struct winbind_cache *cache = get_cache(domain);
831 struct cache_entry *centry = NULL;
832 NTSTATUS status;
833 int i;
835 if (!cache->tdb) goto do_query;
837 centry = wcache_fetch(cache, domain, "GM/%s/%d", domain->name, group_rid);
838 if (!centry) goto do_query;
840 *num_names = centry_uint32(centry);
842 if (*num_names == 0) goto do_cached;
844 (*rid_mem) = talloc(mem_ctx, sizeof(**rid_mem) * (*num_names));
845 (*names) = talloc(mem_ctx, sizeof(**names) * (*num_names));
846 (*name_types) = talloc(mem_ctx, sizeof(**name_types) * (*num_names));
848 if (! (*rid_mem) || ! (*names) || ! (*name_types)) {
849 smb_panic("lookup_groupmem out of memory");
852 for (i=0; i<(*num_names); i++) {
853 (*rid_mem)[i] = centry_uint32(centry);
854 (*names)[i] = centry_string(centry, mem_ctx);
855 (*name_types)[i] = centry_uint32(centry);
858 do_cached:
859 status = centry->status;
860 centry_free(centry);
861 return status;
863 do_query:
864 (*num_names) = 0;
865 (*rid_mem) = NULL;
866 (*names) = NULL;
867 (*name_types) = NULL;
869 /* Return status value returned by seq number check */
871 if (!NT_STATUS_IS_OK(domain->last_status))
872 return domain->last_status;
874 status = cache->backend->lookup_groupmem(domain, mem_ctx, group_rid, num_names,
875 rid_mem, names, name_types);
877 /* and save it */
878 refresh_sequence_number(domain, True);
879 centry = centry_start(domain, status);
880 if (!centry) goto skip_save;
881 centry_put_uint32(centry, *num_names);
882 for (i=0; i<(*num_names); i++) {
883 centry_put_uint32(centry, (*rid_mem)[i]);
884 centry_put_string(centry, (*names)[i]);
885 centry_put_uint32(centry, (*name_types)[i]);
887 centry_end(centry, "GM/%s/%d", domain->name, group_rid);
888 centry_free(centry);
890 skip_save:
891 return status;
894 /* find the sequence number for a domain */
895 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
897 refresh_sequence_number(domain, False);
899 *seq = domain->sequence_number;
901 return NT_STATUS_OK;
904 /* enumerate trusted domains */
905 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
906 TALLOC_CTX *mem_ctx,
907 uint32 *num_domains,
908 char ***names,
909 DOM_SID **dom_sids)
911 struct winbind_cache *cache = get_cache(domain);
913 /* we don't cache this call */
914 return cache->backend->trusted_domains(domain, mem_ctx, num_domains,
915 names, dom_sids);
918 /* find the domain sid */
919 static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
921 struct winbind_cache *cache = get_cache(domain);
923 /* we don't cache this call */
924 return cache->backend->domain_sid(domain, sid);
927 /* the ADS backend methods are exposed via this structure */
928 struct winbindd_methods cache_methods = {
929 True,
930 query_user_list,
931 enum_dom_groups,
932 name_to_sid,
933 sid_to_name,
934 query_user,
935 lookup_usergroups,
936 lookup_groupmem,
937 sequence_number,
938 trusted_domains,
939 domain_sid