r6225: get rid of warnings from my compiler about nested externs
[sfrench/samba-autobuild/.git] / source / nsswitch / winbindd_cache.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Winbind cache backend functions
5
6    Copyright (C) Andrew Tridgell 2001
7    Copyright (C) Gerald Carter   2003
8    Copyright (C) Volker Lendecke 2005
9    
10    
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.
15    
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.
20    
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.
24 */
25
26 #include "includes.h"
27 #include "winbindd.h"
28
29 extern BOOL opt_nocache;
30 extern struct winbindd_methods msrpc_methods;
31 extern struct winbindd_methods ads_methods;
32 extern BOOL opt_dual_daemon;
33 extern BOOL background_process;
34
35 #undef DBGC_CLASS
36 #define DBGC_CLASS DBGC_WINBIND
37
38 struct winbind_cache {
39         TDB_CONTEXT *tdb;
40 };
41
42 struct cache_entry {
43         NTSTATUS status;
44         uint32 sequence_number;
45         uint8 *data;
46         uint32 len, ofs;
47 };
48
49 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
50
51 static struct winbind_cache *wcache;
52
53 /* flush the cache */
54 void wcache_flush_cache(void)
55 {
56         if (!wcache)
57                 return;
58         if (wcache->tdb) {
59                 tdb_close(wcache->tdb);
60                 wcache->tdb = NULL;
61         }
62         if (opt_nocache)
63                 return;
64
65         wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), 5000, 
66                                    TDB_CLEAR_IF_FIRST, O_RDWR|O_CREAT, 0600);
67
68         if (!wcache->tdb) {
69                 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
70         }
71         DEBUG(10,("wcache_flush_cache success\n"));
72 }
73
74 void winbindd_check_cache_size(time_t t)
75 {
76         static time_t last_check_time;
77         struct stat st;
78
79         if (last_check_time == (time_t)0)
80                 last_check_time = t;
81
82         if (t - last_check_time < 60 && t - last_check_time > 0)
83                 return;
84
85         if (wcache == NULL || wcache->tdb == NULL) {
86                 DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
87                 return;
88         }
89
90         if (fstat(wcache->tdb->fd, &st) == -1) {
91                 DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno) ));
92                 return;
93         }
94
95         if (st.st_size > WINBINDD_MAX_CACHE_SIZE) {
96                 DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
97                         (unsigned long)st.st_size,
98                         (unsigned long)WINBINDD_MAX_CACHE_SIZE));
99                 wcache_flush_cache();
100         }
101 }
102
103 /* get the winbind_cache structure */
104 static struct winbind_cache *get_cache(struct winbindd_domain *domain)
105 {
106         struct winbind_cache *ret = wcache;
107
108         if (!domain->backend) {
109                 switch (lp_security()) {
110 #ifdef HAVE_ADS
111                 case SEC_ADS: {
112                         /* always obey the lp_security parameter for our domain */
113                         if (domain->primary) {
114                                 domain->backend = &ads_methods;
115                                 break;
116                         }
117
118                         /* only use ADS for native modes at the momment.
119                            The problem is the correct detection of mixed 
120                            mode domains from NT4 BDC's    --jerry */
121                         
122                         if ( domain->native_mode ) {
123                                 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n",
124                                         domain->name));
125                                 domain->backend = &ads_methods;
126                                 break;
127                         }
128
129                         /* fall through */
130                 }       
131 #endif
132                 default:
133                         DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n",
134                                 domain->name));
135                         domain->backend = &msrpc_methods;
136                 }
137         }
138
139         if (ret)
140                 return ret;
141         
142         ret = SMB_XMALLOC_P(struct winbind_cache);
143         ZERO_STRUCTP(ret);
144
145         wcache = ret;
146         wcache_flush_cache();
147
148         return ret;
149 }
150
151 /*
152   free a centry structure
153 */
154 static void centry_free(struct cache_entry *centry)
155 {
156         if (!centry)
157                 return;
158         SAFE_FREE(centry->data);
159         free(centry);
160 }
161
162 /*
163   pull a uint32 from a cache entry 
164 */
165 static uint32 centry_uint32(struct cache_entry *centry)
166 {
167         uint32 ret;
168         if (centry->len - centry->ofs < 4) {
169                 DEBUG(0,("centry corruption? needed 4 bytes, have %d\n", 
170                          centry->len - centry->ofs));
171                 smb_panic("centry_uint32");
172         }
173         ret = IVAL(centry->data, centry->ofs);
174         centry->ofs += 4;
175         return ret;
176 }
177
178 /*
179   pull a uint8 from a cache entry 
180 */
181 static uint8 centry_uint8(struct cache_entry *centry)
182 {
183         uint8 ret;
184         if (centry->len - centry->ofs < 1) {
185                 DEBUG(0,("centry corruption? needed 1 bytes, have %d\n", 
186                          centry->len - centry->ofs));
187                 smb_panic("centry_uint32");
188         }
189         ret = CVAL(centry->data, centry->ofs);
190         centry->ofs += 1;
191         return ret;
192 }
193
194 /* pull a string from a cache entry, using the supplied
195    talloc context 
196 */
197 static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
198 {
199         uint32 len;
200         char *ret;
201
202         len = centry_uint8(centry);
203
204         if (len == 0xFF) {
205                 /* a deliberate NULL string */
206                 return NULL;
207         }
208
209         if (centry->len - centry->ofs < len) {
210                 DEBUG(0,("centry corruption? needed %d bytes, have %d\n", 
211                          len, centry->len - centry->ofs));
212                 smb_panic("centry_string");
213         }
214
215         ret = TALLOC(mem_ctx, len+1);
216         if (!ret) {
217                 smb_panic("centry_string out of memory\n");
218         }
219         memcpy(ret,centry->data + centry->ofs, len);
220         ret[len] = 0;
221         centry->ofs += len;
222         return ret;
223 }
224
225 /* pull a string from a cache entry, using the supplied
226    talloc context 
227 */
228 static DOM_SID *centry_sid(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
229 {
230         DOM_SID *sid;
231         char *sid_string;
232
233         sid = TALLOC_P(mem_ctx, DOM_SID);
234         if (!sid)
235                 return NULL;
236         
237         sid_string = centry_string(centry, mem_ctx);
238         if (!string_to_sid(sid, sid_string)) {
239                 return NULL;
240         }
241         return sid;
242 }
243
244 /* the server is considered down if it can't give us a sequence number */
245 static BOOL wcache_server_down(struct winbindd_domain *domain)
246 {
247         BOOL ret;
248
249         if (!wcache->tdb)
250                 return False;
251
252         ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
253
254         if (ret)
255                 DEBUG(10,("wcache_server_down: server for Domain %s down\n", 
256                         domain->name ));
257         return ret;
258 }
259
260 static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
261 {
262         TDB_DATA data;
263         fstring key;
264         uint32 time_diff;
265         
266         if (!wcache->tdb) {
267                 DEBUG(10,("fetch_cache_seqnum: tdb == NULL\n"));
268                 return NT_STATUS_UNSUCCESSFUL;
269         }
270                 
271         fstr_sprintf( key, "SEQNUM/%s", domain->name );
272         
273         data = tdb_fetch_bystring( wcache->tdb, key );
274         if ( !data.dptr || data.dsize!=8 ) {
275                 DEBUG(10,("fetch_cache_seqnum: invalid data size key [%s]\n", key ));
276                 return NT_STATUS_UNSUCCESSFUL;
277         }
278         
279         domain->sequence_number = IVAL(data.dptr, 0);
280         domain->last_seq_check  = IVAL(data.dptr, 4);
281         
282         SAFE_FREE(data.dptr);
283
284         /* have we expired? */
285         
286         time_diff = now - domain->last_seq_check;
287         if ( time_diff > lp_winbind_cache_time() ) {
288                 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
289                         domain->name, domain->sequence_number,
290                         (uint32)domain->last_seq_check));
291                 return NT_STATUS_UNSUCCESSFUL;
292         }
293
294         DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n", 
295                 domain->name, domain->sequence_number, 
296                 (uint32)domain->last_seq_check));
297
298         return NT_STATUS_OK;
299 }
300
301 static NTSTATUS store_cache_seqnum( struct winbindd_domain *domain )
302 {
303         TDB_DATA data, key;
304         fstring key_str;
305         char buf[8];
306         
307         if (!wcache->tdb) {
308                 DEBUG(10,("store_cache_seqnum: tdb == NULL\n"));
309                 return NT_STATUS_UNSUCCESSFUL;
310         }
311                 
312         fstr_sprintf( key_str, "SEQNUM/%s", domain->name );
313         key.dptr = key_str;
314         key.dsize = strlen(key_str)+1;
315         
316         SIVAL(buf, 0, domain->sequence_number);
317         SIVAL(buf, 4, domain->last_seq_check);
318         data.dptr = buf;
319         data.dsize = 8;
320         
321         if ( tdb_store( wcache->tdb, key, data, TDB_REPLACE) == -1 ) {
322                 DEBUG(10,("store_cache_seqnum: tdb_store fail key [%s]\n", key_str ));
323                 return NT_STATUS_UNSUCCESSFUL;
324         }
325
326         DEBUG(10,("store_cache_seqnum: success [%s][%u @ %u]\n", 
327                 domain->name, domain->sequence_number, 
328                 (uint32)domain->last_seq_check));
329         
330         return NT_STATUS_OK;
331 }
332
333 /*
334   refresh the domain sequence number. If force is True
335   then always refresh it, no matter how recently we fetched it
336 */
337
338 static void refresh_sequence_number(struct winbindd_domain *domain, BOOL force)
339 {
340         NTSTATUS status;
341         unsigned time_diff;
342         time_t t = time(NULL);
343         unsigned cache_time = lp_winbind_cache_time();
344
345         get_cache( domain );
346
347 #if 0   /* JERRY -- disable as the default cache time is now 5 minutes */
348         /* trying to reconnect is expensive, don't do it too often */
349         if (domain->sequence_number == DOM_SEQUENCE_NONE) {
350                 cache_time *= 8;
351         }
352 #endif
353
354         time_diff = t - domain->last_seq_check;
355
356         /* see if we have to refetch the domain sequence number */
357         if (!force && (time_diff < cache_time)) {
358                 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
359                 goto done;
360         }
361         
362         /* try to get the sequence number from the tdb cache first */
363         /* this will update the timestamp as well */
364         
365         status = fetch_cache_seqnum( domain, t );
366         if ( NT_STATUS_IS_OK(status) )
367                 goto done;      
368
369         /* important! make sure that we know if this is a native 
370            mode domain or not */
371
372         if ( !domain->initialized )
373                 set_dc_type_and_flags( domain );
374
375         status = domain->backend->sequence_number(domain, &domain->sequence_number);
376
377         if (!NT_STATUS_IS_OK(status)) {
378                 domain->sequence_number = DOM_SEQUENCE_NONE;
379         }
380         
381         domain->last_status = status;
382         domain->last_seq_check = time(NULL);
383         
384         /* save the new sequence number ni the cache */
385         store_cache_seqnum( domain );
386
387 done:
388         DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n", 
389                    domain->name, domain->sequence_number));
390
391         return;
392 }
393
394 /*
395   decide if a cache entry has expired
396 */
397 static BOOL centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
398 {
399         /* if the server is OK and our cache entry came from when it was down then
400            the entry is invalid */
401         if (domain->sequence_number != DOM_SEQUENCE_NONE && 
402             centry->sequence_number == DOM_SEQUENCE_NONE) {
403                 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
404                         keystr, domain->name ));
405                 return True;
406         }
407
408         /* if the server is down or the cache entry is not older than the
409            current sequence number then it is OK */
410         if (wcache_server_down(domain) || 
411             centry->sequence_number == domain->sequence_number) {
412                 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
413                         keystr, domain->name ));
414                 return False;
415         }
416
417         DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
418                 keystr, domain->name ));
419
420         /* it's expired */
421         return True;
422 }
423
424 /*
425   fetch an entry from the cache, with a varargs key. auto-fetch the sequence
426   number and return status
427 */
428 static struct cache_entry *wcache_fetch(struct winbind_cache *cache, 
429                                         struct winbindd_domain *domain,
430                                         const char *format, ...) PRINTF_ATTRIBUTE(3,4);
431 static struct cache_entry *wcache_fetch(struct winbind_cache *cache, 
432                                         struct winbindd_domain *domain,
433                                         const char *format, ...)
434 {
435         va_list ap;
436         char *kstr;
437         TDB_DATA data;
438         struct cache_entry *centry;
439         TDB_DATA key;
440
441         refresh_sequence_number(domain, False);
442
443         va_start(ap, format);
444         smb_xvasprintf(&kstr, format, ap);
445         va_end(ap);
446         
447         key.dptr = kstr;
448         key.dsize = strlen(kstr);
449         data = tdb_fetch(wcache->tdb, key);
450         if (!data.dptr) {
451                 /* a cache miss */
452                 free(kstr);
453                 return NULL;
454         }
455
456         centry = SMB_XMALLOC_P(struct cache_entry);
457         centry->data = (unsigned char *)data.dptr;
458         centry->len = data.dsize;
459         centry->ofs = 0;
460
461         if (centry->len < 8) {
462                 /* huh? corrupt cache? */
463                 DEBUG(10,("wcache_fetch: Corrupt cache for key %s domain %s (len < 8) ?\n",
464                         kstr, domain->name ));
465                 centry_free(centry);
466                 free(kstr);
467                 return NULL;
468         }
469         
470         centry->status = NT_STATUS(centry_uint32(centry));
471         centry->sequence_number = centry_uint32(centry);
472
473         if (centry_expired(domain, kstr, centry)) {
474
475                 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
476                          kstr, domain->name ));
477
478                 if (opt_dual_daemon) {
479                         background_process = True;
480                         DEBUG(10,("wcache_fetch: background processing expired entry %s for domain %s\n",
481                                  kstr, domain->name ));
482                 } else {
483                         centry_free(centry);
484                         free(kstr);
485                         return NULL;
486                 }
487         }
488
489         DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
490                  kstr, domain->name ));
491
492         free(kstr);
493         return centry;
494 }
495
496 /*
497   make sure we have at least len bytes available in a centry 
498 */
499 static void centry_expand(struct cache_entry *centry, uint32 len)
500 {
501         uint8 *p;
502         if (centry->len - centry->ofs >= len)
503                 return;
504         centry->len *= 2;
505         p = SMB_REALLOC(centry->data, centry->len);
506         if (!p) {
507                 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
508                 smb_panic("out of memory in centry_expand");
509         }
510         centry->data = p;
511 }
512
513 /*
514   push a uint32 into a centry 
515 */
516 static void centry_put_uint32(struct cache_entry *centry, uint32 v)
517 {
518         centry_expand(centry, 4);
519         SIVAL(centry->data, centry->ofs, v);
520         centry->ofs += 4;
521 }
522
523 /*
524   push a uint8 into a centry 
525 */
526 static void centry_put_uint8(struct cache_entry *centry, uint8 v)
527 {
528         centry_expand(centry, 1);
529         SCVAL(centry->data, centry->ofs, v);
530         centry->ofs += 1;
531 }
532
533 /* 
534    push a string into a centry 
535  */
536 static void centry_put_string(struct cache_entry *centry, const char *s)
537 {
538         int len;
539
540         if (!s) {
541                 /* null strings are marked as len 0xFFFF */
542                 centry_put_uint8(centry, 0xFF);
543                 return;
544         }
545
546         len = strlen(s);
547         /* can't handle more than 254 char strings. Truncating is probably best */
548         if (len > 254)
549                 len = 254;
550         centry_put_uint8(centry, len);
551         centry_expand(centry, len);
552         memcpy(centry->data + centry->ofs, s, len);
553         centry->ofs += len;
554 }
555
556 static void centry_put_sid(struct cache_entry *centry, const DOM_SID *sid) 
557 {
558         fstring sid_string;
559         centry_put_string(centry, sid_to_string(sid_string, sid));
560 }
561
562 /*
563   start a centry for output. When finished, call centry_end()
564 */
565 struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status)
566 {
567         struct cache_entry *centry;
568
569         if (!wcache->tdb)
570                 return NULL;
571
572         centry = SMB_XMALLOC_P(struct cache_entry);
573
574         centry->len = 8192; /* reasonable default */
575         centry->data = SMB_XMALLOC_ARRAY(char, centry->len);
576         centry->ofs = 0;
577         centry->sequence_number = domain->sequence_number;
578         centry_put_uint32(centry, NT_STATUS_V(status));
579         centry_put_uint32(centry, centry->sequence_number);
580         return centry;
581 }
582
583 /*
584   finish a centry and write it to the tdb
585 */
586 static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
587 static void centry_end(struct cache_entry *centry, const char *format, ...)
588 {
589         va_list ap;
590         char *kstr;
591         TDB_DATA key, data;
592
593         va_start(ap, format);
594         smb_xvasprintf(&kstr, format, ap);
595         va_end(ap);
596
597         key.dptr = kstr;
598         key.dsize = strlen(kstr);
599         data.dptr = (char *)centry->data;
600         data.dsize = centry->ofs;
601
602         tdb_store(wcache->tdb, key, data, TDB_REPLACE);
603         free(kstr);
604 }
605
606 static void wcache_save_name_to_sid(struct winbindd_domain *domain, 
607                                     NTSTATUS status, const char *domain_name,
608                                     const char *name, const DOM_SID *sid, 
609                                     enum SID_NAME_USE type)
610 {
611         struct cache_entry *centry;
612         fstring uname;
613
614         centry = centry_start(domain, status);
615         if (!centry)
616                 return;
617         centry_put_uint32(centry, type);
618         centry_put_sid(centry, sid);
619         fstrcpy(uname, name);
620         strupper_m(uname);
621         centry_end(centry, "NS/%s/%s", domain_name, uname);
622         DEBUG(10,("wcache_save_name_to_sid: %s -> %s\n", uname,
623                   sid_string_static(sid)));
624         centry_free(centry);
625 }
626
627 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status, 
628                                     const DOM_SID *sid, const char *domain_name, const char *name, enum SID_NAME_USE type)
629 {
630         struct cache_entry *centry;
631         fstring sid_string;
632
633         centry = centry_start(domain, status);
634         if (!centry)
635                 return;
636         if (NT_STATUS_IS_OK(status)) {
637                 centry_put_uint32(centry, type);
638                 centry_put_string(centry, domain_name);
639                 centry_put_string(centry, name);
640         }
641         centry_end(centry, "SN/%s", sid_to_string(sid_string, sid));
642         DEBUG(10,("wcache_save_sid_to_name: %s -> %s\n", sid_string, name));
643         centry_free(centry);
644 }
645
646
647 static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status, WINBIND_USERINFO *info)
648 {
649         struct cache_entry *centry;
650         fstring sid_string;
651
652         centry = centry_start(domain, status);
653         if (!centry)
654                 return;
655         centry_put_string(centry, info->acct_name);
656         centry_put_string(centry, info->full_name);
657         centry_put_sid(centry, info->user_sid);
658         centry_put_sid(centry, info->group_sid);
659         centry_end(centry, "U/%s", sid_to_string(sid_string, info->user_sid));
660         DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
661         centry_free(centry);
662 }
663
664
665 /* Query display info. This is the basic user list fn */
666 static NTSTATUS query_user_list(struct winbindd_domain *domain,
667                                 TALLOC_CTX *mem_ctx,
668                                 uint32 *num_entries, 
669                                 WINBIND_USERINFO **info)
670 {
671         struct winbind_cache *cache = get_cache(domain);
672         struct cache_entry *centry = NULL;
673         NTSTATUS status;
674         unsigned int i, retry;
675
676         if (!cache->tdb)
677                 goto do_query;
678
679         centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
680         if (!centry)
681                 goto do_query;
682
683         *num_entries = centry_uint32(centry);
684         
685         if (*num_entries == 0)
686                 goto do_cached;
687
688         (*info) = TALLOC_ARRAY(mem_ctx, WINBIND_USERINFO, *num_entries);
689         if (! (*info))
690                 smb_panic("query_user_list out of memory");
691         for (i=0; i<(*num_entries); i++) {
692                 (*info)[i].acct_name = centry_string(centry, mem_ctx);
693                 (*info)[i].full_name = centry_string(centry, mem_ctx);
694                 (*info)[i].user_sid = centry_sid(centry, mem_ctx);
695                 (*info)[i].group_sid = centry_sid(centry, mem_ctx);
696         }
697
698 do_cached:      
699         status = centry->status;
700
701         DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status %s\n",
702                 domain->name, get_friendly_nt_error_msg(status) ));
703
704         centry_free(centry);
705         return status;
706
707 do_query:
708         *num_entries = 0;
709         *info = NULL;
710
711         /* Return status value returned by seq number check */
712
713         if (!NT_STATUS_IS_OK(domain->last_status))
714                 return domain->last_status;
715
716         /* Put the query_user_list() in a retry loop.  There appears to be
717          * some bug either with Windows 2000 or Samba's handling of large
718          * rpc replies.  This manifests itself as sudden disconnection
719          * at a random point in the enumeration of a large (60k) user list.
720          * The retry loop simply tries the operation again. )-:  It's not
721          * pretty but an acceptable workaround until we work out what the
722          * real problem is. */
723
724         retry = 0;
725         do {
726
727                 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
728                         domain->name ));
729
730                 status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
731                 if (!NT_STATUS_IS_OK(status))
732                         DEBUG(3, ("query_user_list: returned 0x%08x, retrying\n", NT_STATUS_V(status)));
733                         if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL)) {
734                                 DEBUG(3, ("query_user_list: flushing connection cache\n"));
735                                 winbindd_cm_flush();
736                         }
737
738         } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) && 
739                  (retry++ < 5));
740
741         /* and save it */
742         refresh_sequence_number(domain, False);
743         centry = centry_start(domain, status);
744         if (!centry)
745                 goto skip_save;
746         centry_put_uint32(centry, *num_entries);
747         for (i=0; i<(*num_entries); i++) {
748                 centry_put_string(centry, (*info)[i].acct_name);
749                 centry_put_string(centry, (*info)[i].full_name);
750                 centry_put_sid(centry, (*info)[i].user_sid);
751                 centry_put_sid(centry, (*info)[i].group_sid);
752                 if (domain->backend->consistent) {
753                         /* when the backend is consistent we can pre-prime some mappings */
754                         wcache_save_name_to_sid(domain, NT_STATUS_OK, 
755                                                 domain->name,
756                                                 (*info)[i].acct_name, 
757                                                 (*info)[i].user_sid,
758                                                 SID_NAME_USER);
759                         wcache_save_sid_to_name(domain, NT_STATUS_OK, 
760                                                 (*info)[i].user_sid,
761                                                 domain->name,
762                                                 (*info)[i].acct_name, 
763                                                 SID_NAME_USER);
764                         wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
765                 }
766         }       
767         centry_end(centry, "UL/%s", domain->name);
768         centry_free(centry);
769
770 skip_save:
771         return status;
772 }
773
774 /* list all domain groups */
775 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
776                                 TALLOC_CTX *mem_ctx,
777                                 uint32 *num_entries, 
778                                 struct acct_info **info)
779 {
780         struct winbind_cache *cache = get_cache(domain);
781         struct cache_entry *centry = NULL;
782         NTSTATUS status;
783         unsigned int i;
784
785         if (!cache->tdb)
786                 goto do_query;
787
788         centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
789         if (!centry)
790                 goto do_query;
791
792         *num_entries = centry_uint32(centry);
793         
794         if (*num_entries == 0)
795                 goto do_cached;
796
797         (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
798         if (! (*info))
799                 smb_panic("enum_dom_groups out of memory");
800         for (i=0; i<(*num_entries); i++) {
801                 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
802                 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
803                 (*info)[i].rid = centry_uint32(centry);
804         }
805
806 do_cached:      
807         status = centry->status;
808
809         DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status %s\n",
810                 domain->name, get_friendly_nt_error_msg(status) ));
811
812         centry_free(centry);
813         return status;
814
815 do_query:
816         *num_entries = 0;
817         *info = NULL;
818
819         /* Return status value returned by seq number check */
820
821         if (!NT_STATUS_IS_OK(domain->last_status))
822                 return domain->last_status;
823
824         DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
825                 domain->name ));
826
827         status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
828
829         /* and save it */
830         refresh_sequence_number(domain, False);
831         centry = centry_start(domain, status);
832         if (!centry)
833                 goto skip_save;
834         centry_put_uint32(centry, *num_entries);
835         for (i=0; i<(*num_entries); i++) {
836                 centry_put_string(centry, (*info)[i].acct_name);
837                 centry_put_string(centry, (*info)[i].acct_desc);
838                 centry_put_uint32(centry, (*info)[i].rid);
839         }       
840         centry_end(centry, "GL/%s/domain", domain->name);
841         centry_free(centry);
842
843 skip_save:
844         return status;
845 }
846
847 /* list all domain groups */
848 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
849                                 TALLOC_CTX *mem_ctx,
850                                 uint32 *num_entries, 
851                                 struct acct_info **info)
852 {
853         struct winbind_cache *cache = get_cache(domain);
854         struct cache_entry *centry = NULL;
855         NTSTATUS status;
856         unsigned int i;
857
858         if (!cache->tdb)
859                 goto do_query;
860
861         centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
862         if (!centry)
863                 goto do_query;
864
865         *num_entries = centry_uint32(centry);
866         
867         if (*num_entries == 0)
868                 goto do_cached;
869
870         (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
871         if (! (*info))
872                 smb_panic("enum_dom_groups out of memory");
873         for (i=0; i<(*num_entries); i++) {
874                 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
875                 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
876                 (*info)[i].rid = centry_uint32(centry);
877         }
878
879 do_cached:      
880
881         /* If we are returning cached data and the domain controller
882            is down then we don't know whether the data is up to date
883            or not.  Return NT_STATUS_MORE_PROCESSING_REQUIRED to
884            indicate this. */
885
886         if (wcache_server_down(domain)) {
887                 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
888                 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
889         } else
890                 status = centry->status;
891
892         DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status %s\n",
893                 domain->name, get_friendly_nt_error_msg(status) ));
894
895         centry_free(centry);
896         return status;
897
898 do_query:
899         *num_entries = 0;
900         *info = NULL;
901
902         /* Return status value returned by seq number check */
903
904         if (!NT_STATUS_IS_OK(domain->last_status))
905                 return domain->last_status;
906
907         DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
908                 domain->name ));
909
910         status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
911
912         /* and save it */
913         refresh_sequence_number(domain, False);
914         centry = centry_start(domain, status);
915         if (!centry)
916                 goto skip_save;
917         centry_put_uint32(centry, *num_entries);
918         for (i=0; i<(*num_entries); i++) {
919                 centry_put_string(centry, (*info)[i].acct_name);
920                 centry_put_string(centry, (*info)[i].acct_desc);
921                 centry_put_uint32(centry, (*info)[i].rid);
922         }
923         centry_end(centry, "GL/%s/local", domain->name);
924         centry_free(centry);
925
926 skip_save:
927         return status;
928 }
929
930 /* convert a single name to a sid in a domain */
931 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
932                             TALLOC_CTX *mem_ctx,
933                             const char *domain_name,
934                             const char *name,
935                             DOM_SID *sid,
936                             enum SID_NAME_USE *type)
937 {
938         struct winbind_cache *cache = get_cache(domain);
939         struct cache_entry *centry = NULL;
940         NTSTATUS status;
941         fstring uname;
942         DOM_SID *sid2;
943
944         if (!cache->tdb)
945                 goto do_query;
946
947         fstrcpy(uname, name);
948         strupper_m(uname);
949         centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
950         if (!centry)
951                 goto do_query;
952         *type = (enum SID_NAME_USE)centry_uint32(centry);
953         sid2 = centry_sid(centry, mem_ctx);
954         if (!sid2) {
955                 ZERO_STRUCTP(sid);
956         } else {
957                 sid_copy(sid, sid2);
958         }
959
960         status = centry->status;
961
962         DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status %s\n",
963                 domain->name, get_friendly_nt_error_msg(status) ));
964
965         centry_free(centry);
966         return status;
967
968 do_query:
969         ZERO_STRUCTP(sid);
970
971         /* If the seq number check indicated that there is a problem
972          * with this DC, then return that status... except for
973          * access_denied.  This is special because the dc may be in
974          * "restrict anonymous = 1" mode, in which case it will deny
975          * most unauthenticated operations, but *will* allow the LSA
976          * name-to-sid that we try as a fallback. */
977
978         if (!(NT_STATUS_IS_OK(domain->last_status)
979               || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
980                 return domain->last_status;
981
982         DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
983                 domain->name ));
984
985         status = domain->backend->name_to_sid(domain, mem_ctx, domain_name, name, sid, type);
986
987         /* and save it */
988         wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
989
990         /* We can't save the sid to name mapping as we don't know the
991            correct case of the name without looking it up */
992
993         return status;
994 }
995
996 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
997    given */
998 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
999                             TALLOC_CTX *mem_ctx,
1000                             const DOM_SID *sid,
1001                             char **domain_name,
1002                             char **name,
1003                             enum SID_NAME_USE *type)
1004 {
1005         struct winbind_cache *cache = get_cache(domain);
1006         struct cache_entry *centry = NULL;
1007         NTSTATUS status;
1008         fstring sid_string;
1009
1010         if (!cache->tdb)
1011                 goto do_query;
1012
1013         centry = wcache_fetch(cache, domain, "SN/%s", sid_to_string(sid_string, sid));
1014         if (!centry)
1015                 goto do_query;
1016         if (NT_STATUS_IS_OK(centry->status)) {
1017                 *type = (enum SID_NAME_USE)centry_uint32(centry);
1018                 *domain_name = centry_string(centry, mem_ctx);
1019                 *name = centry_string(centry, mem_ctx);
1020         }
1021         status = centry->status;
1022
1023         DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status %s\n",
1024                 domain->name, get_friendly_nt_error_msg(status) ));
1025
1026         centry_free(centry);
1027         return status;
1028
1029 do_query:
1030         *name = NULL;
1031         *domain_name = NULL;
1032
1033         /* If the seq number check indicated that there is a problem
1034          * with this DC, then return that status... except for
1035          * access_denied.  This is special because the dc may be in
1036          * "restrict anonymous = 1" mode, in which case it will deny
1037          * most unauthenticated operations, but *will* allow the LSA
1038          * sid-to-name that we try as a fallback. */
1039
1040         if (!(NT_STATUS_IS_OK(domain->last_status)
1041               || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1042                 return domain->last_status;
1043
1044         DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1045                 domain->name ));
1046
1047         status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1048
1049         /* and save it */
1050         refresh_sequence_number(domain, False);
1051         wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1052
1053         /* We can't save the name to sid mapping here, as with sid history a
1054          * later name2sid would give the wrong sid. */
1055
1056         return status;
1057 }
1058
1059
1060 /* Lookup user information from a rid */
1061 static NTSTATUS query_user(struct winbindd_domain *domain, 
1062                            TALLOC_CTX *mem_ctx, 
1063                            const DOM_SID *user_sid, 
1064                            WINBIND_USERINFO *info)
1065 {
1066         struct winbind_cache *cache = get_cache(domain);
1067         struct cache_entry *centry = NULL;
1068         NTSTATUS status;
1069
1070         if (!cache->tdb)
1071                 goto do_query;
1072
1073         centry = wcache_fetch(cache, domain, "U/%s", sid_string_static(user_sid));
1074         
1075         /* If we have an access denied cache entry and a cached info3 in the
1076            samlogon cache then do a query.  This will force the rpc back end
1077            to return the info3 data. */
1078
1079         if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1080             netsamlogon_cache_have(user_sid)) {
1081                 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1082                 domain->last_status = NT_STATUS_OK;
1083                 centry_free(centry);
1084                 goto do_query;
1085         }
1086         
1087         if (!centry)
1088                 goto do_query;
1089
1090         info->acct_name = centry_string(centry, mem_ctx);
1091         info->full_name = centry_string(centry, mem_ctx);
1092         info->user_sid = centry_sid(centry, mem_ctx);
1093         info->group_sid = centry_sid(centry, mem_ctx);
1094         status = centry->status;
1095
1096         DEBUG(10,("query_user: [Cached] - cached info for domain %s status %s\n",
1097                 domain->name, get_friendly_nt_error_msg(status) ));
1098
1099         centry_free(centry);
1100         return status;
1101
1102 do_query:
1103         ZERO_STRUCTP(info);
1104
1105         /* Return status value returned by seq number check */
1106
1107         if (!NT_STATUS_IS_OK(domain->last_status))
1108                 return domain->last_status;
1109         
1110         DEBUG(10,("sid_to_name: [Cached] - doing backend query for info for domain %s\n",
1111                 domain->name ));
1112
1113         status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
1114
1115         /* and save it */
1116         refresh_sequence_number(domain, False);
1117         wcache_save_user(domain, status, info);
1118
1119         return status;
1120 }
1121
1122
1123 /* Lookup groups a user is a member of. */
1124 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
1125                                   TALLOC_CTX *mem_ctx,
1126                                   const DOM_SID *user_sid, 
1127                                   uint32 *num_groups, DOM_SID ***user_gids)
1128 {
1129         struct winbind_cache *cache = get_cache(domain);
1130         struct cache_entry *centry = NULL;
1131         NTSTATUS status;
1132         unsigned int i;
1133         fstring sid_string;
1134
1135         if (!cache->tdb)
1136                 goto do_query;
1137
1138         centry = wcache_fetch(cache, domain, "UG/%s", sid_to_string(sid_string, user_sid));
1139         
1140         /* If we have an access denied cache entry and a cached info3 in the
1141            samlogon cache then do a query.  This will force the rpc back end
1142            to return the info3 data. */
1143
1144         if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1145             netsamlogon_cache_have(user_sid)) {
1146                 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1147                 domain->last_status = NT_STATUS_OK;
1148                 centry_free(centry);
1149                 goto do_query;
1150         }
1151         
1152         if (!centry)
1153                 goto do_query;
1154
1155         *num_groups = centry_uint32(centry);
1156         
1157         if (*num_groups == 0)
1158                 goto do_cached;
1159
1160         (*user_gids) = TALLOC_ARRAY(mem_ctx, DOM_SID *, *num_groups);
1161         if (! (*user_gids))
1162                 smb_panic("lookup_usergroups out of memory");
1163         for (i=0; i<(*num_groups); i++) {
1164                 (*user_gids)[i] = centry_sid(centry, mem_ctx);
1165         }
1166
1167 do_cached:      
1168         status = centry->status;
1169
1170         DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status %s\n",
1171                 domain->name, get_friendly_nt_error_msg(status) ));
1172
1173         centry_free(centry);
1174         return status;
1175
1176 do_query:
1177         (*num_groups) = 0;
1178         (*user_gids) = NULL;
1179
1180         /* Return status value returned by seq number check */
1181
1182         if (!NT_STATUS_IS_OK(domain->last_status))
1183                 return domain->last_status;
1184
1185         DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
1186                 domain->name ));
1187
1188         status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
1189
1190         /* and save it */
1191         refresh_sequence_number(domain, False);
1192         centry = centry_start(domain, status);
1193         if (!centry)
1194                 goto skip_save;
1195         centry_put_uint32(centry, *num_groups);
1196         for (i=0; i<(*num_groups); i++) {
1197                 centry_put_sid(centry, (*user_gids)[i]);
1198         }       
1199         centry_end(centry, "UG/%s", sid_to_string(sid_string, user_sid));
1200         centry_free(centry);
1201
1202 skip_save:
1203         return status;
1204 }
1205
1206 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
1207                                    TALLOC_CTX *mem_ctx,
1208                                    uint32 num_sids, DOM_SID **sids,
1209                                    uint32 *num_aliases, uint32 **alias_rids)
1210 {
1211         struct winbind_cache *cache = get_cache(domain);
1212         struct cache_entry *centry = NULL;
1213         NTSTATUS status;
1214         char *sidlist = talloc_strdup(mem_ctx, "");
1215         int i;
1216
1217         if (!cache->tdb)
1218                 goto do_query;
1219
1220         if (num_sids == 0) {
1221                 *num_aliases = 0;
1222                 *alias_rids = NULL;
1223                 return NT_STATUS_OK;
1224         }
1225
1226         /* We need to cache indexed by the whole list of SIDs, the aliases
1227          * resulting might come from any of the SIDs. */
1228
1229         for (i=0; i<num_sids; i++) {
1230                 sidlist = talloc_asprintf(mem_ctx, "%s/%s", sidlist,
1231                                           sid_string_static(sids[i]));
1232                 if (sidlist == NULL)
1233                         return NT_STATUS_NO_MEMORY;
1234         }
1235
1236         centry = wcache_fetch(cache, domain, "UA%s", sidlist);
1237
1238         if (!centry)
1239                 goto do_query;
1240
1241         *num_aliases = centry_uint32(centry);
1242         *alias_rids = NULL;
1243
1244         (*alias_rids) = TALLOC_ARRAY(mem_ctx, uint32, *num_aliases);
1245
1246         if ((*num_aliases != 0) && ((*alias_rids) == NULL))
1247                 return NT_STATUS_NO_MEMORY;
1248
1249         for (i=0; i<(*num_aliases); i++)
1250                 (*alias_rids)[i] = centry_uint32(centry);
1251
1252         status = centry->status;
1253
1254         DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain %s "
1255                   "status %s\n", domain->name,
1256                   get_friendly_nt_error_msg(status)));
1257
1258         centry_free(centry);
1259         return status;
1260
1261  do_query:
1262         (*num_aliases) = 0;
1263         (*alias_rids) = NULL;
1264
1265         if (!NT_STATUS_IS_OK(domain->last_status))
1266                 return domain->last_status;
1267
1268         DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
1269                   "for domain %s\n", domain->name ));
1270
1271         status = domain->backend->lookup_useraliases(domain, mem_ctx,
1272                                                      num_sids, sids,
1273                                                      num_aliases, alias_rids);
1274
1275         /* and save it */
1276         refresh_sequence_number(domain, False);
1277         centry = centry_start(domain, status);
1278         if (!centry)
1279                 goto skip_save;
1280         centry_put_uint32(centry, *num_aliases);
1281         for (i=0; i<(*num_aliases); i++)
1282                 centry_put_uint32(centry, (*alias_rids)[i]);
1283         centry_end(centry, "UA%s", sidlist);
1284         centry_free(centry);
1285
1286  skip_save:
1287         return status;
1288 }
1289
1290
1291 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1292                                 TALLOC_CTX *mem_ctx,
1293                                 const DOM_SID *group_sid, uint32 *num_names, 
1294                                 DOM_SID ***sid_mem, char ***names, 
1295                                 uint32 **name_types)
1296 {
1297         struct winbind_cache *cache = get_cache(domain);
1298         struct cache_entry *centry = NULL;
1299         NTSTATUS status;
1300         unsigned int i;
1301         fstring sid_string;
1302
1303         if (!cache->tdb)
1304                 goto do_query;
1305
1306         centry = wcache_fetch(cache, domain, "GM/%s", sid_to_string(sid_string, group_sid));
1307         if (!centry)
1308                 goto do_query;
1309
1310         *num_names = centry_uint32(centry);
1311         
1312         if (*num_names == 0)
1313                 goto do_cached;
1314
1315         (*sid_mem) = TALLOC_ARRAY(mem_ctx, DOM_SID *, *num_names);
1316         (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_names);
1317         (*name_types) = TALLOC_ARRAY(mem_ctx, uint32, *num_names);
1318
1319         if (! (*sid_mem) || ! (*names) || ! (*name_types)) {
1320                 smb_panic("lookup_groupmem out of memory");
1321         }
1322
1323         for (i=0; i<(*num_names); i++) {
1324                 (*sid_mem)[i] = centry_sid(centry, mem_ctx);
1325                 (*names)[i] = centry_string(centry, mem_ctx);
1326                 (*name_types)[i] = centry_uint32(centry);
1327         }
1328
1329 do_cached:      
1330         status = centry->status;
1331
1332         DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status %s\n",
1333                 domain->name, get_friendly_nt_error_msg(status) ));
1334
1335         centry_free(centry);
1336         return status;
1337
1338 do_query:
1339         (*num_names) = 0;
1340         (*sid_mem) = NULL;
1341         (*names) = NULL;
1342         (*name_types) = NULL;
1343         
1344         /* Return status value returned by seq number check */
1345
1346         if (!NT_STATUS_IS_OK(domain->last_status))
1347                 return domain->last_status;
1348
1349         DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
1350                 domain->name ));
1351
1352         status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid, num_names, 
1353                                                   sid_mem, names, name_types);
1354
1355         /* and save it */
1356         refresh_sequence_number(domain, False);
1357         centry = centry_start(domain, status);
1358         if (!centry)
1359                 goto skip_save;
1360         centry_put_uint32(centry, *num_names);
1361         for (i=0; i<(*num_names); i++) {
1362                 centry_put_sid(centry, (*sid_mem)[i]);
1363                 centry_put_string(centry, (*names)[i]);
1364                 centry_put_uint32(centry, (*name_types)[i]);
1365         }       
1366         centry_end(centry, "GM/%s", sid_to_string(sid_string, group_sid));
1367         centry_free(centry);
1368
1369 skip_save:
1370         return status;
1371 }
1372
1373 /* find the sequence number for a domain */
1374 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
1375 {
1376         refresh_sequence_number(domain, False);
1377
1378         *seq = domain->sequence_number;
1379
1380         return NT_STATUS_OK;
1381 }
1382
1383 /* enumerate trusted domains */
1384 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1385                                 TALLOC_CTX *mem_ctx,
1386                                 uint32 *num_domains,
1387                                 char ***names,
1388                                 char ***alt_names,
1389                                 DOM_SID **dom_sids)
1390 {
1391         get_cache(domain);
1392
1393         DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
1394                 domain->name ));
1395
1396         /* we don't cache this call */
1397         return domain->backend->trusted_domains(domain, mem_ctx, num_domains, 
1398                                                names, alt_names, dom_sids);
1399 }
1400
1401 /* find the domain sid */
1402 static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
1403 {
1404         get_cache(domain);
1405
1406         DEBUG(10,("domain_sid: [Cached] - doing backend query for info for domain %s\n",
1407                 domain->name ));
1408
1409         /* we don't cache this call */
1410         return domain->backend->domain_sid(domain, sid);
1411 }
1412
1413 /* find the alternate names for the domain, if any */
1414 static NTSTATUS alternate_name(struct winbindd_domain *domain)
1415 {
1416         get_cache(domain);
1417
1418         DEBUG(10,("alternate_name: [Cached] - doing backend query for info for domain %s\n",
1419                 domain->name ));
1420
1421         /* we don't cache this call */
1422         return domain->backend->alternate_name(domain);
1423 }
1424
1425 /* Invalidate cached user and group lists coherently */
1426
1427 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, 
1428                        void *state)
1429 {
1430         if (strncmp(kbuf.dptr, "UL/", 3) == 0 ||
1431             strncmp(kbuf.dptr, "GL/", 3) == 0)
1432                 tdb_delete(the_tdb, kbuf);
1433
1434         return 0;
1435 }
1436
1437 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
1438
1439 void wcache_invalidate_samlogon(struct winbindd_domain *domain, 
1440                                 NET_USER_INFO_3 *info3)
1441 {
1442         struct winbind_cache *cache;
1443         
1444         if (!domain)
1445                 return;
1446
1447         cache = get_cache(domain);
1448         netsamlogon_clear_cached_user(cache->tdb, info3);
1449 }
1450
1451 void wcache_invalidate_cache(void)
1452 {
1453         struct winbindd_domain *domain;
1454
1455         for (domain = domain_list(); domain; domain = domain->next) {
1456                 struct winbind_cache *cache = get_cache(domain);
1457
1458                 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
1459                            "entries for %s\n", domain->name));
1460                 if (cache)
1461                         tdb_traverse(cache->tdb, traverse_fn, NULL);
1462         }
1463 }
1464
1465 /* the ADS backend methods are exposed via this structure */
1466 struct winbindd_methods cache_methods = {
1467         True,
1468         query_user_list,
1469         enum_dom_groups,
1470         enum_local_groups,
1471         name_to_sid,
1472         sid_to_name,
1473         query_user,
1474         lookup_usergroups,
1475         lookup_useraliases,
1476         lookup_groupmem,
1477         sequence_number,
1478         trusted_domains,
1479         domain_sid,
1480         alternate_name
1481 };