92a5e1d333b1fbdac029c50b4e426c194bba2a3f
[nivanova/samba-autobuild/.git] / source3 / winbindd / 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-2007
8    Copyright (C) Volker Lendecke 2005
9    Copyright (C) Guenther Deschner 2005
10    Copyright (C) Michael Adam    2007
11
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 3 of the License, or
15    (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include "includes.h"
27 #include "system/filesys.h"
28 #include "winbindd.h"
29 #include "tdb_validate.h"
30 #include "../libcli/auth/libcli_auth.h"
31 #include "../librpc/gen_ndr/ndr_winbind.h"
32 #include "ads.h"
33 #include "nss_info.h"
34 #include "../libcli/security/security.h"
35 #include "passdb/machine_sid.h"
36 #include "util_tdb.h"
37 #include "libsmb/samlogon_cache.h"
38 #include "lib/namemap_cache.h"
39
40 #undef DBGC_CLASS
41 #define DBGC_CLASS DBGC_WINBIND
42
43 #define WINBINDD_CACHE_VER1 1 /* initial db version */
44 #define WINBINDD_CACHE_VER2 2 /* second version with timeouts for NDR entries */
45
46 #define WINBINDD_CACHE_VERSION WINBINDD_CACHE_VER2
47 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
48
49 extern struct winbindd_methods reconnect_methods;
50 #ifdef HAVE_ADS
51 extern struct winbindd_methods reconnect_ads_methods;
52 #endif
53 extern struct winbindd_methods builtin_passdb_methods;
54 extern struct winbindd_methods sam_passdb_methods;
55
56 static void wcache_flush_cache(void);
57
58 /*
59  * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
60  * Here are the list of entry types that are *not* stored
61  * as form struct cache_entry in the cache.
62  */
63
64 static const char *non_centry_keys[] = {
65         "SEQNUM/",
66         "WINBINDD_OFFLINE",
67         WINBINDD_CACHE_VERSION_KEYSTR,
68         NULL
69 };
70
71 /************************************************************************
72  Is this key a non-centry type ?
73 ************************************************************************/
74
75 static bool is_non_centry_key(TDB_DATA kbuf)
76 {
77         int i;
78
79         if (kbuf.dptr == NULL || kbuf.dsize == 0) {
80                 return false;
81         }
82         for (i = 0; non_centry_keys[i] != NULL; i++) {
83                 size_t namelen = strlen(non_centry_keys[i]);
84                 if (kbuf.dsize < namelen) {
85                         continue;
86                 }
87                 if (strncmp(non_centry_keys[i], (const char *)kbuf.dptr, namelen) == 0) {
88                         return true;
89                 }
90         }
91         return false;
92 }
93
94 /* Global online/offline state - False when online. winbindd starts up online
95    and sets this to true if the first query fails and there's an entry in
96    the cache tdb telling us to stay offline. */
97
98 static bool global_winbindd_offline_state;
99
100 struct winbind_cache {
101         TDB_CONTEXT *tdb;
102 };
103
104 struct cache_entry {
105         NTSTATUS status;
106         uint32_t sequence_number;
107         uint64_t timeout;
108         uint8_t *data;
109         uint32_t len, ofs;
110 };
111
112 void (*smb_panic_fn)(const char *const why) = smb_panic;
113
114 static struct winbind_cache *wcache;
115
116 static char *wcache_path(void)
117 {
118         /*
119          * Data needs to be kept persistent in state directory for
120          * running with "winbindd offline logon".
121          */
122         return state_path(talloc_tos(), "winbindd_cache.tdb");
123 }
124
125 static void winbindd_domain_init_backend(struct winbindd_domain *domain)
126 {
127         if (domain->backend != NULL) {
128                 return;
129         }
130
131         if (domain->internal) {
132                 domain->backend = &builtin_passdb_methods;
133         }
134
135         if (dom_sid_equal(&domain->sid, &global_sid_Builtin)) {
136                 domain->initialized = true;
137         }
138
139         if (strequal(domain->name, get_global_sam_name()) &&
140             sid_check_is_our_sam(&domain->sid))
141         {
142                 domain->backend = &sam_passdb_methods;
143         }
144
145         if (!domain->initialized) {
146                 /* We do not need a connection to an RW DC for cache operation */
147                 init_dc_connection(domain, false);
148         }
149
150 #ifdef HAVE_ADS
151         if (domain->backend == NULL) {
152                 struct winbindd_domain *our_domain = domain;
153
154                 /* find our domain first so we can figure out if we
155                    are joined to a kerberized domain */
156
157                 if (!domain->primary) {
158                         our_domain = find_our_domain();
159                 }
160
161                 if ((our_domain->active_directory || IS_DC)
162                     && domain->active_directory
163                     && !lp_winbind_rpc_only())
164                 {
165                         DBG_INFO("Setting ADS methods for domain %s\n",
166                                  domain->name);
167                         domain->backend = &reconnect_ads_methods;
168                 }
169         }
170 #endif  /* HAVE_ADS */
171
172         if (domain->backend == NULL) {
173                 DBG_INFO("Setting MS-RPC methods for domain %s\n", domain->name);
174                 domain->backend = &reconnect_methods;
175         }
176 }
177
178 /* get the winbind_cache structure */
179 static struct winbind_cache *get_cache(struct winbindd_domain *domain)
180 {
181         struct winbind_cache *ret = wcache;
182
183         winbindd_domain_init_backend(domain);
184
185         if (ret != NULL) {
186                 return ret;
187         }
188
189         ret = SMB_XMALLOC_P(struct winbind_cache);
190         ZERO_STRUCTP(ret);
191
192         wcache = ret;
193         wcache_flush_cache();
194
195         return ret;
196 }
197
198 /*
199   free a centry structure
200 */
201 static void centry_free(struct cache_entry *centry)
202 {
203         if (!centry)
204                 return;
205         SAFE_FREE(centry->data);
206         free(centry);
207 }
208
209 static bool centry_check_bytes(struct cache_entry *centry, size_t nbytes)
210 {
211         if (centry->len - centry->ofs < nbytes) {
212                 DEBUG(0,("centry corruption? needed %u bytes, have %d\n", 
213                          (unsigned int)nbytes,
214                          centry->len - centry->ofs));
215                 return false;
216         }
217         return true;
218 }
219
220 /*
221   pull a uint64_t from a cache entry
222 */
223 static uint64_t centry_uint64_t(struct cache_entry *centry)
224 {
225         uint64_t ret;
226
227         if (!centry_check_bytes(centry, 8)) {
228                 smb_panic_fn("centry_uint64_t");
229         }
230         ret = BVAL(centry->data, centry->ofs);
231         centry->ofs += 8;
232         return ret;
233 }
234
235 /*
236   pull a uint32_t from a cache entry
237 */
238 static uint32_t centry_uint32(struct cache_entry *centry)
239 {
240         uint32_t ret;
241
242         if (!centry_check_bytes(centry, 4)) {
243                 smb_panic_fn("centry_uint32");
244         }
245         ret = IVAL(centry->data, centry->ofs);
246         centry->ofs += 4;
247         return ret;
248 }
249
250 /*
251   pull a uint16_t from a cache entry
252 */
253 static uint16_t centry_uint16(struct cache_entry *centry)
254 {
255         uint16_t ret;
256         if (!centry_check_bytes(centry, 2)) {
257                 smb_panic_fn("centry_uint16");
258         }
259         ret = SVAL(centry->data, centry->ofs);
260         centry->ofs += 2;
261         return ret;
262 }
263
264 /*
265   pull a uint8_t from a cache entry
266 */
267 static uint8_t centry_uint8(struct cache_entry *centry)
268 {
269         uint8_t ret;
270         if (!centry_check_bytes(centry, 1)) {
271                 smb_panic_fn("centry_uint8");
272         }
273         ret = CVAL(centry->data, centry->ofs);
274         centry->ofs += 1;
275         return ret;
276 }
277
278 /*
279   pull a NTTIME from a cache entry 
280 */
281 static NTTIME centry_nttime(struct cache_entry *centry)
282 {
283         NTTIME ret;
284         if (!centry_check_bytes(centry, 8)) {
285                 smb_panic_fn("centry_nttime");
286         }
287         ret = IVAL(centry->data, centry->ofs);
288         centry->ofs += 4;
289         ret += (uint64_t)IVAL(centry->data, centry->ofs) << 32;
290         centry->ofs += 4;
291         return ret;
292 }
293
294 /*
295   pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
296 */
297 static time_t centry_time(struct cache_entry *centry)
298 {
299         return (time_t)centry_nttime(centry);
300 }
301
302 /* pull a string from a cache entry, using the supplied
303    talloc context 
304 */
305 static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
306 {
307         uint32_t len;
308         char *ret;
309
310         len = centry_uint8(centry);
311
312         if (len == 0xFF) {
313                 /* a deliberate NULL string */
314                 return NULL;
315         }
316
317         if (!centry_check_bytes(centry, (size_t)len)) {
318                 smb_panic_fn("centry_string");
319         }
320
321         ret = talloc_array(mem_ctx, char, len+1);
322         if (!ret) {
323                 smb_panic_fn("centry_string out of memory\n");
324         }
325         memcpy(ret,centry->data + centry->ofs, len);
326         ret[len] = 0;
327         centry->ofs += len;
328         return ret;
329 }
330
331 /* pull a hash16 from a cache entry, using the supplied
332    talloc context 
333 */
334 static char *centry_hash16(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
335 {
336         uint32_t len;
337         char *ret;
338
339         len = centry_uint8(centry);
340
341         if (len != 16) {
342                 DEBUG(0,("centry corruption? hash len (%u) != 16\n", 
343                         len ));
344                 return NULL;
345         }
346
347         if (!centry_check_bytes(centry, 16)) {
348                 return NULL;
349         }
350
351         ret = talloc_array(mem_ctx, char, 16);
352         if (!ret) {
353                 smb_panic_fn("centry_hash out of memory\n");
354         }
355         memcpy(ret,centry->data + centry->ofs, 16);
356         centry->ofs += 16;
357         return ret;
358 }
359
360 /* pull a sid from a cache entry, using the supplied
361    talloc context 
362 */
363 static bool centry_sid(struct cache_entry *centry, struct dom_sid *sid)
364 {
365         char *sid_string;
366         bool ret;
367
368         sid_string = centry_string(centry, talloc_tos());
369         if (sid_string == NULL) {
370                 return false;
371         }
372         ret = string_to_sid(sid, sid_string);
373         TALLOC_FREE(sid_string);
374         return ret;
375 }
376
377
378 /*
379   pull a NTSTATUS from a cache entry
380 */
381 static NTSTATUS centry_ntstatus(struct cache_entry *centry)
382 {
383         NTSTATUS status;
384
385         status = NT_STATUS(centry_uint32(centry));
386         return status;
387 }
388
389
390 /* the server is considered down if it can't give us a sequence number */
391 static bool wcache_server_down(struct winbindd_domain *domain)
392 {
393         bool ret;
394
395         if (!wcache->tdb)
396                 return false;
397
398         ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
399
400         if (ret)
401                 DEBUG(10,("wcache_server_down: server for Domain %s down\n", 
402                         domain->name ));
403         return ret;
404 }
405
406 struct wcache_seqnum_state {
407         uint32_t *seqnum;
408         uint32_t *last_seq_check;
409 };
410
411 static int wcache_seqnum_parser(TDB_DATA key, TDB_DATA data,
412                                 void *private_data)
413 {
414         struct wcache_seqnum_state *state = private_data;
415
416         if (data.dsize != 8) {
417                 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
418                            (int)data.dsize));
419                 return -1;
420         }
421
422         *state->seqnum = IVAL(data.dptr, 0);
423         *state->last_seq_check = IVAL(data.dptr, 4);
424         return 0;
425 }
426
427 static bool wcache_fetch_seqnum(const char *domain_name, uint32_t *seqnum,
428                                 uint32_t *last_seq_check)
429 {
430         struct wcache_seqnum_state state = {
431                 .seqnum = seqnum, .last_seq_check = last_seq_check
432         };
433         size_t len = strlen(domain_name);
434         char keystr[len+8];
435         TDB_DATA key = { .dptr = (uint8_t *)keystr, .dsize = sizeof(keystr) };
436         int ret;
437
438         if (wcache->tdb == NULL) {
439                 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
440                 return false;
441         }
442
443         snprintf(keystr, sizeof(keystr),  "SEQNUM/%s", domain_name);
444
445         ret = tdb_parse_record(wcache->tdb, key, wcache_seqnum_parser,
446                                &state);
447         return (ret == 0);
448 }
449
450 static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
451 {
452         uint32_t last_check, time_diff;
453
454         if (!wcache_fetch_seqnum(domain->name, &domain->sequence_number,
455                                  &last_check)) {
456                 return NT_STATUS_UNSUCCESSFUL;
457         }
458         domain->last_seq_check = last_check;
459
460         /* have we expired? */
461
462         time_diff = now - domain->last_seq_check;
463         if ((int)time_diff > lp_winbind_cache_time()) {
464                 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
465                         domain->name, domain->sequence_number,
466                         (uint32_t)domain->last_seq_check));
467                 return NT_STATUS_UNSUCCESSFUL;
468         }
469
470         DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n", 
471                 domain->name, domain->sequence_number, 
472                 (uint32_t)domain->last_seq_check));
473
474         return NT_STATUS_OK;
475 }
476
477 bool wcache_store_seqnum(const char *domain_name, uint32_t seqnum,
478                          time_t last_seq_check)
479 {
480         size_t len = strlen(domain_name);
481         char keystr[len+8];
482         TDB_DATA key = { .dptr = (uint8_t *)keystr, .dsize = sizeof(keystr) };
483         uint8_t buf[8];
484         int ret;
485
486         if (wcache->tdb == NULL) {
487                 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
488                 return false;
489         }
490
491         snprintf(keystr, sizeof(keystr),  "SEQNUM/%s", domain_name);
492
493         SIVAL(buf, 0, seqnum);
494         SIVAL(buf, 4, last_seq_check);
495
496         ret = tdb_store(wcache->tdb, key, make_tdb_data(buf, sizeof(buf)),
497                         TDB_REPLACE);
498         if (ret != 0) {
499                 DEBUG(10, ("tdb_store_bystring failed: %s\n",
500                            tdb_errorstr(wcache->tdb)));
501                 return false;
502         }
503
504         DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
505                    domain_name, seqnum, (unsigned)last_seq_check));
506
507         return true;
508 }
509
510 static bool store_cache_seqnum( struct winbindd_domain *domain )
511 {
512         return wcache_store_seqnum(domain->name, domain->sequence_number,
513                                    domain->last_seq_check);
514 }
515
516 /*
517   refresh the domain sequence number on timeout.
518 */
519
520 static void refresh_sequence_number(struct winbindd_domain *domain)
521 {
522         NTSTATUS status;
523         unsigned time_diff;
524         time_t t = time(NULL);
525         unsigned cache_time = lp_winbind_cache_time();
526
527         if (is_domain_offline(domain)) {
528                 return;
529         }
530
531         get_cache( domain );
532
533 #if 0   /* JERRY -- disable as the default cache time is now 5 minutes */
534         /* trying to reconnect is expensive, don't do it too often */
535         if (domain->sequence_number == DOM_SEQUENCE_NONE) {
536                 cache_time *= 8;
537         }
538 #endif
539
540         time_diff = t - domain->last_seq_check;
541
542         /* see if we have to refetch the domain sequence number */
543         if ((time_diff < cache_time) &&
544                         (domain->sequence_number != DOM_SEQUENCE_NONE) &&
545                         NT_STATUS_IS_OK(domain->last_status)) {
546                 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
547                 goto done;
548         }
549
550         /* try to get the sequence number from the tdb cache first */
551         /* this will update the timestamp as well */
552
553         status = fetch_cache_seqnum( domain, t );
554         if (NT_STATUS_IS_OK(status) &&
555                         (domain->sequence_number != DOM_SEQUENCE_NONE) &&
556                         NT_STATUS_IS_OK(domain->last_status)) {
557                 goto done;
558         }
559
560         /* important! make sure that we know if this is a native 
561            mode domain or not.  And that we can contact it. */
562
563         if ( winbindd_can_contact_domain( domain ) ) {          
564                 status = domain->backend->sequence_number(domain, 
565                                                           &domain->sequence_number);
566         } else {
567                 /* just use the current time */
568                 status = NT_STATUS_OK;
569                 domain->sequence_number = time(NULL);
570         }
571
572
573         /* the above call could have set our domain->backend to NULL when
574          * coming from offline to online mode, make sure to reinitialize the
575          * backend - Guenther */
576         get_cache( domain );
577
578         if (!NT_STATUS_IS_OK(status)) {
579                 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status)));
580                 domain->sequence_number = DOM_SEQUENCE_NONE;
581         }
582
583         domain->last_status = status;
584         domain->last_seq_check = time(NULL);
585
586         /* save the new sequence number in the cache */
587         store_cache_seqnum( domain );
588
589 done:
590         DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n", 
591                    domain->name, domain->sequence_number));
592
593         return;
594 }
595
596 /*
597   decide if a cache entry has expired
598 */
599 static bool centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
600 {
601         /* If we've been told to be offline - stay in that state... */
602         if (lp_winbind_offline_logon() && global_winbindd_offline_state) {
603                 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
604                         keystr, domain->name ));
605                 return false;
606         }
607
608         /* when the domain is offline return the cached entry.
609          * This deals with transient offline states... */
610
611         if (!domain->online) {
612                 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
613                         keystr, domain->name ));
614                 return false;
615         }
616
617         /* if the server is OK and our cache entry came from when it was down then
618            the entry is invalid */
619         if ((domain->sequence_number != DOM_SEQUENCE_NONE) &&  
620             (centry->sequence_number == DOM_SEQUENCE_NONE)) {
621                 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
622                         keystr, domain->name ));
623                 return true;
624         }
625
626         /* if the server is down or the cache entry is not older than the
627            current sequence number or it did not timeout then it is OK */
628         if (wcache_server_down(domain)
629             || ((centry->sequence_number == domain->sequence_number)
630                 && ((time_t)centry->timeout > time(NULL)))) {
631                 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
632                         keystr, domain->name ));
633                 return false;
634         }
635
636         DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
637                 keystr, domain->name ));
638
639         /* it's expired */
640         return true;
641 }
642
643 static struct cache_entry *wcache_fetch_raw(char *kstr)
644 {
645         TDB_DATA data;
646         struct cache_entry *centry;
647         TDB_DATA key;
648
649         key = string_tdb_data(kstr);
650         data = tdb_fetch(wcache->tdb, key);
651         if (!data.dptr) {
652                 /* a cache miss */
653                 return NULL;
654         }
655
656         centry = SMB_XMALLOC_P(struct cache_entry);
657         centry->data = (unsigned char *)data.dptr;
658         centry->len = data.dsize;
659         centry->ofs = 0;
660
661         if (centry->len < 16) {
662                 /* huh? corrupt cache? */
663                 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s "
664                           "(len < 16)?\n", kstr));
665                 centry_free(centry);
666                 return NULL;
667         }
668
669         centry->status = centry_ntstatus(centry);
670         centry->sequence_number = centry_uint32(centry);
671         centry->timeout = centry_uint64_t(centry);
672
673         return centry;
674 }
675
676 static bool is_my_own_sam_domain(struct winbindd_domain *domain)
677 {
678         if (strequal(domain->name, get_global_sam_name()) &&
679             sid_check_is_our_sam(&domain->sid)) {
680                 return true;
681         }
682
683         return false;
684 }
685
686 static bool is_builtin_domain(struct winbindd_domain *domain)
687 {
688         if (strequal(domain->name, "BUILTIN") &&
689             sid_check_is_builtin(&domain->sid)) {
690                 return true;
691         }
692
693         return false;
694 }
695
696 /*
697   fetch an entry from the cache, with a varargs key. auto-fetch the sequence
698   number and return status
699 */
700 static struct cache_entry *wcache_fetch(struct winbind_cache *cache, 
701                                         struct winbindd_domain *domain,
702                                         const char *format, ...) PRINTF_ATTRIBUTE(3,4);
703 static struct cache_entry *wcache_fetch(struct winbind_cache *cache, 
704                                         struct winbindd_domain *domain,
705                                         const char *format, ...)
706 {
707         va_list ap;
708         char *kstr;
709         struct cache_entry *centry;
710
711         if (!winbindd_use_cache() ||
712             is_my_own_sam_domain(domain) ||
713             is_builtin_domain(domain)) {
714                 return NULL;
715         }
716
717         refresh_sequence_number(domain);
718
719         va_start(ap, format);
720         smb_xvasprintf(&kstr, format, ap);
721         va_end(ap);
722
723         centry = wcache_fetch_raw(kstr);
724         if (centry == NULL) {
725                 free(kstr);
726                 return NULL;
727         }
728
729         if (centry_expired(domain, kstr, centry)) {
730
731                 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
732                          kstr, domain->name ));
733
734                 centry_free(centry);
735                 free(kstr);
736                 return NULL;
737         }
738
739         DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
740                  kstr, domain->name ));
741
742         free(kstr);
743         return centry;
744 }
745
746 static void wcache_delete(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
747 static void wcache_delete(const char *format, ...)
748 {
749         va_list ap;
750         char *kstr;
751         TDB_DATA key;
752
753         va_start(ap, format);
754         smb_xvasprintf(&kstr, format, ap);
755         va_end(ap);
756
757         key = string_tdb_data(kstr);
758
759         tdb_delete(wcache->tdb, key);
760         free(kstr);
761 }
762
763 /*
764   make sure we have at least len bytes available in a centry 
765 */
766 static void centry_expand(struct cache_entry *centry, uint32_t len)
767 {
768         if (centry->len - centry->ofs >= len)
769                 return;
770         centry->len *= 2;
771         centry->data = SMB_REALLOC_ARRAY(centry->data, unsigned char,
772                                          centry->len);
773         if (!centry->data) {
774                 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
775                 smb_panic_fn("out of memory in centry_expand");
776         }
777 }
778
779 /*
780   push a uint64_t into a centry
781 */
782 static void centry_put_uint64_t(struct cache_entry *centry, uint64_t v)
783 {
784         centry_expand(centry, 8);
785         SBVAL(centry->data, centry->ofs, v);
786         centry->ofs += 8;
787 }
788
789 /*
790   push a uint32_t into a centry
791 */
792 static void centry_put_uint32(struct cache_entry *centry, uint32_t v)
793 {
794         centry_expand(centry, 4);
795         SIVAL(centry->data, centry->ofs, v);
796         centry->ofs += 4;
797 }
798
799 /*
800   push a uint16_t into a centry
801 */
802 static void centry_put_uint16(struct cache_entry *centry, uint16_t v)
803 {
804         centry_expand(centry, 2);
805         SSVAL(centry->data, centry->ofs, v);
806         centry->ofs += 2;
807 }
808
809 /*
810   push a uint8_t into a centry
811 */
812 static void centry_put_uint8(struct cache_entry *centry, uint8_t v)
813 {
814         centry_expand(centry, 1);
815         SCVAL(centry->data, centry->ofs, v);
816         centry->ofs += 1;
817 }
818
819 /* 
820    push a string into a centry 
821  */
822 static void centry_put_string(struct cache_entry *centry, const char *s)
823 {
824         int len;
825
826         if (!s) {
827                 /* null strings are marked as len 0xFFFF */
828                 centry_put_uint8(centry, 0xFF);
829                 return;
830         }
831
832         len = strlen(s);
833         /* can't handle more than 254 char strings. Truncating is probably best */
834         if (len > 254) {
835                 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len));
836                 len = 254;
837         }
838         centry_put_uint8(centry, len);
839         centry_expand(centry, len);
840         memcpy(centry->data + centry->ofs, s, len);
841         centry->ofs += len;
842 }
843
844 /* 
845    push a 16 byte hash into a centry - treat as 16 byte string.
846  */
847 static void centry_put_hash16(struct cache_entry *centry, const uint8_t val[16])
848 {
849         centry_put_uint8(centry, 16);
850         centry_expand(centry, 16);
851         memcpy(centry->data + centry->ofs, val, 16);
852         centry->ofs += 16;
853 }
854
855 static void centry_put_sid(struct cache_entry *centry, const struct dom_sid *sid)
856 {
857         struct dom_sid_buf sid_string;
858         centry_put_string(centry, dom_sid_str_buf(sid, &sid_string));
859 }
860
861
862 /*
863   put NTSTATUS into a centry
864 */
865 static void centry_put_ntstatus(struct cache_entry *centry, NTSTATUS status)
866 {
867         uint32_t status_value = NT_STATUS_V(status);
868         centry_put_uint32(centry, status_value);
869 }
870
871
872 /*
873   push a NTTIME into a centry 
874 */
875 static void centry_put_nttime(struct cache_entry *centry, NTTIME nt)
876 {
877         centry_expand(centry, 8);
878         SIVAL(centry->data, centry->ofs, nt & 0xFFFFFFFF);
879         centry->ofs += 4;
880         SIVAL(centry->data, centry->ofs, nt >> 32);
881         centry->ofs += 4;
882 }
883
884 /*
885   push a time_t into a centry - use a 64 bit size.
886   NTTIME here is being used as a convenient 64-bit size.
887 */
888 static void centry_put_time(struct cache_entry *centry, time_t t)
889 {
890         NTTIME nt = (NTTIME)t;
891         centry_put_nttime(centry, nt);
892 }
893
894 /*
895   start a centry for output. When finished, call centry_end()
896 */
897 static struct cache_entry *centry_start(struct winbindd_domain *domain,
898                                         NTSTATUS status)
899 {
900         struct cache_entry *centry;
901
902         if (!wcache->tdb)
903                 return NULL;
904
905         centry = SMB_XMALLOC_P(struct cache_entry);
906
907         centry->len = 8192; /* reasonable default */
908         centry->data = SMB_XMALLOC_ARRAY(uint8_t, centry->len);
909         centry->ofs = 0;
910         centry->sequence_number = domain->sequence_number;
911         centry->timeout = lp_winbind_cache_time() + time(NULL);
912         centry_put_ntstatus(centry, status);
913         centry_put_uint32(centry, centry->sequence_number);
914         centry_put_uint64_t(centry, centry->timeout);
915         return centry;
916 }
917
918 /*
919   finish a centry and write it to the tdb
920 */
921 static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
922 static void centry_end(struct cache_entry *centry, const char *format, ...)
923 {
924         va_list ap;
925         char *kstr;
926         TDB_DATA key, data;
927
928         if (!winbindd_use_cache()) {
929                 return;
930         }
931
932         va_start(ap, format);
933         smb_xvasprintf(&kstr, format, ap);
934         va_end(ap);
935
936         key = string_tdb_data(kstr);
937         data.dptr = centry->data;
938         data.dsize = centry->ofs;
939
940         tdb_store(wcache->tdb, key, data, TDB_REPLACE);
941         free(kstr);
942 }
943
944 static void wcache_save_name_to_sid(struct winbindd_domain *domain, 
945                                     NTSTATUS status, const char *domain_name,
946                                     const char *name, const struct dom_sid *sid,
947                                     enum lsa_SidType type)
948 {
949         bool ok;
950
951         ok = namemap_cache_set_name2sid(domain_name, name, sid, type,
952                                         time(NULL) + lp_winbind_cache_time());
953         if (!ok) {
954                 DBG_DEBUG("namemap_cache_set_name2sid failed\n");
955         }
956
957         /*
958          * Don't store the reverse mapping. The name came from user
959          * input, and we might not have the correct capitalization,
960          * which is important for nsswitch.
961          */
962 }
963
964 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status, 
965                                     const struct dom_sid *sid, const char *domain_name, const char *name, enum lsa_SidType type)
966 {
967         bool ok;
968
969         ok = namemap_cache_set_sid2name(sid, domain_name, name, type,
970                                         time(NULL) + lp_winbind_cache_time());
971         if (!ok) {
972                 DBG_DEBUG("namemap_cache_set_sid2name failed\n");
973         }
974
975         if (type != SID_NAME_UNKNOWN) {
976                 ok = namemap_cache_set_name2sid(
977                         domain_name, name, sid, type,
978                         time(NULL) + lp_winbind_cache_time());
979                 if (!ok) {
980                         DBG_DEBUG("namemap_cache_set_name2sid failed\n");
981                 }
982         }
983 }
984
985 static void wcache_save_lockout_policy(struct winbindd_domain *domain,
986                                        NTSTATUS status,
987                                        struct samr_DomInfo12 *lockout_policy)
988 {
989         struct cache_entry *centry;
990
991         centry = centry_start(domain, status);
992         if (!centry)
993                 return;
994
995         centry_put_nttime(centry, lockout_policy->lockout_duration);
996         centry_put_nttime(centry, lockout_policy->lockout_window);
997         centry_put_uint16(centry, lockout_policy->lockout_threshold);
998
999         centry_end(centry, "LOC_POL/%s", domain->name);
1000
1001         DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
1002
1003         centry_free(centry);
1004 }
1005
1006
1007
1008 static void wcache_save_password_policy(struct winbindd_domain *domain,
1009                                         NTSTATUS status,
1010                                         struct samr_DomInfo1 *policy)
1011 {
1012         struct cache_entry *centry;
1013
1014         centry = centry_start(domain, status);
1015         if (!centry)
1016                 return;
1017
1018         centry_put_uint16(centry, policy->min_password_length);
1019         centry_put_uint16(centry, policy->password_history_length);
1020         centry_put_uint32(centry, policy->password_properties);
1021         centry_put_nttime(centry, policy->max_password_age);
1022         centry_put_nttime(centry, policy->min_password_age);
1023
1024         centry_end(centry, "PWD_POL/%s", domain->name);
1025
1026         DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
1027
1028         centry_free(centry);
1029 }
1030
1031 /***************************************************************************
1032  ***************************************************************************/
1033
1034 static void wcache_save_username_alias(struct winbindd_domain *domain,
1035                                        NTSTATUS status,
1036                                        const char *name, const char *alias)
1037 {
1038         struct cache_entry *centry;
1039         fstring uname;
1040
1041         if ( (centry = centry_start(domain, status)) == NULL )
1042                 return;
1043
1044         centry_put_string( centry, alias );
1045
1046         fstrcpy(uname, name);
1047         (void)strupper_m(uname);
1048         centry_end(centry, "NSS/NA/%s", uname);
1049
1050         DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name, alias ));
1051
1052         centry_free(centry);
1053 }
1054
1055 static void wcache_save_alias_username(struct winbindd_domain *domain,
1056                                        NTSTATUS status,
1057                                        const char *alias, const char *name)
1058 {
1059         struct cache_entry *centry;
1060         fstring uname;
1061
1062         if ( (centry = centry_start(domain, status)) == NULL )
1063                 return;
1064
1065         centry_put_string( centry, name );
1066
1067         fstrcpy(uname, alias);
1068         (void)strupper_m(uname);
1069         centry_end(centry, "NSS/AN/%s", uname);
1070
1071         DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias, name ));
1072
1073         centry_free(centry);
1074 }
1075
1076 /***************************************************************************
1077  ***************************************************************************/
1078
1079 NTSTATUS resolve_username_to_alias( TALLOC_CTX *mem_ctx,
1080                                     struct winbindd_domain *domain,
1081                                     const char *name, char **alias )
1082 {
1083         struct winbind_cache *cache = get_cache(domain);
1084         struct cache_entry *centry = NULL;
1085         NTSTATUS status;
1086         char *upper_name;
1087
1088         if ( domain->internal )
1089                 return NT_STATUS_NOT_SUPPORTED;
1090
1091         if (!cache->tdb)
1092                 goto do_query;
1093
1094         upper_name = talloc_strdup_upper(mem_ctx, name);
1095         if (upper_name == NULL) {
1096                 return NT_STATUS_NO_MEMORY;
1097         }
1098
1099         centry = wcache_fetch(cache, domain, "NSS/NA/%s", upper_name);
1100
1101         talloc_free(upper_name);
1102
1103         if (!centry)
1104                 goto do_query;
1105
1106         status = centry->status;
1107
1108         if (!NT_STATUS_IS_OK(status)) {
1109                 centry_free(centry);
1110                 return status;
1111         }
1112
1113         *alias = centry_string( centry, mem_ctx );
1114
1115         centry_free(centry);
1116
1117         DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1118                   name, *alias ? *alias : "(none)"));
1119
1120         return (*alias) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1121
1122 do_query:
1123
1124         /* If its not in cache and we are offline, then fail */
1125
1126         if (is_domain_offline(domain)) {
1127                 DEBUG(8,("resolve_username_to_alias: rejecting query "
1128                          "in offline mode\n"));
1129                 return NT_STATUS_NOT_FOUND;
1130         }
1131
1132         status = nss_map_to_alias( mem_ctx, domain->name, name, alias );
1133
1134         if ( NT_STATUS_IS_OK( status ) ) {
1135                 wcache_save_username_alias(domain, status, name, *alias);
1136         }
1137
1138         if ( NT_STATUS_EQUAL( status, NT_STATUS_NONE_MAPPED ) ) {
1139                 wcache_save_username_alias(domain, status, name, "(NULL)");
1140         }
1141
1142         DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1143                  nt_errstr(status)));
1144
1145         if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1146                 set_domain_offline( domain );
1147         }
1148
1149         return status;
1150 }
1151
1152 /***************************************************************************
1153  ***************************************************************************/
1154
1155 NTSTATUS resolve_alias_to_username( TALLOC_CTX *mem_ctx,
1156                                     struct winbindd_domain *domain,
1157                                     const char *alias, char **name )
1158 {
1159         struct winbind_cache *cache = get_cache(domain);
1160         struct cache_entry *centry = NULL;
1161         NTSTATUS status;
1162         char *upper_name;
1163
1164         if ( domain->internal )
1165                 return  NT_STATUS_NOT_SUPPORTED;
1166
1167         if (!cache->tdb)
1168                 goto do_query;
1169
1170         upper_name = talloc_strdup(mem_ctx, alias);
1171         if (upper_name == NULL) {
1172                 return NT_STATUS_NO_MEMORY;
1173         }
1174         if (!strupper_m(upper_name)) {
1175                 talloc_free(upper_name);
1176                 return NT_STATUS_INVALID_PARAMETER;
1177         }
1178
1179         centry = wcache_fetch(cache, domain, "NSS/AN/%s", upper_name);
1180
1181         talloc_free(upper_name);
1182
1183         if (!centry)
1184                 goto do_query;
1185
1186         status = centry->status;
1187
1188         if (!NT_STATUS_IS_OK(status)) {
1189                 centry_free(centry);
1190                 return status;
1191         }
1192
1193         *name = centry_string( centry, mem_ctx );
1194
1195         centry_free(centry);
1196
1197         DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1198                   alias, *name ? *name : "(none)"));
1199
1200         return (*name) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1201
1202 do_query:
1203
1204         /* If its not in cache and we are offline, then fail */
1205
1206         if (is_domain_offline(domain)) {
1207                 DEBUG(8,("resolve_alias_to_username: rejecting query "
1208                          "in offline mode\n"));
1209                 return NT_STATUS_NOT_FOUND;
1210         }
1211
1212         /* an alias cannot contain a domain prefix or '@' */
1213
1214         if (strchr(alias, '\\') || strchr(alias, '@')) {
1215                 DEBUG(10,("resolve_alias_to_username: skipping fully "
1216                           "qualified name %s\n", alias));
1217                 return NT_STATUS_OBJECT_NAME_INVALID;
1218         }
1219
1220         status = nss_map_from_alias( mem_ctx, domain->name, alias, name );
1221
1222         if ( NT_STATUS_IS_OK( status ) ) {
1223                 wcache_save_alias_username( domain, status, alias, *name );
1224         }
1225
1226         if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1227                 wcache_save_alias_username(domain, status, alias, "(NULL)");
1228         }
1229
1230         DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1231                  nt_errstr(status)));
1232
1233         if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1234                 set_domain_offline( domain );
1235         }
1236
1237         return status;
1238 }
1239
1240 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const struct dom_sid *sid)
1241 {
1242         struct winbind_cache *cache = get_cache(domain);
1243         int ret;
1244         struct dom_sid_buf tmp;
1245         fstring key_str;
1246         uint32_t rid;
1247
1248         if (!cache->tdb) {
1249                 return NT_STATUS_INTERNAL_DB_ERROR;
1250         }
1251
1252         if (is_null_sid(sid)) {
1253                 return NT_STATUS_INVALID_SID;
1254         }
1255
1256         if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1257                 return NT_STATUS_INVALID_SID;
1258         }
1259
1260         fstr_sprintf(key_str, "CRED/%s", dom_sid_str_buf(sid, &tmp));
1261
1262         ret = tdb_exists(cache->tdb, string_tdb_data(key_str));
1263         if (ret != 1) {
1264                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1265         }
1266
1267         return NT_STATUS_OK;
1268 }
1269
1270 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1271    as new salted ones. */
1272
1273 NTSTATUS wcache_get_creds(struct winbindd_domain *domain, 
1274                           TALLOC_CTX *mem_ctx, 
1275                           const struct dom_sid *sid,
1276                           const uint8_t **cached_nt_pass,
1277                           const uint8_t **cached_salt)
1278 {
1279         struct winbind_cache *cache = get_cache(domain);
1280         struct cache_entry *centry = NULL;
1281         NTSTATUS status;
1282         uint32_t rid;
1283         struct dom_sid_buf sidstr;
1284
1285         if (!cache->tdb) {
1286                 return NT_STATUS_INTERNAL_DB_ERROR;
1287         }
1288
1289         if (is_null_sid(sid)) {
1290                 return NT_STATUS_INVALID_SID;
1291         }
1292
1293         if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1294                 return NT_STATUS_INVALID_SID;
1295         }
1296
1297         /* Try and get a salted cred first. If we can't
1298            fall back to an unsalted cred. */
1299
1300         centry = wcache_fetch(cache, domain, "CRED/%s",
1301                               dom_sid_str_buf(sid, &sidstr));
1302         if (!centry) {
1303                 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n", 
1304                           dom_sid_str_buf(sid, &sidstr)));
1305                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1306         }
1307
1308         /*
1309          * We don't use the time element at this moment,
1310          * but we have to consume it, so that we don't
1311          * neet to change the disk format of the cache.
1312          */
1313         (void)centry_time(centry);
1314
1315         /* In the salted case this isn't actually the nt_hash itself,
1316            but the MD5 of the salt + nt_hash. Let the caller
1317            sort this out. It can tell as we only return the cached_salt
1318            if we are returning a salted cred. */
1319
1320         *cached_nt_pass = (const uint8_t *)centry_hash16(centry, mem_ctx);
1321         if (*cached_nt_pass == NULL) {
1322
1323                 dom_sid_str_buf(sid, &sidstr);
1324
1325                 /* Bad (old) cred cache. Delete and pretend we
1326                    don't have it. */
1327                 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n", 
1328                                 sidstr.buf));
1329                 wcache_delete("CRED/%s", sidstr.buf);
1330                 centry_free(centry);
1331                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1332         }
1333
1334         /* We only have 17 bytes more data in the salted cred case. */
1335         if (centry->len - centry->ofs == 17) {
1336                 *cached_salt = (const uint8_t *)centry_hash16(centry, mem_ctx);
1337         } else {
1338                 *cached_salt = NULL;
1339         }
1340
1341         dump_data_pw("cached_nt_pass", *cached_nt_pass, NT_HASH_LEN);
1342         if (*cached_salt) {
1343                 dump_data_pw("cached_salt", *cached_salt, NT_HASH_LEN);
1344         }
1345
1346         status = centry->status;
1347
1348         DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1349                   dom_sid_str_buf(sid, &sidstr),
1350                   nt_errstr(status) ));
1351
1352         centry_free(centry);
1353         return status;
1354 }
1355
1356 /* Store creds for a SID - only writes out new salted ones. */
1357
1358 NTSTATUS wcache_save_creds(struct winbindd_domain *domain, 
1359                            const struct dom_sid *sid,
1360                            const uint8_t nt_pass[NT_HASH_LEN])
1361 {
1362         struct cache_entry *centry;
1363         struct dom_sid_buf sid_str;
1364         uint32_t rid;
1365         uint8_t cred_salt[NT_HASH_LEN];
1366         uint8_t salted_hash[NT_HASH_LEN];
1367
1368         if (is_null_sid(sid)) {
1369                 return NT_STATUS_INVALID_SID;
1370         }
1371
1372         if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1373                 return NT_STATUS_INVALID_SID;
1374         }
1375
1376         centry = centry_start(domain, NT_STATUS_OK);
1377         if (!centry) {
1378                 return NT_STATUS_INTERNAL_DB_ERROR;
1379         }
1380
1381         dump_data_pw("nt_pass", nt_pass, NT_HASH_LEN);
1382
1383         centry_put_time(centry, time(NULL));
1384
1385         /* Create a salt and then salt the hash. */
1386         generate_random_buffer(cred_salt, NT_HASH_LEN);
1387         E_md5hash(cred_salt, nt_pass, salted_hash);
1388
1389         centry_put_hash16(centry, salted_hash);
1390         centry_put_hash16(centry, cred_salt);
1391         centry_end(centry, "CRED/%s", dom_sid_str_buf(sid, &sid_str));
1392
1393         DEBUG(10,("wcache_save_creds: %s\n", sid_str.buf));
1394
1395         centry_free(centry);
1396
1397         return NT_STATUS_OK;
1398 }
1399
1400
1401 /* Query display info. This is the basic user list fn */
1402 NTSTATUS wb_cache_query_user_list(struct winbindd_domain *domain,
1403                                   TALLOC_CTX *mem_ctx,
1404                                   uint32_t **prids)
1405 {
1406         struct winbind_cache *cache = get_cache(domain);
1407         struct cache_entry *centry = NULL;
1408         uint32_t num_rids = 0;
1409         uint32_t *rids = NULL;
1410         NTSTATUS status;
1411         unsigned int i, retry;
1412         bool old_status = domain->online;
1413
1414         *prids = NULL;
1415
1416         if (!cache->tdb)
1417                 goto do_query;
1418
1419         centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1420         if (!centry)
1421                 goto do_query;
1422
1423 do_fetch_cache:
1424         num_rids = centry_uint32(centry);
1425
1426         if (num_rids == 0) {
1427                 goto do_cached;
1428         }
1429
1430         rids = talloc_array(mem_ctx, uint32_t, num_rids);
1431         if (rids == NULL) {
1432                 centry_free(centry);
1433                 return NT_STATUS_NO_MEMORY;
1434         }
1435
1436         for (i=0; i<num_rids; i++) {
1437                 rids[i] = centry_uint32(centry);
1438         }
1439
1440 do_cached:      
1441         status = centry->status;
1442
1443         DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1444                 domain->name, nt_errstr(status) ));
1445
1446         centry_free(centry);
1447         return status;
1448
1449 do_query:
1450
1451         /* Return status value returned by seq number check */
1452
1453         if (!NT_STATUS_IS_OK(domain->last_status))
1454                 return domain->last_status;
1455
1456         /* Put the query_user_list() in a retry loop.  There appears to be
1457          * some bug either with Windows 2000 or Samba's handling of large
1458          * rpc replies.  This manifests itself as sudden disconnection
1459          * at a random point in the enumeration of a large (60k) user list.
1460          * The retry loop simply tries the operation again. )-:  It's not
1461          * pretty but an acceptable workaround until we work out what the
1462          * real problem is. */
1463
1464         retry = 0;
1465         do {
1466
1467                 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1468                         domain->name ));
1469
1470                 rids = NULL;
1471                 status = domain->backend->query_user_list(domain, mem_ctx,
1472                                                           &rids);
1473                 num_rids = talloc_array_length(rids);
1474
1475                 if (!NT_STATUS_IS_OK(status)) {
1476                         DEBUG(3, ("query_user_list: returned 0x%08x, "
1477                                   "retrying\n", NT_STATUS_V(status)));
1478                 }
1479                 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1480                         DEBUG(3, ("query_user_list: flushing "
1481                                   "connection cache\n"));
1482                         invalidate_cm_connection(domain);
1483                 }
1484                 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1485                     NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1486                         if (!domain->internal && old_status) {
1487                                 set_domain_offline(domain);
1488                         }
1489                         /* store partial response. */
1490                         if (num_rids > 0) {
1491                                 /*
1492                                  * humm, what about the status used for cache?
1493                                  * Should it be NT_STATUS_OK?
1494                                  */
1495                                 break;
1496                         }
1497                         /*
1498                          * domain is offline now, and there is no user entries,
1499                          * try to fetch from cache again.
1500                          */
1501                         if (cache->tdb && !domain->online && !domain->internal && old_status) {
1502                                 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1503                                 /* partial response... */
1504                                 if (!centry) {
1505                                         goto skip_save;
1506                                 } else {
1507                                         goto do_fetch_cache;
1508                                 }
1509                         } else {
1510                                 goto skip_save;
1511                         }
1512                 }
1513
1514         } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) && 
1515                  (retry++ < 5));
1516
1517         /* and save it */
1518         refresh_sequence_number(domain);
1519         if (!NT_STATUS_IS_OK(status)) {
1520                 return status;
1521         }
1522         centry = centry_start(domain, status);
1523         if (!centry)
1524                 goto skip_save;
1525         centry_put_uint32(centry, num_rids);
1526         for (i=0; i<num_rids; i++) {
1527                 centry_put_uint32(centry, rids[i]);
1528         }       
1529         centry_end(centry, "UL/%s", domain->name);
1530         centry_free(centry);
1531
1532         *prids = rids;
1533
1534 skip_save:
1535         return status;
1536 }
1537
1538 /* list all domain groups */
1539 NTSTATUS wb_cache_enum_dom_groups(struct winbindd_domain *domain,
1540                                   TALLOC_CTX *mem_ctx,
1541                                   uint32_t *num_entries,
1542                                   struct wb_acct_info **info)
1543 {
1544         struct winbind_cache *cache = get_cache(domain);
1545         struct cache_entry *centry = NULL;
1546         NTSTATUS status;
1547         unsigned int i;
1548         bool old_status;
1549
1550         old_status = domain->online;
1551         if (!cache->tdb)
1552                 goto do_query;
1553
1554         centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1555         if (!centry)
1556                 goto do_query;
1557
1558 do_fetch_cache:
1559         *num_entries = centry_uint32(centry);
1560
1561         if (*num_entries == 0)
1562                 goto do_cached;
1563
1564         (*info) = talloc_array(mem_ctx, struct wb_acct_info, *num_entries);
1565         if (! (*info)) {
1566                 smb_panic_fn("enum_dom_groups out of memory");
1567         }
1568         for (i=0; i<(*num_entries); i++) {
1569                 (*info)[i].acct_name = centry_string(centry, (*info));
1570                 (*info)[i].acct_desc = centry_string(centry, (*info));
1571                 (*info)[i].rid = centry_uint32(centry);
1572         }
1573
1574 do_cached:      
1575         status = centry->status;
1576
1577         DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1578                 domain->name, nt_errstr(status) ));
1579
1580         centry_free(centry);
1581         return status;
1582
1583 do_query:
1584         *num_entries = 0;
1585         *info = NULL;
1586
1587         /* Return status value returned by seq number check */
1588
1589         if (!NT_STATUS_IS_OK(domain->last_status))
1590                 return domain->last_status;
1591
1592         DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1593                 domain->name ));
1594
1595         status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1596
1597         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1598             NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1599                 if (!domain->internal && old_status) {
1600                         set_domain_offline(domain);
1601                 }
1602                 if (cache->tdb &&
1603                         !domain->online &&
1604                         !domain->internal &&
1605                         old_status) {
1606                         centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1607                         if (centry) {
1608                                 goto do_fetch_cache;
1609                         }
1610                 }
1611         }
1612         /* and save it */
1613         refresh_sequence_number(domain);
1614         if (!NT_STATUS_IS_OK(status)) {
1615                 return status;
1616         }
1617         centry = centry_start(domain, status);
1618         if (!centry)
1619                 goto skip_save;
1620         centry_put_uint32(centry, *num_entries);
1621         for (i=0; i<(*num_entries); i++) {
1622                 centry_put_string(centry, (*info)[i].acct_name);
1623                 centry_put_string(centry, (*info)[i].acct_desc);
1624                 centry_put_uint32(centry, (*info)[i].rid);
1625         }       
1626         centry_end(centry, "GL/%s/domain", domain->name);
1627         centry_free(centry);
1628
1629 skip_save:
1630         return status;
1631 }
1632
1633 /* list all domain groups */
1634 NTSTATUS wb_cache_enum_local_groups(struct winbindd_domain *domain,
1635                                     TALLOC_CTX *mem_ctx,
1636                                     uint32_t *num_entries,
1637                                     struct wb_acct_info **info)
1638 {
1639         struct winbind_cache *cache = get_cache(domain);
1640         struct cache_entry *centry = NULL;
1641         NTSTATUS status;
1642         unsigned int i;
1643         bool old_status;
1644
1645         old_status = domain->online;
1646         if (!cache->tdb)
1647                 goto do_query;
1648
1649         centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1650         if (!centry)
1651                 goto do_query;
1652
1653 do_fetch_cache:
1654         *num_entries = centry_uint32(centry);
1655
1656         if (*num_entries == 0)
1657                 goto do_cached;
1658
1659         (*info) = talloc_array(mem_ctx, struct wb_acct_info, *num_entries);
1660         if (! (*info)) {
1661                 smb_panic_fn("enum_dom_groups out of memory");
1662         }
1663         for (i=0; i<(*num_entries); i++) {
1664                 (*info)[i].acct_name = centry_string(centry, (*info));
1665                 (*info)[i].acct_desc = centry_string(centry, (*info));
1666                 (*info)[i].rid = centry_uint32(centry);
1667         }
1668
1669 do_cached:      
1670
1671         /* If we are returning cached data and the domain controller
1672            is down then we don't know whether the data is up to date
1673            or not.  Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1674            indicate this. */
1675
1676         if (wcache_server_down(domain)) {
1677                 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1678                 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1679         } else
1680                 status = centry->status;
1681
1682         DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1683                 domain->name, nt_errstr(status) ));
1684
1685         centry_free(centry);
1686         return status;
1687
1688 do_query:
1689         *num_entries = 0;
1690         *info = NULL;
1691
1692         /* Return status value returned by seq number check */
1693
1694         if (!NT_STATUS_IS_OK(domain->last_status))
1695                 return domain->last_status;
1696
1697         DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1698                 domain->name ));
1699
1700         status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1701
1702         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1703                 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1704                 if (!domain->internal && old_status) {
1705                         set_domain_offline(domain);
1706                 }
1707                 if (cache->tdb &&
1708                         !domain->internal &&
1709                         !domain->online &&
1710                         old_status) {
1711                         centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1712                         if (centry) {
1713                                 goto do_fetch_cache;
1714                         }
1715                 }
1716         }
1717         /* and save it */
1718         refresh_sequence_number(domain);
1719         if (!NT_STATUS_IS_OK(status)) {
1720                 return status;
1721         }
1722         centry = centry_start(domain, status);
1723         if (!centry)
1724                 goto skip_save;
1725         centry_put_uint32(centry, *num_entries);
1726         for (i=0; i<(*num_entries); i++) {
1727                 centry_put_string(centry, (*info)[i].acct_name);
1728                 centry_put_string(centry, (*info)[i].acct_desc);
1729                 centry_put_uint32(centry, (*info)[i].rid);
1730         }
1731         centry_end(centry, "GL/%s/local", domain->name);
1732         centry_free(centry);
1733
1734 skip_save:
1735         return status;
1736 }
1737
1738 struct wcache_name_to_sid_state {
1739         struct dom_sid *sid;
1740         enum lsa_SidType *type;
1741         bool offline;
1742         bool found;
1743 };
1744
1745 static void wcache_name_to_sid_fn(const struct dom_sid *sid,
1746                                   enum lsa_SidType type,
1747                                   bool expired,
1748                                   void *private_data)
1749 {
1750         struct wcache_name_to_sid_state *state = private_data;
1751
1752         *state->sid = *sid;
1753         *state->type = type;
1754         state->found = (!expired || state->offline);
1755 }
1756
1757 static NTSTATUS wcache_name_to_sid(struct winbindd_domain *domain,
1758                                    const char *domain_name,
1759                                    const char *name,
1760                                    struct dom_sid *sid,
1761                                    enum lsa_SidType *type)
1762 {
1763         struct wcache_name_to_sid_state state = {
1764                 .sid = sid, .type = type, .found = false,
1765                 .offline = is_domain_offline(domain),
1766         };
1767         bool ok;
1768
1769         ok = namemap_cache_find_name(domain_name, name, wcache_name_to_sid_fn,
1770                                      &state);
1771         if (!ok) {
1772                 DBG_DEBUG("namemap_cache_find_name failed\n");
1773                 return NT_STATUS_NOT_FOUND;
1774         }
1775         if (!state.found) {
1776                 DBG_DEBUG("cache entry not found\n");
1777                 return NT_STATUS_NOT_FOUND;
1778         }
1779         if (*type == SID_NAME_UNKNOWN) {
1780                 return NT_STATUS_NONE_MAPPED;
1781         }
1782
1783         return NT_STATUS_OK;
1784 }
1785
1786 /* convert a single name to a sid in a domain */
1787 NTSTATUS wb_cache_name_to_sid(struct winbindd_domain *domain,
1788                               TALLOC_CTX *mem_ctx,
1789                               const char *domain_name,
1790                               const char *name,
1791                               uint32_t flags,
1792                               struct dom_sid *sid,
1793                               enum lsa_SidType *type)
1794 {
1795         NTSTATUS status;
1796         bool old_status;
1797
1798         old_status = domain->online;
1799
1800         status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1801         if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1802                 return status;
1803         }
1804
1805         ZERO_STRUCTP(sid);
1806
1807         /* If the seq number check indicated that there is a problem
1808          * with this DC, then return that status... except for
1809          * access_denied.  This is special because the dc may be in
1810          * "restrict anonymous = 1" mode, in which case it will deny
1811          * most unauthenticated operations, but *will* allow the LSA
1812          * name-to-sid that we try as a fallback. */
1813
1814         if (!(NT_STATUS_IS_OK(domain->last_status)
1815               || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1816                 return domain->last_status;
1817
1818         DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1819                 domain->name ));
1820
1821         winbindd_domain_init_backend(domain);
1822         status = domain->backend->name_to_sid(domain, mem_ctx, domain_name,
1823                                               name, flags, NULL, sid, type);
1824
1825         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1826                 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1827                 if (!domain->internal && old_status) {
1828                         set_domain_offline(domain);
1829                 }
1830                 if (!domain->internal &&
1831                         !domain->online &&
1832                         old_status) {
1833                         NTSTATUS cache_status;
1834                         cache_status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1835                         return cache_status;
1836                 }
1837         }
1838         /* and save it */
1839
1840         if (domain->online &&
1841             (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
1842                 enum lsa_SidType save_type = *type;
1843
1844                 if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1845                         save_type = SID_NAME_UNKNOWN;
1846                 }
1847
1848                 wcache_save_name_to_sid(domain, status, domain_name, name, sid,
1849                                         save_type);
1850
1851                 /* Only save the reverse mapping if this was not a UPN */
1852                 if (!strchr(name, '@')) {
1853                         if (!strupper_m(discard_const_p(char, domain_name))) {
1854                                 return NT_STATUS_INVALID_PARAMETER;
1855                         }
1856                         (void)strlower_m(discard_const_p(char, name));
1857                         wcache_save_sid_to_name(domain, status, sid,
1858                                                 domain_name, name, save_type);
1859                 }
1860         }
1861
1862         return status;
1863 }
1864
1865 struct wcache_sid_to_name_state {
1866         TALLOC_CTX *mem_ctx;
1867         char **domain_name;
1868         char **name;
1869         enum lsa_SidType *type;
1870         bool offline;
1871         bool found;
1872 };
1873
1874 static void wcache_sid_to_name_fn(const char *domain,
1875                                   const char *name,
1876                                   enum lsa_SidType type,
1877                                   bool expired,
1878                                   void *private_data)
1879 {
1880         struct wcache_sid_to_name_state *state = private_data;
1881
1882         *state->domain_name = talloc_strdup(state->mem_ctx, domain);
1883         if (*state->domain_name == NULL) {
1884                 return;
1885         }
1886         *state->name = talloc_strdup(state->mem_ctx, name);
1887         if (*state->name == NULL) {
1888                 return;
1889         }
1890         *state->type = type;
1891         state->found = (!expired || state->offline);
1892 }
1893
1894 static NTSTATUS wcache_sid_to_name(struct winbindd_domain *domain,
1895                                    const struct dom_sid *sid,
1896                                    TALLOC_CTX *mem_ctx,
1897                                    char **domain_name,
1898                                    char **name,
1899                                    enum lsa_SidType *type)
1900 {
1901         struct wcache_sid_to_name_state state = {
1902                 .mem_ctx = mem_ctx, .found = false,
1903                 .domain_name = domain_name, .name = name, .type = type,
1904                 .offline = is_domain_offline(domain)
1905         };
1906         bool ok;
1907
1908         ok = namemap_cache_find_sid(sid, wcache_sid_to_name_fn, &state);
1909         if (!ok) {
1910                 DBG_DEBUG("namemap_cache_find_name failed\n");
1911                 return NT_STATUS_NOT_FOUND;
1912         }
1913         if (!state.found) {
1914                 DBG_DEBUG("cache entry not found\n");
1915                 return NT_STATUS_NOT_FOUND;
1916         }
1917         if (*type == SID_NAME_UNKNOWN) {
1918                 return NT_STATUS_NONE_MAPPED;
1919         }
1920
1921         return NT_STATUS_OK;
1922 }
1923
1924 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1925    given */
1926 NTSTATUS wb_cache_sid_to_name(struct winbindd_domain *domain,
1927                               TALLOC_CTX *mem_ctx,
1928                               const struct dom_sid *sid,
1929                               char **domain_name,
1930                               char **name,
1931                               enum lsa_SidType *type)
1932 {
1933         NTSTATUS status;
1934         bool old_status;
1935
1936         old_status = domain->online;
1937         status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
1938                                     type);
1939         if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1940                 return status;
1941         }
1942
1943         *name = NULL;
1944         *domain_name = NULL;
1945
1946         /* If the seq number check indicated that there is a problem
1947          * with this DC, then return that status... except for
1948          * access_denied.  This is special because the dc may be in
1949          * "restrict anonymous = 1" mode, in which case it will deny
1950          * most unauthenticated operations, but *will* allow the LSA
1951          * sid-to-name that we try as a fallback. */
1952
1953         if (!(NT_STATUS_IS_OK(domain->last_status)
1954               || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1955                 return domain->last_status;
1956
1957         DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1958                 domain->name ));
1959
1960         winbindd_domain_init_backend(domain);
1961
1962         status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1963
1964         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1965                 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1966                 if (!domain->internal && old_status) {
1967                         set_domain_offline(domain);
1968                 }
1969                 if (!domain->internal &&
1970                         !domain->online &&
1971                         old_status) {
1972                         NTSTATUS cache_status;
1973                         cache_status = wcache_sid_to_name(domain, sid, mem_ctx,
1974                                                         domain_name, name, type);
1975                         return cache_status;
1976                 }
1977         }
1978         /* and save it */
1979         if (!NT_STATUS_IS_OK(status)) {
1980                 return status;
1981         }
1982         wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1983
1984         /* We can't save the name to sid mapping here, as with sid history a
1985          * later name2sid would give the wrong sid. */
1986
1987         return status;
1988 }
1989
1990 NTSTATUS wb_cache_rids_to_names(struct winbindd_domain *domain,
1991                                 TALLOC_CTX *mem_ctx,
1992                                 const struct dom_sid *domain_sid,
1993                                 uint32_t *rids,
1994                                 size_t num_rids,
1995                                 char **domain_name,
1996                                 char ***names,
1997                                 enum lsa_SidType **types)
1998 {
1999         struct winbind_cache *cache = get_cache(domain);
2000         size_t i;
2001         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
2002         bool have_mapped;
2003         bool have_unmapped;
2004         bool old_status;
2005
2006         old_status = domain->online;
2007         *domain_name = NULL;
2008         *names = NULL;
2009         *types = NULL;
2010
2011         if (!cache->tdb) {
2012                 goto do_query;
2013         }
2014
2015         if (num_rids == 0) {
2016                 return NT_STATUS_OK;
2017         }
2018
2019         *names = talloc_array(mem_ctx, char *, num_rids);
2020         *types = talloc_array(mem_ctx, enum lsa_SidType, num_rids);
2021
2022         if ((*names == NULL) || (*types == NULL)) {
2023                 result = NT_STATUS_NO_MEMORY;
2024                 goto error;
2025         }
2026
2027         have_mapped = have_unmapped = false;
2028
2029         for (i=0; i<num_rids; i++) {
2030                 struct dom_sid sid;
2031                 NTSTATUS status;
2032                 enum lsa_SidType type;
2033                 char *dom, *name;
2034
2035                 if (!sid_compose(&sid, domain_sid, rids[i])) {
2036                         result = NT_STATUS_INTERNAL_ERROR;
2037                         goto error;
2038                 }
2039
2040                 status = wcache_sid_to_name(domain, &sid, *names, &dom,
2041                                             &name, &type);
2042
2043                 (*types)[i] = SID_NAME_UNKNOWN;
2044                 (*names)[i] = talloc_strdup(*names, "");
2045
2046                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2047                         /* not cached */
2048                         goto do_query;
2049                 }
2050
2051                 if (NT_STATUS_IS_OK(status)) {
2052                         have_mapped = true;
2053                         (*types)[i] = type;
2054
2055                         if (*domain_name == NULL) {
2056                                 *domain_name = dom;
2057                         } else {
2058                                 TALLOC_FREE(dom);
2059                         }
2060
2061                         (*names)[i] = name;
2062
2063                 } else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
2064                         have_unmapped = true;
2065                 } else {
2066                         /* something's definitely wrong */
2067                         result = status;
2068                         goto error;
2069                 }
2070         }
2071
2072         if (!have_mapped) {
2073                 return NT_STATUS_NONE_MAPPED;
2074         }
2075         if (!have_unmapped) {
2076                 return NT_STATUS_OK;
2077         }
2078         return STATUS_SOME_UNMAPPED;
2079
2080  do_query:
2081
2082         TALLOC_FREE(*names);
2083         TALLOC_FREE(*types);
2084
2085         result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
2086                                                 rids, num_rids, domain_name,
2087                                                 names, types);
2088
2089         if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
2090             NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2091                 if (!domain->internal && old_status) {
2092                         set_domain_offline(domain);
2093                 }
2094                 if (cache->tdb &&
2095                         !domain->internal &&
2096                         !domain->online &&
2097                         old_status) {
2098                         have_mapped = have_unmapped = false;
2099
2100                         *names = talloc_array(mem_ctx, char *, num_rids);
2101                         if (*names == NULL) {
2102                                 result = NT_STATUS_NO_MEMORY;
2103                                 goto error;
2104                         }
2105
2106                         *types = talloc_array(mem_ctx, enum lsa_SidType,
2107                                               num_rids);
2108                         if (*types == NULL) {
2109                                 result = NT_STATUS_NO_MEMORY;
2110                                 goto error;
2111                         }
2112
2113                         for (i=0; i<num_rids; i++) {
2114                                 struct dom_sid sid;
2115                                 NTSTATUS status;
2116                                 enum lsa_SidType type;
2117                                 char *dom, *name;
2118
2119                                 if (!sid_compose(&sid, domain_sid, rids[i])) {
2120                                         result = NT_STATUS_INTERNAL_ERROR;
2121                                         goto error;
2122                                 }
2123
2124                                 status = wcache_sid_to_name(domain, &sid,
2125                                                             *names, &dom,
2126                                                             &name, &type);
2127
2128                                 (*types)[i] = SID_NAME_UNKNOWN;
2129                                 (*names)[i] = talloc_strdup(*names, "");
2130
2131                                 if (NT_STATUS_IS_OK(status)) {
2132                                         have_mapped = true;
2133                                         (*types)[i] = type;
2134
2135                                         if (*domain_name == NULL) {
2136                                                 *domain_name = dom;
2137                                         } else {
2138                                                 TALLOC_FREE(dom);
2139                                         }
2140
2141                                         (*names)[i] = name;
2142
2143                                 } else if (NT_STATUS_EQUAL(
2144                                                    status,
2145                                                    NT_STATUS_NONE_MAPPED)) {
2146                                         have_unmapped = true;
2147                                 } else {
2148                                         /* something's definitely wrong */
2149                                         result = status;
2150                                         goto error;
2151                                 }
2152                         }
2153
2154                         if (!have_mapped) {
2155                                 return NT_STATUS_NONE_MAPPED;
2156                         }
2157                         if (!have_unmapped) {
2158                                 return NT_STATUS_OK;
2159                         }
2160                         return STATUS_SOME_UNMAPPED;
2161                 }
2162         }
2163         /*
2164           None of the queried rids has been found so save all negative entries
2165         */
2166         if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
2167                 for (i = 0; i < num_rids; i++) {
2168                         struct dom_sid sid;
2169                         const char *name = "";
2170                         const enum lsa_SidType type = SID_NAME_UNKNOWN;
2171                         NTSTATUS status = NT_STATUS_NONE_MAPPED;
2172
2173                         if (!sid_compose(&sid, domain_sid, rids[i])) {
2174                                 return NT_STATUS_INTERNAL_ERROR;
2175                         }
2176
2177                         wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2178                                                 name, type);
2179                 }
2180
2181                 return result;
2182         }
2183
2184         /*
2185           Some or all of the queried rids have been found.
2186         */
2187         if (!NT_STATUS_IS_OK(result) &&
2188             !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
2189                 return result;
2190         }
2191
2192         refresh_sequence_number(domain);
2193
2194         for (i=0; i<num_rids; i++) {
2195                 struct dom_sid sid;
2196                 NTSTATUS status;
2197
2198                 if (!sid_compose(&sid, domain_sid, rids[i])) {
2199                         result = NT_STATUS_INTERNAL_ERROR;
2200                         goto error;
2201                 }
2202
2203                 status = (*types)[i] == SID_NAME_UNKNOWN ?
2204                         NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
2205
2206                 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2207                                         (*names)[i], (*types)[i]);
2208         }
2209
2210         return result;
2211
2212  error:
2213         TALLOC_FREE(*names);
2214         TALLOC_FREE(*types);
2215         return result;
2216 }
2217
2218 static NTSTATUS wcache_query_user(struct winbindd_domain *domain,
2219                                   TALLOC_CTX *mem_ctx,
2220                                   const struct dom_sid *user_sid,
2221                                   struct wbint_userinfo *info)
2222 {
2223         struct winbind_cache *cache = get_cache(domain);
2224         struct cache_entry *centry = NULL;
2225         NTSTATUS status;
2226         struct dom_sid_buf sid_string;
2227
2228         if (cache->tdb == NULL) {
2229                 return NT_STATUS_NOT_FOUND;
2230         }
2231
2232         centry = wcache_fetch(
2233                 cache, domain, "U/%s", dom_sid_str_buf(user_sid, &sid_string));
2234         if (centry == NULL) {
2235                 return NT_STATUS_NOT_FOUND;
2236         }
2237
2238         /*
2239          * If we have an access denied cache entry and a cached info3
2240          * in the samlogon cache then do a query.  This will force the
2241          * rpc back end to return the info3 data.
2242          */
2243
2244         if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED) &&
2245             netsamlogon_cache_have(user_sid)) {
2246                 DEBUG(10, ("query_user: cached access denied and have cached "
2247                            "info3\n"));
2248                 domain->last_status = NT_STATUS_OK;
2249                 centry_free(centry);
2250                 return NT_STATUS_NOT_FOUND;
2251         }
2252
2253         /* if status is not ok then this is a negative hit
2254            and the rest of the data doesn't matter */
2255         status = centry->status;
2256         if (NT_STATUS_IS_OK(status)) {
2257                 info->domain_name = centry_string(centry, mem_ctx);
2258                 info->acct_name = centry_string(centry, mem_ctx);
2259                 info->full_name = centry_string(centry, mem_ctx);
2260                 info->homedir = centry_string(centry, mem_ctx);
2261                 info->shell = centry_string(centry, mem_ctx);
2262                 info->uid = centry_uint32(centry);
2263                 info->primary_gid = centry_uint32(centry);
2264                 info->primary_group_name = centry_string(centry, mem_ctx);
2265                 centry_sid(centry, &info->user_sid);
2266                 centry_sid(centry, &info->group_sid);
2267         }
2268
2269         DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2270                   "%s\n", domain->name, nt_errstr(status) ));
2271
2272         centry_free(centry);
2273         return status;
2274 }
2275
2276
2277 /**
2278 * @brief Query a fullname from the username cache (for further gecos processing)
2279 *
2280 * @param domain         A pointer to the winbindd_domain struct.
2281 * @param mem_ctx        The talloc context.
2282 * @param user_sid       The user sid.
2283 * @param full_name      A pointer to the full_name string.
2284 *
2285 * @return NTSTATUS code
2286 */
2287 NTSTATUS wcache_query_user_fullname(struct winbindd_domain *domain,
2288                                     TALLOC_CTX *mem_ctx,
2289                                     const struct dom_sid *user_sid,
2290                                     const char **full_name)
2291 {
2292         NTSTATUS status;
2293         struct wbint_userinfo info;
2294
2295         status = wcache_query_user(domain, mem_ctx, user_sid, &info);
2296         if (!NT_STATUS_IS_OK(status)) {
2297                 return status;
2298         }
2299
2300         if (info.full_name != NULL) {
2301                 *full_name = talloc_strdup(mem_ctx, info.full_name);
2302                 if (*full_name == NULL) {
2303                         return NT_STATUS_NO_MEMORY;
2304                 }
2305         }
2306
2307         return NT_STATUS_OK;
2308 }
2309
2310 static NTSTATUS wcache_lookup_usergroups(struct winbindd_domain *domain,
2311                                          TALLOC_CTX *mem_ctx,
2312                                          const struct dom_sid *user_sid,
2313                                          uint32_t *pnum_sids,
2314                                          struct dom_sid **psids)
2315 {
2316         struct winbind_cache *cache = get_cache(domain);
2317         struct cache_entry *centry = NULL;
2318         NTSTATUS status;
2319         uint32_t i, num_sids;
2320         struct dom_sid *sids;
2321         struct dom_sid_buf sid_string;
2322
2323         if (cache->tdb == NULL) {
2324                 return NT_STATUS_NOT_FOUND;
2325         }
2326
2327         centry = wcache_fetch(
2328                 cache,
2329                 domain,
2330                 "UG/%s",
2331                 dom_sid_str_buf(user_sid, &sid_string));
2332         if (centry == NULL) {
2333                 return NT_STATUS_NOT_FOUND;
2334         }
2335
2336         /* If we have an access denied cache entry and a cached info3 in the
2337            samlogon cache then do a query.  This will force the rpc back end
2338            to return the info3 data. */
2339
2340         if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)
2341             && netsamlogon_cache_have(user_sid)) {
2342                 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2343                            "cached info3\n"));
2344                 domain->last_status = NT_STATUS_OK;
2345                 centry_free(centry);
2346                 return NT_STATUS_NOT_FOUND;
2347         }
2348
2349         num_sids = centry_uint32(centry);
2350         sids = talloc_array(mem_ctx, struct dom_sid, num_sids);
2351         if (sids == NULL) {
2352                 centry_free(centry);
2353                 return NT_STATUS_NO_MEMORY;
2354         }
2355
2356         for (i=0; i<num_sids; i++) {
2357                 centry_sid(centry, &sids[i]);
2358         }
2359
2360         status = centry->status;
2361
2362         DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2363                   "status: %s\n", domain->name, nt_errstr(status)));
2364
2365         centry_free(centry);
2366
2367         *pnum_sids = num_sids;
2368         *psids = sids;
2369         return status;
2370 }
2371
2372 /* Lookup groups a user is a member of. */
2373 NTSTATUS wb_cache_lookup_usergroups(struct winbindd_domain *domain,
2374                                     TALLOC_CTX *mem_ctx,
2375                                     const struct dom_sid *user_sid,
2376                                     uint32_t *num_groups,
2377                                     struct dom_sid **user_gids)
2378 {
2379         struct cache_entry *centry = NULL;
2380         NTSTATUS status;
2381         unsigned int i;
2382         struct dom_sid_buf sid_string;
2383         bool old_status;
2384
2385         old_status = domain->online;
2386         status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2387                                           num_groups, user_gids);
2388         if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2389                 return status;
2390         }
2391
2392         (*num_groups) = 0;
2393         (*user_gids) = NULL;
2394
2395         /* Return status value returned by seq number check */
2396
2397         if (!NT_STATUS_IS_OK(domain->last_status))
2398                 return domain->last_status;
2399
2400         DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2401                 domain->name ));
2402
2403         status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
2404
2405         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2406                 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2407                 if (!domain->internal && old_status) {
2408                         set_domain_offline(domain);
2409                 }
2410                 if (!domain->internal &&
2411                         !domain->online &&
2412                         old_status) {
2413                         NTSTATUS cache_status;
2414                         cache_status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2415                                                           num_groups, user_gids);
2416                         return cache_status;
2417                 }
2418         }
2419         if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
2420                 goto skip_save;
2421
2422         /* and save it */
2423         refresh_sequence_number(domain);
2424         if (!NT_STATUS_IS_OK(status)) {
2425                 return status;
2426         }
2427         centry = centry_start(domain, status);
2428         if (!centry)
2429                 goto skip_save;
2430
2431         centry_put_uint32(centry, *num_groups);
2432         for (i=0; i<(*num_groups); i++) {
2433                 centry_put_sid(centry, &(*user_gids)[i]);
2434         }       
2435
2436         centry_end(centry, "UG/%s", dom_sid_str_buf(user_sid, &sid_string));
2437         centry_free(centry);
2438
2439 skip_save:
2440         return status;
2441 }
2442
2443 static char *wcache_make_sidlist(TALLOC_CTX *mem_ctx, uint32_t num_sids,
2444                                  const struct dom_sid *sids)
2445 {
2446         uint32_t i;
2447         char *sidlist;
2448
2449         sidlist = talloc_strdup(mem_ctx, "");
2450         if (sidlist == NULL) {
2451                 return NULL;
2452         }
2453         for (i=0; i<num_sids; i++) {
2454                 struct dom_sid_buf tmp;
2455                 sidlist = talloc_asprintf_append_buffer(
2456                         sidlist,
2457                         "/%s",
2458                         dom_sid_str_buf(&sids[i], &tmp));
2459                 if (sidlist == NULL) {
2460                         return NULL;
2461                 }
2462         }
2463         return sidlist;
2464 }
2465
2466 static NTSTATUS wcache_lookup_useraliases(struct winbindd_domain *domain,
2467                                           TALLOC_CTX *mem_ctx,
2468                                           uint32_t num_sids,
2469                                           const struct dom_sid *sids,
2470                                           uint32_t *pnum_aliases,
2471                                           uint32_t **paliases)
2472 {
2473         struct winbind_cache *cache = get_cache(domain);
2474         struct cache_entry *centry = NULL;
2475         uint32_t i, num_aliases;
2476         uint32_t *aliases;
2477         NTSTATUS status;
2478         char *sidlist;
2479
2480         if (cache->tdb == NULL) {
2481                 return NT_STATUS_NOT_FOUND;
2482         }
2483
2484         if (num_sids == 0) {
2485                 *pnum_aliases = 0;
2486                 *paliases = NULL;
2487                 return NT_STATUS_OK;
2488         }
2489
2490         /* We need to cache indexed by the whole list of SIDs, the aliases
2491          * resulting might come from any of the SIDs. */
2492
2493         sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2494         if (sidlist == NULL) {
2495                 return NT_STATUS_NO_MEMORY;
2496         }
2497
2498         centry = wcache_fetch(cache, domain, "UA%s", sidlist);
2499         TALLOC_FREE(sidlist);
2500         if (centry == NULL) {
2501                 return NT_STATUS_NOT_FOUND;
2502         }
2503
2504         num_aliases = centry_uint32(centry);
2505         aliases = talloc_array(mem_ctx, uint32_t, num_aliases);
2506         if (aliases == NULL) {
2507                 centry_free(centry);
2508                 return NT_STATUS_NO_MEMORY;
2509         }
2510
2511         for (i=0; i<num_aliases; i++) {
2512                 aliases[i] = centry_uint32(centry);
2513         }
2514
2515         status = centry->status;
2516
2517         DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2518                   "status %s\n", domain->name, nt_errstr(status)));
2519
2520         centry_free(centry);
2521
2522         *pnum_aliases = num_aliases;
2523         *paliases = aliases;
2524
2525         return status;
2526 }
2527
2528 NTSTATUS wb_cache_lookup_useraliases(struct winbindd_domain *domain,
2529                                      TALLOC_CTX *mem_ctx,
2530                                      uint32_t num_sids,
2531                                      const struct dom_sid *sids,
2532                                      uint32_t *num_aliases,
2533                                      uint32_t **alias_rids)
2534 {
2535         struct cache_entry *centry = NULL;
2536         NTSTATUS status;
2537         char *sidlist;
2538         uint32_t i;
2539         bool old_status;
2540
2541         old_status = domain->online;
2542         status = wcache_lookup_useraliases(domain, mem_ctx, num_sids, sids,
2543                                            num_aliases, alias_rids);
2544         if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2545                 return status;
2546         }
2547
2548         (*num_aliases) = 0;
2549         (*alias_rids) = NULL;
2550
2551         if (!NT_STATUS_IS_OK(domain->last_status))
2552                 return domain->last_status;
2553
2554         DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2555                   "for domain %s\n", domain->name ));
2556
2557         sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2558         if (sidlist == NULL) {
2559                 return NT_STATUS_NO_MEMORY;
2560         }
2561
2562         status = domain->backend->lookup_useraliases(domain, mem_ctx,
2563                                                      num_sids, sids,
2564                                                      num_aliases, alias_rids);
2565
2566         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2567                 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2568                 if (!domain->internal && old_status) {
2569                         set_domain_offline(domain);
2570                 }
2571                 if (!domain->internal &&
2572                         !domain->online &&
2573                         old_status) {
2574                         NTSTATUS cache_status;
2575                         cache_status = wcache_lookup_useraliases(domain, mem_ctx, num_sids,
2576                                                                  sids, num_aliases, alias_rids);
2577                         return cache_status;
2578                 }
2579         }
2580         /* and save it */
2581         refresh_sequence_number(domain);
2582         if (!NT_STATUS_IS_OK(status)) {
2583                 return status;
2584         }
2585         centry = centry_start(domain, status);
2586         if (!centry)
2587                 goto skip_save;
2588         centry_put_uint32(centry, *num_aliases);
2589         for (i=0; i<(*num_aliases); i++)
2590                 centry_put_uint32(centry, (*alias_rids)[i]);
2591         centry_end(centry, "UA%s", sidlist);
2592         centry_free(centry);
2593
2594  skip_save:
2595         return status;
2596 }
2597
2598 static NTSTATUS wcache_lookup_groupmem(struct winbindd_domain *domain,
2599                                        TALLOC_CTX *mem_ctx,
2600                                        const struct dom_sid *group_sid,
2601                                        uint32_t *num_names,
2602                                        struct dom_sid **sid_mem, char ***names,
2603                                        uint32_t **name_types)
2604 {
2605         struct winbind_cache *cache = get_cache(domain);
2606         struct cache_entry *centry = NULL;
2607         NTSTATUS status;
2608         unsigned int i;
2609         struct dom_sid_buf sid_string;
2610
2611         if (cache->tdb == NULL) {
2612                 return NT_STATUS_NOT_FOUND;
2613         }
2614
2615         centry = wcache_fetch(
2616                 cache,
2617                 domain,
2618                 "GM/%s",
2619                 dom_sid_str_buf(group_sid, &sid_string));
2620         if (centry == NULL) {
2621                 return NT_STATUS_NOT_FOUND;
2622         }
2623
2624         *sid_mem = NULL;
2625         *names = NULL;
2626         *name_types = NULL;
2627
2628         *num_names = centry_uint32(centry);
2629         if (*num_names == 0) {
2630                 centry_free(centry);
2631                 return NT_STATUS_OK;
2632         }
2633
2634         *sid_mem = talloc_array(mem_ctx, struct dom_sid, *num_names);
2635         *names = talloc_array(mem_ctx, char *, *num_names);
2636         *name_types = talloc_array(mem_ctx, uint32_t, *num_names);
2637
2638         if ((*sid_mem == NULL) || (*names == NULL) || (*name_types == NULL)) {
2639                 TALLOC_FREE(*sid_mem);
2640                 TALLOC_FREE(*names);
2641                 TALLOC_FREE(*name_types);
2642                 centry_free(centry);
2643                 return NT_STATUS_NO_MEMORY;
2644         }
2645
2646         for (i=0; i<(*num_names); i++) {
2647                 centry_sid(centry, &(*sid_mem)[i]);
2648                 (*names)[i] = centry_string(centry, mem_ctx);
2649                 (*name_types)[i] = centry_uint32(centry);
2650         }
2651
2652         status = centry->status;
2653
2654         DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2655                   "status: %s\n", domain->name, nt_errstr(status)));
2656
2657         centry_free(centry);
2658         return status;
2659 }
2660
2661 NTSTATUS wb_cache_lookup_groupmem(struct winbindd_domain *domain,
2662                                   TALLOC_CTX *mem_ctx,
2663                                   const struct dom_sid *group_sid,
2664                                   enum lsa_SidType type,
2665                                   uint32_t *num_names,
2666                                   struct dom_sid **sid_mem,
2667                                   char ***names,
2668                                   uint32_t **name_types)
2669 {
2670         struct cache_entry *centry = NULL;
2671         NTSTATUS status;
2672         unsigned int i;
2673         struct dom_sid_buf sid_string;
2674         bool old_status;
2675
2676         old_status = domain->online;
2677         status = wcache_lookup_groupmem(domain, mem_ctx, group_sid, num_names,
2678                                         sid_mem, names, name_types);
2679         if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2680                 return status;
2681         }
2682
2683         (*num_names) = 0;
2684         (*sid_mem) = NULL;
2685         (*names) = NULL;
2686         (*name_types) = NULL;
2687
2688         /* Return status value returned by seq number check */
2689
2690         if (!NT_STATUS_IS_OK(domain->last_status))
2691                 return domain->last_status;
2692
2693         DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2694                 domain->name ));
2695
2696         status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid,
2697                                                   type, num_names,
2698                                                   sid_mem, names, name_types);
2699
2700         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2701                 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2702                 if (!domain->internal && old_status) {
2703                         set_domain_offline(domain);
2704                 }
2705                 if (!domain->internal &&
2706                         !domain->online &&
2707                         old_status) {
2708                         NTSTATUS cache_status;
2709                         cache_status = wcache_lookup_groupmem(domain, mem_ctx, group_sid,
2710                                                               num_names, sid_mem, names,
2711                                                               name_types);
2712                         return cache_status;
2713                 }
2714         }
2715         /* and save it */
2716         refresh_sequence_number(domain);
2717         if (!NT_STATUS_IS_OK(status)) {
2718                 return status;
2719         }
2720         centry = centry_start(domain, status);
2721         if (!centry)
2722                 goto skip_save;
2723         centry_put_uint32(centry, *num_names);
2724         for (i=0; i<(*num_names); i++) {
2725                 centry_put_sid(centry, &(*sid_mem)[i]);
2726                 centry_put_string(centry, (*names)[i]);
2727                 centry_put_uint32(centry, (*name_types)[i]);
2728         }       
2729         centry_end(centry,
2730                    "GM/%s",
2731                    dom_sid_str_buf(group_sid, &sid_string));
2732         centry_free(centry);
2733
2734 skip_save:
2735         return status;
2736 }
2737
2738 /* find the sequence number for a domain */
2739 NTSTATUS wb_cache_sequence_number(struct winbindd_domain *domain,
2740                                   uint32_t *seq)
2741 {
2742         refresh_sequence_number(domain);
2743
2744         *seq = domain->sequence_number;
2745
2746         return NT_STATUS_OK;
2747 }
2748
2749 /* enumerate trusted domains 
2750  * (we need to have the list of trustdoms in the cache when we go offline) -
2751  * Guenther */
2752 NTSTATUS wb_cache_trusted_domains(struct winbindd_domain *domain,
2753                                   TALLOC_CTX *mem_ctx,
2754                                   struct netr_DomainTrustList *trusts)
2755 {
2756         NTSTATUS status;
2757         struct winbind_cache *cache;
2758         struct winbindd_tdc_domain *dom_list = NULL;
2759         size_t num_domains = 0;
2760         bool retval = false;
2761         size_t i;
2762         bool old_status;
2763
2764         old_status = domain->online;
2765         trusts->count = 0;
2766         trusts->array = NULL;
2767
2768         cache = get_cache(domain);
2769         if (!cache || !cache->tdb) {
2770                 goto do_query;
2771         }
2772
2773         if (domain->online) {
2774                 goto do_query;
2775         }
2776
2777         retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2778         if (!retval || !num_domains || !dom_list) {
2779                 TALLOC_FREE(dom_list);
2780                 goto do_query;
2781         }
2782
2783 do_fetch_cache:
2784         trusts->array = talloc_zero_array(mem_ctx, struct netr_DomainTrust, num_domains);
2785         if (!trusts->array) {
2786                 TALLOC_FREE(dom_list);
2787                 return NT_STATUS_NO_MEMORY;
2788         }
2789
2790         for (i = 0; i < num_domains; i++) {
2791                 struct netr_DomainTrust *trust;
2792                 struct dom_sid *sid;
2793                 struct winbindd_domain *dom;
2794
2795                 dom = find_domain_from_name_noinit(dom_list[i].domain_name);
2796                 if (dom && dom->internal) {
2797                         continue;
2798                 }
2799
2800                 trust = &trusts->array[trusts->count];
2801                 trust->netbios_name = talloc_strdup(trusts->array, dom_list[i].domain_name);
2802                 trust->dns_name = talloc_strdup(trusts->array, dom_list[i].dns_name);
2803                 sid = talloc(trusts->array, struct dom_sid);
2804                 if (!trust->netbios_name || !trust->dns_name ||
2805                         !sid) {
2806                         TALLOC_FREE(dom_list);
2807                         TALLOC_FREE(trusts->array);
2808                         return NT_STATUS_NO_MEMORY;
2809                 }
2810
2811                 trust->trust_flags = dom_list[i].trust_flags;
2812                 trust->trust_attributes = dom_list[i].trust_attribs;
2813                 trust->trust_type = dom_list[i].trust_type;
2814                 sid_copy(sid, &dom_list[i].sid);
2815                 trust->sid = sid;
2816                 trusts->count++;
2817         }
2818
2819         TALLOC_FREE(dom_list);
2820         return NT_STATUS_OK;
2821
2822 do_query:
2823         /* Return status value returned by seq number check */
2824
2825         if (!NT_STATUS_IS_OK(domain->last_status))
2826                 return domain->last_status;
2827
2828         DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2829                 domain->name ));
2830
2831         status = domain->backend->trusted_domains(domain, mem_ctx, trusts);
2832
2833         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2834                 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2835                 if (!domain->internal && old_status) {
2836                         set_domain_offline(domain);
2837                 }
2838                 if (!domain->internal &&
2839                         !domain->online &&
2840                         old_status) {
2841                         retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2842                         if (retval && num_domains && dom_list) {
2843                                 TALLOC_FREE(trusts->array);
2844                                 trusts->count = 0;
2845                                 goto do_fetch_cache;
2846                         }
2847                 }
2848         }
2849         /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2850          * so that the generic centry handling still applies correctly -
2851          * Guenther*/
2852
2853         if (!NT_STATUS_IS_ERR(status)) {
2854                 status = NT_STATUS_OK;
2855         }
2856         return status;
2857 }       
2858
2859 /* get lockout policy */
2860 NTSTATUS wb_cache_lockout_policy(struct winbindd_domain *domain,
2861                                  TALLOC_CTX *mem_ctx,
2862                                  struct samr_DomInfo12 *policy)
2863 {
2864         struct winbind_cache *cache = get_cache(domain);
2865         struct cache_entry *centry = NULL;
2866         NTSTATUS status;
2867         bool old_status;
2868
2869         old_status = domain->online;
2870         if (!cache->tdb)
2871                 goto do_query;
2872
2873         centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2874
2875         if (!centry)
2876                 goto do_query;
2877
2878 do_fetch_cache:
2879         policy->lockout_duration = centry_nttime(centry);
2880         policy->lockout_window = centry_nttime(centry);
2881         policy->lockout_threshold = centry_uint16(centry);
2882
2883         status = centry->status;
2884
2885         DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2886                 domain->name, nt_errstr(status) ));
2887
2888         centry_free(centry);
2889         return status;
2890
2891 do_query:
2892         ZERO_STRUCTP(policy);
2893
2894         /* Return status value returned by seq number check */
2895
2896         if (!NT_STATUS_IS_OK(domain->last_status))
2897                 return domain->last_status;
2898
2899         DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2900                 domain->name ));
2901
2902         status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2903
2904         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2905                 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2906                 if (!domain->internal && old_status) {
2907                         set_domain_offline(domain);
2908                 }
2909                 if (cache->tdb &&
2910                         !domain->internal &&
2911                         !domain->online &&
2912                         old_status) {
2913                         centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2914                         if (centry) {
2915                                 goto do_fetch_cache;
2916                         }
2917                 }
2918         }
2919         /* and save it */
2920         refresh_sequence_number(domain);
2921         if (!NT_STATUS_IS_OK(status)) {
2922                 return status;
2923         }
2924         wcache_save_lockout_policy(domain, status, policy);
2925
2926         return status;
2927 }
2928
2929 /* get password policy */
2930 NTSTATUS wb_cache_password_policy(struct winbindd_domain *domain,
2931                                   TALLOC_CTX *mem_ctx,
2932                                   struct samr_DomInfo1 *policy)
2933 {
2934         struct winbind_cache *cache = get_cache(domain);
2935         struct cache_entry *centry = NULL;
2936         NTSTATUS status;
2937         bool old_status;
2938
2939         old_status = domain->online;
2940         if (!cache->tdb)
2941                 goto do_query;
2942
2943         centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2944
2945         if (!centry)
2946                 goto do_query;
2947
2948 do_fetch_cache:
2949         policy->min_password_length = centry_uint16(centry);
2950         policy->password_history_length = centry_uint16(centry);
2951         policy->password_properties = centry_uint32(centry);
2952         policy->max_password_age = centry_nttime(centry);
2953         policy->min_password_age = centry_nttime(centry);
2954
2955         status = centry->status;
2956
2957         DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2958                 domain->name, nt_errstr(status) ));
2959
2960         centry_free(centry);
2961         return status;
2962
2963 do_query:
2964         ZERO_STRUCTP(policy);
2965
2966         /* Return status value returned by seq number check */
2967
2968         if (!NT_STATUS_IS_OK(domain->last_status))
2969                 return domain->last_status;
2970
2971         DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2972                 domain->name ));
2973
2974         status = domain->backend->password_policy(domain, mem_ctx, policy);
2975
2976         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2977                 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2978                 if (!domain->internal && old_status) {
2979                         set_domain_offline(domain);
2980                 }
2981                 if (cache->tdb &&
2982                         !domain->internal &&
2983                         !domain->online &&
2984                         old_status) {
2985                         centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2986                         if (centry) {
2987                                 goto do_fetch_cache;
2988                         }
2989                 }
2990         }
2991         /* and save it */
2992         refresh_sequence_number(domain);
2993         if (!NT_STATUS_IS_OK(status)) {
2994                 return status;
2995         }
2996         wcache_save_password_policy(domain, status, policy);
2997
2998         return status;
2999 }
3000
3001
3002 /* Invalidate cached user and group lists coherently */
3003
3004 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, 
3005                        void *state)
3006 {
3007         if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
3008             strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
3009                 tdb_delete(the_tdb, kbuf);
3010
3011         return 0;
3012 }
3013
3014 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3015
3016 void wcache_invalidate_samlogon(struct winbindd_domain *domain, 
3017                                 const struct dom_sid *sid)
3018 {
3019         fstring key_str;
3020         struct dom_sid_buf sid_string;
3021         struct winbind_cache *cache;
3022
3023         /* don't clear cached U/SID and UG/SID entries when we want to logon
3024          * offline - gd */
3025
3026         if (lp_winbind_offline_logon()) {
3027                 return;
3028         }
3029
3030         if (!domain)
3031                 return;
3032
3033         cache = get_cache(domain);
3034
3035         if (!cache->tdb) {
3036                 return;
3037         }
3038
3039         /* Clear U/SID cache entry */
3040         fstr_sprintf(key_str, "U/%s", dom_sid_str_buf(sid, &sid_string));
3041         DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
3042         tdb_delete(cache->tdb, string_tdb_data(key_str));
3043
3044         /* Clear UG/SID cache entry */
3045         fstr_sprintf(key_str, "UG/%s", dom_sid_str_buf(sid, &sid_string));
3046         DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
3047         tdb_delete(cache->tdb, string_tdb_data(key_str));
3048
3049         /* Samba/winbindd never needs this. */
3050         netsamlogon_clear_cached_user(sid);
3051 }
3052
3053 bool wcache_invalidate_cache(void)
3054 {
3055         struct winbindd_domain *domain;
3056
3057         for (domain = domain_list(); domain; domain = domain->next) {
3058                 struct winbind_cache *cache = get_cache(domain);
3059
3060                 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3061                            "entries for %s\n", domain->name));
3062                 if (cache) {
3063                         if (cache->tdb) {
3064                                 tdb_traverse(cache->tdb, traverse_fn, NULL);
3065                         } else {
3066                                 return false;
3067                         }
3068                 }
3069         }
3070         return true;
3071 }
3072
3073 bool wcache_invalidate_cache_noinit(void)
3074 {
3075         struct winbindd_domain *domain;
3076
3077         for (domain = domain_list(); domain; domain = domain->next) {
3078                 struct winbind_cache *cache;
3079
3080                 /* Skip uninitialized domains. */
3081                 if (!domain->initialized && !domain->internal) {
3082                         continue;
3083                 }
3084
3085                 cache = get_cache(domain);
3086
3087                 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3088                            "entries for %s\n", domain->name));
3089                 if (cache) {
3090                         if (cache->tdb) {
3091                                 tdb_traverse(cache->tdb, traverse_fn, NULL);
3092                                 /*
3093                                  * Flushing cache has nothing to with domains.
3094                                  * return here if we successfully flushed once.
3095                                  * To avoid unnecessary traversing the cache.
3096                                  */
3097                                 return true;
3098                         } else {
3099                                 return false;
3100                         }
3101                 }
3102         }
3103         return true;
3104 }
3105
3106 static bool init_wcache(void)
3107 {
3108         char *db_path;
3109
3110         if (wcache == NULL) {
3111                 wcache = SMB_XMALLOC_P(struct winbind_cache);
3112                 ZERO_STRUCTP(wcache);
3113         }
3114
3115         if (wcache->tdb != NULL)
3116                 return true;
3117
3118         db_path = wcache_path();
3119         if (db_path == NULL) {
3120                 return false;
3121         }
3122
3123         /* when working offline we must not clear the cache on restart */
3124         wcache->tdb = tdb_open_log(db_path,
3125                                 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE, 
3126                                 TDB_INCOMPATIBLE_HASH |
3127                                         (lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
3128                                 O_RDWR|O_CREAT, 0600);
3129         TALLOC_FREE(db_path);
3130         if (wcache->tdb == NULL) {
3131                 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3132                 return false;
3133         }
3134
3135         return true;
3136 }
3137
3138 /************************************************************************
3139  This is called by the parent to initialize the cache file.
3140  We don't need sophisticated locking here as we know we're the
3141  only opener.
3142 ************************************************************************/
3143
3144 bool initialize_winbindd_cache(void)
3145 {
3146         bool cache_bad = true;
3147         uint32_t vers;
3148
3149         if (!init_wcache()) {
3150                 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3151                 return false;
3152         }
3153
3154         /* Check version number. */
3155         if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
3156                         vers == WINBINDD_CACHE_VERSION) {
3157                 cache_bad = false;
3158         }
3159
3160         if (cache_bad) {
3161                 char *db_path;
3162
3163                 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3164                         "and re-creating with version number %d\n",
3165                         WINBINDD_CACHE_VERSION ));
3166
3167                 tdb_close(wcache->tdb);
3168                 wcache->tdb = NULL;
3169
3170                 db_path = wcache_path();
3171                 if (db_path == NULL) {
3172                         return false;
3173                 }
3174
3175                 if (unlink(db_path) == -1) {
3176                         DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3177                                 db_path,
3178                                 strerror(errno) ));
3179                         TALLOC_FREE(db_path);
3180                         return false;
3181                 }
3182                 TALLOC_FREE(db_path);
3183                 if (!init_wcache()) {
3184                         DEBUG(0,("initialize_winbindd_cache: re-initialization "
3185                                         "init_wcache failed.\n"));
3186                         return false;
3187                 }
3188
3189                 /* Write the version. */
3190                 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
3191                         DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3192                                 tdb_errorstr(wcache->tdb) ));
3193                         return false;
3194                 }
3195         }
3196
3197         tdb_close(wcache->tdb);
3198         wcache->tdb = NULL;
3199         return true;
3200 }
3201
3202 void close_winbindd_cache(void)
3203 {
3204         if (!wcache) {
3205                 return;
3206         }
3207         if (wcache->tdb) {
3208                 tdb_close(wcache->tdb);
3209                 wcache->tdb = NULL;
3210         }
3211 }
3212
3213 bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
3214                        char **domain_name, char **name,
3215                        enum lsa_SidType *type)
3216 {
3217         struct winbindd_domain *domain;
3218         NTSTATUS status;
3219
3220         domain = find_lookup_domain_from_sid(sid);
3221         if (domain == NULL) {
3222                 return false;
3223         }
3224         status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
3225                                     type);
3226         return NT_STATUS_IS_OK(status);
3227 }
3228
3229 bool lookup_cached_name(const char *namespace,
3230                         const char *domain_name,
3231                         const char *name,
3232                         struct dom_sid *sid,
3233                         enum lsa_SidType *type)
3234 {
3235         struct winbindd_domain *domain;
3236         NTSTATUS status;
3237         bool original_online_state;
3238
3239         domain = find_lookup_domain_from_name(namespace);
3240         if (domain == NULL) {
3241                 return false;
3242         }
3243
3244         /* If we are doing a cached logon, temporarily set the domain
3245            offline so the cache won't expire the entry */
3246
3247         original_online_state = domain->online;
3248         domain->online = false;
3249         status = wcache_name_to_sid(domain, domain_name, name, sid, type);
3250         domain->online = original_online_state;
3251
3252         return NT_STATUS_IS_OK(status);
3253 }
3254
3255 /*
3256  * Cache a name to sid without checking the sequence number.
3257  * Used when caching from a trusted PAC.
3258  */
3259
3260 void cache_name2sid_trusted(struct winbindd_domain *domain,
3261                         const char *domain_name,
3262                         const char *name,
3263                         enum lsa_SidType type,
3264                         const struct dom_sid *sid)
3265 {
3266         /*
3267          * Ensure we store the mapping with the
3268          * existing sequence number from the cache.
3269          */
3270         get_cache(domain);
3271         (void)fetch_cache_seqnum(domain, time(NULL));
3272         wcache_save_name_to_sid(domain,
3273                                 NT_STATUS_OK,
3274                                 domain_name,
3275                                 name,
3276                                 sid,
3277                                 type);
3278 }
3279
3280 void cache_name2sid(struct winbindd_domain *domain, 
3281                     const char *domain_name, const char *name,
3282                     enum lsa_SidType type, const struct dom_sid *sid)
3283 {
3284         refresh_sequence_number(domain);
3285         wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
3286                                 sid, type);
3287 }
3288
3289 /*
3290  * The original idea that this cache only contains centries has
3291  * been blurred - now other stuff gets put in here. Ensure we
3292  * ignore these things on cleanup.
3293  */
3294
3295 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, 
3296                                TDB_DATA dbuf, void *state)
3297 {
3298         struct cache_entry *centry;
3299
3300         if (is_non_centry_key(kbuf)) {
3301                 return 0;
3302         }
3303
3304         centry = wcache_fetch_raw((char *)kbuf.dptr);
3305         if (!centry) {
3306                 return 0;
3307         }
3308
3309         if (!NT_STATUS_IS_OK(centry->status)) {
3310                 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
3311                 tdb_delete(the_tdb, kbuf);
3312         }
3313
3314         centry_free(centry);
3315         return 0;
3316 }
3317
3318 /* flush the cache */
3319 static void wcache_flush_cache(void)
3320 {
3321         char *db_path;
3322
3323         if (!wcache)
3324                 return;
3325         if (wcache->tdb) {
3326                 tdb_close(wcache->tdb);
3327                 wcache->tdb = NULL;
3328         }
3329         if (!winbindd_use_cache()) {
3330                 return;
3331         }
3332
3333         db_path = wcache_path();
3334         if (db_path == NULL) {
3335                 return;
3336         }
3337
3338         /* when working offline we must not clear the cache on restart */
3339         wcache->tdb = tdb_open_log(db_path,
3340                                 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3341                                 TDB_INCOMPATIBLE_HASH |
3342                                 (lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
3343                                 O_RDWR|O_CREAT, 0600);
3344         TALLOC_FREE(db_path);
3345         if (!wcache->tdb) {
3346                 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3347                 return;
3348         }
3349
3350         tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
3351
3352         DEBUG(10,("wcache_flush_cache success\n"));
3353 }
3354
3355 /* Count cached creds */
3356
3357 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, 
3358                                     void *state)
3359 {
3360         int *cred_count = (int*)state;
3361  
3362         if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3363                 (*cred_count)++;
3364         }
3365         return 0;
3366 }
3367
3368 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
3369 {
3370         struct winbind_cache *cache = get_cache(domain);
3371
3372         *count = 0;
3373
3374         if (!cache->tdb) {
3375                 return NT_STATUS_INTERNAL_DB_ERROR;
3376         }
3377  
3378         tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
3379
3380         return NT_STATUS_OK;
3381 }
3382
3383 struct cred_list {
3384         struct cred_list *prev, *next;
3385         TDB_DATA key;
3386         fstring name;
3387         time_t created;
3388 };
3389 static struct cred_list *wcache_cred_list;
3390
3391 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, 
3392                                     void *state)
3393 {
3394         struct cred_list *cred;
3395
3396         if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3397
3398                 cred = SMB_MALLOC_P(struct cred_list);
3399                 if (cred == NULL) {
3400                         DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3401                         return -1;
3402                 }
3403
3404                 ZERO_STRUCTP(cred);
3405
3406                 /* save a copy of the key */
3407
3408                 fstrcpy(cred->name, (const char *)kbuf.dptr);           
3409                 DLIST_ADD(wcache_cred_list, cred);
3410         }
3411
3412         return 0;
3413 }
3414
3415 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const struct dom_sid *sid)
3416 {
3417         struct winbind_cache *cache = get_cache(domain);
3418         NTSTATUS status;
3419         int ret;
3420         struct cred_list *cred, *next, *oldest = NULL;
3421
3422         if (!cache->tdb) {
3423                 return NT_STATUS_INTERNAL_DB_ERROR;
3424         }
3425
3426         /* we possibly already have an entry */
3427         if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
3428
3429                 fstring key_str;
3430                 struct dom_sid_buf tmp;
3431
3432                 DEBUG(11,("we already have an entry, deleting that\n"));
3433
3434                 fstr_sprintf(key_str, "CRED/%s", dom_sid_str_buf(sid, &tmp));
3435
3436                 tdb_delete(cache->tdb, string_tdb_data(key_str));
3437
3438                 return NT_STATUS_OK;
3439         }
3440
3441         ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
3442         if (ret == 0) {
3443                 return NT_STATUS_OK;
3444         } else if ((ret < 0) || (wcache_cred_list == NULL)) {
3445                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3446         }
3447
3448         ZERO_STRUCTP(oldest);
3449
3450         for (cred = wcache_cred_list; cred; cred = cred->next) {
3451
3452                 TDB_DATA data;
3453                 time_t t;
3454
3455                 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
3456                 if (!data.dptr) {
3457                         DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n", 
3458                                 cred->name));
3459                         status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
3460                         goto done;
3461                 }
3462
3463                 t = IVAL(data.dptr, 0);
3464                 SAFE_FREE(data.dptr);
3465
3466                 if (!oldest) {
3467                         oldest = SMB_MALLOC_P(struct cred_list);
3468                         if (oldest == NULL) {
3469                                 status = NT_STATUS_NO_MEMORY;
3470                                 goto done;
3471                         }
3472
3473                         fstrcpy(oldest->name, cred->name);
3474                         oldest->created = t;
3475                         continue;
3476                 }
3477
3478                 if (t < oldest->created) {
3479                         fstrcpy(oldest->name, cred->name);
3480                         oldest->created = t;
3481                 }
3482         }
3483
3484         if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
3485                 status = NT_STATUS_OK;
3486         } else {
3487                 status = NT_STATUS_UNSUCCESSFUL;
3488         }
3489 done:
3490         for (cred = wcache_cred_list; cred; cred = next) {
3491                 next = cred->next;
3492                 DLIST_REMOVE(wcache_cred_list, cred);
3493                 SAFE_FREE(cred);
3494         }
3495         SAFE_FREE(oldest);
3496
3497         return status;
3498 }
3499
3500 /* Change the global online/offline state. */
3501 bool set_global_winbindd_state_offline(void)
3502 {
3503         TDB_DATA data;
3504
3505         DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3506
3507         /* Only go offline if someone has created
3508            the key "WINBINDD_OFFLINE" in the cache tdb. */
3509
3510         if (wcache == NULL || wcache->tdb == NULL) {
3511                 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3512                 return false;
3513         }
3514
3515         if (!lp_winbind_offline_logon()) {
3516                 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3517                 return false;
3518         }
3519
3520         if (global_winbindd_offline_state) {
3521                 /* Already offline. */
3522                 return true;
3523         }
3524
3525         data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
3526
3527         if (!data.dptr || data.dsize != 4) {
3528                 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3529                 SAFE_FREE(data.dptr);
3530                 return false;
3531         } else {
3532                 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3533                 global_winbindd_offline_state = true;
3534                 SAFE_FREE(data.dptr);
3535                 return true;
3536         }