source: vendor/current/source3/winbindd/winbindd_cache.c

Last change on this file was 989, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.7

File size: 123.0 KB
Line 
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
38#undef DBGC_CLASS
39#define DBGC_CLASS DBGC_WINBIND
40
41#define WINBINDD_CACHE_VER1 1 /* initial db version */
42#define WINBINDD_CACHE_VER2 2 /* second version with timeouts for NDR entries */
43
44#define WINBINDD_CACHE_VERSION WINBINDD_CACHE_VER2
45#define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
46
47extern struct winbindd_methods reconnect_methods;
48#ifdef HAVE_ADS
49extern struct winbindd_methods reconnect_ads_methods;
50#endif
51extern struct winbindd_methods builtin_passdb_methods;
52extern struct winbindd_methods sam_passdb_methods;
53
54/*
55 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
56 * Here are the list of entry types that are *not* stored
57 * as form struct cache_entry in the cache.
58 */
59
60static const char *non_centry_keys[] = {
61 "SEQNUM/",
62 "WINBINDD_OFFLINE",
63 WINBINDD_CACHE_VERSION_KEYSTR,
64 NULL
65};
66
67/************************************************************************
68 Is this key a non-centry type ?
69************************************************************************/
70
71static bool is_non_centry_key(TDB_DATA kbuf)
72{
73 int i;
74
75 if (kbuf.dptr == NULL || kbuf.dsize == 0) {
76 return false;
77 }
78 for (i = 0; non_centry_keys[i] != NULL; i++) {
79 size_t namelen = strlen(non_centry_keys[i]);
80 if (kbuf.dsize < namelen) {
81 continue;
82 }
83 if (strncmp(non_centry_keys[i], (const char *)kbuf.dptr, namelen) == 0) {
84 return true;
85 }
86 }
87 return false;
88}
89
90/* Global online/offline state - False when online. winbindd starts up online
91 and sets this to true if the first query fails and there's an entry in
92 the cache tdb telling us to stay offline. */
93
94static bool global_winbindd_offline_state;
95
96struct winbind_cache {
97 TDB_CONTEXT *tdb;
98};
99
100struct cache_entry {
101 NTSTATUS status;
102 uint32_t sequence_number;
103 uint64_t timeout;
104 uint8_t *data;
105 uint32_t len, ofs;
106};
107
108void (*smb_panic_fn)(const char *const why) = smb_panic;
109
110#define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
111
112static struct winbind_cache *wcache;
113
114/* get the winbind_cache structure */
115static struct winbind_cache *get_cache(struct winbindd_domain *domain)
116{
117 struct winbind_cache *ret = wcache;
118
119 /* We have to know what type of domain we are dealing with first. */
120
121 if (domain->internal) {
122 domain->backend = &builtin_passdb_methods;
123 }
124
125 if (dom_sid_equal(&domain->sid, &global_sid_Builtin)) {
126 domain->initialized = true;
127 }
128
129 if (strequal(domain->name, get_global_sam_name()) &&
130 sid_check_is_our_sam(&domain->sid)) {
131 domain->backend = &sam_passdb_methods;
132 }
133
134 if ( !domain->initialized ) {
135 /* We do not need a connection to an RW DC for cache operation */
136 init_dc_connection(domain, false);
137 }
138
139 /*
140 OK. listen up becasue I'm only going to say this once.
141 We have the following scenarios to consider
142 (a) trusted AD domains on a Samba DC,
143 (b) trusted AD domains and we are joined to a non-kerberos domain
144 (c) trusted AD domains and we are joined to a kerberos (AD) domain
145
146 For (a) we can always contact the trusted domain using krb5
147 since we have the domain trust account password
148
149 For (b) we can only use RPC since we have no way of
150 getting a krb5 ticket in our own domain
151
152 For (c) we can always use krb5 since we have a kerberos trust
153
154 --jerry
155 */
156
157 if (!domain->backend) {
158#ifdef HAVE_ADS
159 struct winbindd_domain *our_domain = domain;
160
161 /* find our domain first so we can figure out if we
162 are joined to a kerberized domain */
163
164 if ( !domain->primary )
165 our_domain = find_our_domain();
166
167 if ((our_domain->active_directory || IS_DC)
168 && domain->active_directory
169 && !lp_winbind_rpc_only()) {
170 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain->name));
171 domain->backend = &reconnect_ads_methods;
172 } else {
173#endif /* HAVE_ADS */
174 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain->name));
175 domain->backend = &reconnect_methods;
176#ifdef HAVE_ADS
177 }
178#endif /* HAVE_ADS */
179 }
180
181 if (ret)
182 return ret;
183
184 ret = SMB_XMALLOC_P(struct winbind_cache);
185 ZERO_STRUCTP(ret);
186
187 wcache = ret;
188 wcache_flush_cache();
189
190 return ret;
191}
192
193/*
194 free a centry structure
195*/
196static void centry_free(struct cache_entry *centry)
197{
198 if (!centry)
199 return;
200 SAFE_FREE(centry->data);
201 free(centry);
202}
203
204static bool centry_check_bytes(struct cache_entry *centry, size_t nbytes)
205{
206 if (centry->len - centry->ofs < nbytes) {
207 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
208 (unsigned int)nbytes,
209 centry->len - centry->ofs));
210 return false;
211 }
212 return true;
213}
214
215/*
216 pull a uint64_t from a cache entry
217*/
218static uint64_t centry_uint64_t(struct cache_entry *centry)
219{
220 uint64_t ret;
221
222 if (!centry_check_bytes(centry, 8)) {
223 smb_panic_fn("centry_uint64_t");
224 }
225 ret = BVAL(centry->data, centry->ofs);
226 centry->ofs += 8;
227 return ret;
228}
229
230/*
231 pull a uint32_t from a cache entry
232*/
233static uint32_t centry_uint32(struct cache_entry *centry)
234{
235 uint32_t ret;
236
237 if (!centry_check_bytes(centry, 4)) {
238 smb_panic_fn("centry_uint32");
239 }
240 ret = IVAL(centry->data, centry->ofs);
241 centry->ofs += 4;
242 return ret;
243}
244
245/*
246 pull a uint16_t from a cache entry
247*/
248static uint16_t centry_uint16(struct cache_entry *centry)
249{
250 uint16_t ret;
251 if (!centry_check_bytes(centry, 2)) {
252 smb_panic_fn("centry_uint16");
253 }
254 ret = SVAL(centry->data, centry->ofs);
255 centry->ofs += 2;
256 return ret;
257}
258
259/*
260 pull a uint8_t from a cache entry
261*/
262static uint8_t centry_uint8(struct cache_entry *centry)
263{
264 uint8_t ret;
265 if (!centry_check_bytes(centry, 1)) {
266 smb_panic_fn("centry_uint8");
267 }
268 ret = CVAL(centry->data, centry->ofs);
269 centry->ofs += 1;
270 return ret;
271}
272
273/*
274 pull a NTTIME from a cache entry
275*/
276static NTTIME centry_nttime(struct cache_entry *centry)
277{
278 NTTIME ret;
279 if (!centry_check_bytes(centry, 8)) {
280 smb_panic_fn("centry_nttime");
281 }
282 ret = IVAL(centry->data, centry->ofs);
283 centry->ofs += 4;
284 ret += (uint64_t)IVAL(centry->data, centry->ofs) << 32;
285 centry->ofs += 4;
286 return ret;
287}
288
289/*
290 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
291*/
292static time_t centry_time(struct cache_entry *centry)
293{
294 return (time_t)centry_nttime(centry);
295}
296
297/* pull a string from a cache entry, using the supplied
298 talloc context
299*/
300static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
301{
302 uint32_t len;
303 char *ret;
304
305 len = centry_uint8(centry);
306
307 if (len == 0xFF) {
308 /* a deliberate NULL string */
309 return NULL;
310 }
311
312 if (!centry_check_bytes(centry, (size_t)len)) {
313 smb_panic_fn("centry_string");
314 }
315
316 ret = talloc_array(mem_ctx, char, len+1);
317 if (!ret) {
318 smb_panic_fn("centry_string out of memory\n");
319 }
320 memcpy(ret,centry->data + centry->ofs, len);
321 ret[len] = 0;
322 centry->ofs += len;
323 return ret;
324}
325
326/* pull a hash16 from a cache entry, using the supplied
327 talloc context
328*/
329static char *centry_hash16(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
330{
331 uint32_t len;
332 char *ret;
333
334 len = centry_uint8(centry);
335
336 if (len != 16) {
337 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
338 len ));
339 return NULL;
340 }
341
342 if (!centry_check_bytes(centry, 16)) {
343 return NULL;
344 }
345
346 ret = talloc_array(mem_ctx, char, 16);
347 if (!ret) {
348 smb_panic_fn("centry_hash out of memory\n");
349 }
350 memcpy(ret,centry->data + centry->ofs, 16);
351 centry->ofs += 16;
352 return ret;
353}
354
355/* pull a sid from a cache entry, using the supplied
356 talloc context
357*/
358static bool centry_sid(struct cache_entry *centry, struct dom_sid *sid)
359{
360 char *sid_string;
361 bool ret;
362
363 sid_string = centry_string(centry, talloc_tos());
364 if (sid_string == NULL) {
365 return false;
366 }
367 ret = string_to_sid(sid, sid_string);
368 TALLOC_FREE(sid_string);
369 return ret;
370}
371
372
373/*
374 pull a NTSTATUS from a cache entry
375*/
376static NTSTATUS centry_ntstatus(struct cache_entry *centry)
377{
378 NTSTATUS status;
379
380 status = NT_STATUS(centry_uint32(centry));
381 return status;
382}
383
384
385/* the server is considered down if it can't give us a sequence number */
386static bool wcache_server_down(struct winbindd_domain *domain)
387{
388 bool ret;
389
390 if (!wcache->tdb)
391 return false;
392
393 ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
394
395 if (ret)
396 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
397 domain->name ));
398 return ret;
399}
400
401struct wcache_seqnum_state {
402 uint32_t *seqnum;
403 uint32_t *last_seq_check;
404};
405
406static int wcache_seqnum_parser(TDB_DATA key, TDB_DATA data,
407 void *private_data)
408{
409 struct wcache_seqnum_state *state = private_data;
410
411 if (data.dsize != 8) {
412 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
413 (int)data.dsize));
414 return -1;
415 }
416
417 *state->seqnum = IVAL(data.dptr, 0);
418 *state->last_seq_check = IVAL(data.dptr, 4);
419 return 0;
420}
421
422static bool wcache_fetch_seqnum(const char *domain_name, uint32_t *seqnum,
423 uint32_t *last_seq_check)
424{
425 struct wcache_seqnum_state state = {
426 .seqnum = seqnum, .last_seq_check = last_seq_check
427 };
428 size_t len = strlen(domain_name);
429 char keystr[len+8];
430 TDB_DATA key = { .dptr = (uint8_t *)keystr, .dsize = sizeof(keystr) };
431 int ret;
432
433 if (wcache->tdb == NULL) {
434 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
435 return false;
436 }
437
438 snprintf(keystr, sizeof(keystr), "SEQNUM/%s", domain_name);
439
440 ret = tdb_parse_record(wcache->tdb, key, wcache_seqnum_parser,
441 &state);
442 return (ret == 0);
443}
444
445static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
446{
447 uint32_t last_check, time_diff;
448
449 if (!wcache_fetch_seqnum(domain->name, &domain->sequence_number,
450 &last_check)) {
451 return NT_STATUS_UNSUCCESSFUL;
452 }
453 domain->last_seq_check = last_check;
454
455 /* have we expired? */
456
457 time_diff = now - domain->last_seq_check;
458 if ( time_diff > lp_winbind_cache_time() ) {
459 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
460 domain->name, domain->sequence_number,
461 (uint32_t)domain->last_seq_check));
462 return NT_STATUS_UNSUCCESSFUL;
463 }
464
465 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
466 domain->name, domain->sequence_number,
467 (uint32_t)domain->last_seq_check));
468
469 return NT_STATUS_OK;
470}
471
472bool wcache_store_seqnum(const char *domain_name, uint32_t seqnum,
473 time_t last_seq_check)
474{
475 size_t len = strlen(domain_name);
476 char keystr[len+8];
477 TDB_DATA key = { .dptr = (uint8_t *)keystr, .dsize = sizeof(keystr) };
478 uint8_t buf[8];
479 int ret;
480
481 if (wcache->tdb == NULL) {
482 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
483 return false;
484 }
485
486 snprintf(keystr, sizeof(keystr), "SEQNUM/%s", domain_name);
487
488 SIVAL(buf, 0, seqnum);
489 SIVAL(buf, 4, last_seq_check);
490
491 ret = tdb_store(wcache->tdb, key, make_tdb_data(buf, sizeof(buf)),
492 TDB_REPLACE);
493 if (ret != 0) {
494 DEBUG(10, ("tdb_store_bystring failed: %s\n",
495 tdb_errorstr(wcache->tdb)));
496 return false;
497 }
498
499 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
500 domain_name, seqnum, (unsigned)last_seq_check));
501
502 return true;
503}
504
505static bool store_cache_seqnum( struct winbindd_domain *domain )
506{
507 return wcache_store_seqnum(domain->name, domain->sequence_number,
508 domain->last_seq_check);
509}
510
511/*
512 refresh the domain sequence number on timeout.
513*/
514
515static void refresh_sequence_number(struct winbindd_domain *domain)
516{
517 NTSTATUS status;
518 unsigned time_diff;
519 time_t t = time(NULL);
520 unsigned cache_time = lp_winbind_cache_time();
521
522 if (is_domain_offline(domain)) {
523 return;
524 }
525
526 get_cache( domain );
527
528#if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
529 /* trying to reconnect is expensive, don't do it too often */
530 if (domain->sequence_number == DOM_SEQUENCE_NONE) {
531 cache_time *= 8;
532 }
533#endif
534
535 time_diff = t - domain->last_seq_check;
536
537 /* see if we have to refetch the domain sequence number */
538 if ((time_diff < cache_time) &&
539 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
540 NT_STATUS_IS_OK(domain->last_status)) {
541 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
542 goto done;
543 }
544
545 /* try to get the sequence number from the tdb cache first */
546 /* this will update the timestamp as well */
547
548 status = fetch_cache_seqnum( domain, t );
549 if (NT_STATUS_IS_OK(status) &&
550 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
551 NT_STATUS_IS_OK(domain->last_status)) {
552 goto done;
553 }
554
555 /* important! make sure that we know if this is a native
556 mode domain or not. And that we can contact it. */
557
558 if ( winbindd_can_contact_domain( domain ) ) {
559 status = domain->backend->sequence_number(domain,
560 &domain->sequence_number);
561 } else {
562 /* just use the current time */
563 status = NT_STATUS_OK;
564 domain->sequence_number = time(NULL);
565 }
566
567
568 /* the above call could have set our domain->backend to NULL when
569 * coming from offline to online mode, make sure to reinitialize the
570 * backend - Guenther */
571 get_cache( domain );
572
573 if (!NT_STATUS_IS_OK(status)) {
574 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status)));
575 domain->sequence_number = DOM_SEQUENCE_NONE;
576 }
577
578 domain->last_status = status;
579 domain->last_seq_check = time(NULL);
580
581 /* save the new sequence number in the cache */
582 store_cache_seqnum( domain );
583
584done:
585 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
586 domain->name, domain->sequence_number));
587
588 return;
589}
590
591/*
592 decide if a cache entry has expired
593*/
594static bool centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
595{
596 /* If we've been told to be offline - stay in that state... */
597 if (lp_winbind_offline_logon() && global_winbindd_offline_state) {
598 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
599 keystr, domain->name ));
600 return false;
601 }
602
603 /* when the domain is offline return the cached entry.
604 * This deals with transient offline states... */
605
606 if (!domain->online) {
607 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
608 keystr, domain->name ));
609 return false;
610 }
611
612 /* if the server is OK and our cache entry came from when it was down then
613 the entry is invalid */
614 if ((domain->sequence_number != DOM_SEQUENCE_NONE) &&
615 (centry->sequence_number == DOM_SEQUENCE_NONE)) {
616 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
617 keystr, domain->name ));
618 return true;
619 }
620
621 /* if the server is down or the cache entry is not older than the
622 current sequence number or it did not timeout then it is OK */
623 if (wcache_server_down(domain)
624 || ((centry->sequence_number == domain->sequence_number)
625 && (centry->timeout > time(NULL)))) {
626 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
627 keystr, domain->name ));
628 return false;
629 }
630
631 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
632 keystr, domain->name ));
633
634 /* it's expired */
635 return true;
636}
637
638static struct cache_entry *wcache_fetch_raw(char *kstr)
639{
640 TDB_DATA data;
641 struct cache_entry *centry;
642 TDB_DATA key;
643
644 key = string_tdb_data(kstr);
645 data = tdb_fetch(wcache->tdb, key);
646 if (!data.dptr) {
647 /* a cache miss */
648 return NULL;
649 }
650
651 centry = SMB_XMALLOC_P(struct cache_entry);
652 centry->data = (unsigned char *)data.dptr;
653 centry->len = data.dsize;
654 centry->ofs = 0;
655
656 if (centry->len < 16) {
657 /* huh? corrupt cache? */
658 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s "
659 "(len < 16)?\n", kstr));
660 centry_free(centry);
661 return NULL;
662 }
663
664 centry->status = centry_ntstatus(centry);
665 centry->sequence_number = centry_uint32(centry);
666 centry->timeout = centry_uint64_t(centry);
667
668 return centry;
669}
670
671static bool is_my_own_sam_domain(struct winbindd_domain *domain)
672{
673 if (strequal(domain->name, get_global_sam_name()) &&
674 sid_check_is_our_sam(&domain->sid)) {
675 return true;
676 }
677
678 return false;
679}
680
681static bool is_builtin_domain(struct winbindd_domain *domain)
682{
683 if (strequal(domain->name, "BUILTIN") &&
684 sid_check_is_builtin(&domain->sid)) {
685 return true;
686 }
687
688 return false;
689}
690
691/*
692 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
693 number and return status
694*/
695static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
696 struct winbindd_domain *domain,
697 const char *format, ...) PRINTF_ATTRIBUTE(3,4);
698static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
699 struct winbindd_domain *domain,
700 const char *format, ...)
701{
702 va_list ap;
703 char *kstr;
704 struct cache_entry *centry;
705
706 if (!winbindd_use_cache() ||
707 is_my_own_sam_domain(domain) ||
708 is_builtin_domain(domain)) {
709 return NULL;
710 }
711
712 refresh_sequence_number(domain);
713
714 va_start(ap, format);
715 smb_xvasprintf(&kstr, format, ap);
716 va_end(ap);
717
718 centry = wcache_fetch_raw(kstr);
719 if (centry == NULL) {
720 free(kstr);
721 return NULL;
722 }
723
724 if (centry_expired(domain, kstr, centry)) {
725
726 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
727 kstr, domain->name ));
728
729 centry_free(centry);
730 free(kstr);
731 return NULL;
732 }
733
734 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
735 kstr, domain->name ));
736
737 free(kstr);
738 return centry;
739}
740
741static void wcache_delete(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
742static void wcache_delete(const char *format, ...)
743{
744 va_list ap;
745 char *kstr;
746 TDB_DATA key;
747
748 va_start(ap, format);
749 smb_xvasprintf(&kstr, format, ap);
750 va_end(ap);
751
752 key = string_tdb_data(kstr);
753
754 tdb_delete(wcache->tdb, key);
755 free(kstr);
756}
757
758/*
759 make sure we have at least len bytes available in a centry
760*/
761static void centry_expand(struct cache_entry *centry, uint32_t len)
762{
763 if (centry->len - centry->ofs >= len)
764 return;
765 centry->len *= 2;
766 centry->data = SMB_REALLOC_ARRAY(centry->data, unsigned char,
767 centry->len);
768 if (!centry->data) {
769 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
770 smb_panic_fn("out of memory in centry_expand");
771 }
772}
773
774/*
775 push a uint64_t into a centry
776*/
777static void centry_put_uint64_t(struct cache_entry *centry, uint64_t v)
778{
779 centry_expand(centry, 8);
780 SBVAL(centry->data, centry->ofs, v);
781 centry->ofs += 8;
782}
783
784/*
785 push a uint32_t into a centry
786*/
787static void centry_put_uint32(struct cache_entry *centry, uint32_t v)
788{
789 centry_expand(centry, 4);
790 SIVAL(centry->data, centry->ofs, v);
791 centry->ofs += 4;
792}
793
794/*
795 push a uint16_t into a centry
796*/
797static void centry_put_uint16(struct cache_entry *centry, uint16_t v)
798{
799 centry_expand(centry, 2);
800 SSVAL(centry->data, centry->ofs, v);
801 centry->ofs += 2;
802}
803
804/*
805 push a uint8_t into a centry
806*/
807static void centry_put_uint8(struct cache_entry *centry, uint8_t v)
808{
809 centry_expand(centry, 1);
810 SCVAL(centry->data, centry->ofs, v);
811 centry->ofs += 1;
812}
813
814/*
815 push a string into a centry
816 */
817static void centry_put_string(struct cache_entry *centry, const char *s)
818{
819 int len;
820
821 if (!s) {
822 /* null strings are marked as len 0xFFFF */
823 centry_put_uint8(centry, 0xFF);
824 return;
825 }
826
827 len = strlen(s);
828 /* can't handle more than 254 char strings. Truncating is probably best */
829 if (len > 254) {
830 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len));
831 len = 254;
832 }
833 centry_put_uint8(centry, len);
834 centry_expand(centry, len);
835 memcpy(centry->data + centry->ofs, s, len);
836 centry->ofs += len;
837}
838
839/*
840 push a 16 byte hash into a centry - treat as 16 byte string.
841 */
842static void centry_put_hash16(struct cache_entry *centry, const uint8_t val[16])
843{
844 centry_put_uint8(centry, 16);
845 centry_expand(centry, 16);
846 memcpy(centry->data + centry->ofs, val, 16);
847 centry->ofs += 16;
848}
849
850static void centry_put_sid(struct cache_entry *centry, const struct dom_sid *sid)
851{
852 fstring sid_string;
853 centry_put_string(centry, sid_to_fstring(sid_string, sid));
854}
855
856
857/*
858 put NTSTATUS into a centry
859*/
860static void centry_put_ntstatus(struct cache_entry *centry, NTSTATUS status)
861{
862 uint32_t status_value = NT_STATUS_V(status);
863 centry_put_uint32(centry, status_value);
864}
865
866
867/*
868 push a NTTIME into a centry
869*/
870static void centry_put_nttime(struct cache_entry *centry, NTTIME nt)
871{
872 centry_expand(centry, 8);
873 SIVAL(centry->data, centry->ofs, nt & 0xFFFFFFFF);
874 centry->ofs += 4;
875 SIVAL(centry->data, centry->ofs, nt >> 32);
876 centry->ofs += 4;
877}
878
879/*
880 push a time_t into a centry - use a 64 bit size.
881 NTTIME here is being used as a convenient 64-bit size.
882*/
883static void centry_put_time(struct cache_entry *centry, time_t t)
884{
885 NTTIME nt = (NTTIME)t;
886 centry_put_nttime(centry, nt);
887}
888
889/*
890 start a centry for output. When finished, call centry_end()
891*/
892static struct cache_entry *centry_start(struct winbindd_domain *domain,
893 NTSTATUS status)
894{
895 struct cache_entry *centry;
896
897 if (!wcache->tdb)
898 return NULL;
899
900 centry = SMB_XMALLOC_P(struct cache_entry);
901
902 centry->len = 8192; /* reasonable default */
903 centry->data = SMB_XMALLOC_ARRAY(uint8_t, centry->len);
904 centry->ofs = 0;
905 centry->sequence_number = domain->sequence_number;
906 centry->timeout = lp_winbind_cache_time() + time(NULL);
907 centry_put_ntstatus(centry, status);
908 centry_put_uint32(centry, centry->sequence_number);
909 centry_put_uint64_t(centry, centry->timeout);
910 return centry;
911}
912
913/*
914 finish a centry and write it to the tdb
915*/
916static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
917static void centry_end(struct cache_entry *centry, const char *format, ...)
918{
919 va_list ap;
920 char *kstr;
921 TDB_DATA key, data;
922
923 if (!winbindd_use_cache()) {
924 return;
925 }
926
927 va_start(ap, format);
928 smb_xvasprintf(&kstr, format, ap);
929 va_end(ap);
930
931 key = string_tdb_data(kstr);
932 data.dptr = centry->data;
933 data.dsize = centry->ofs;
934
935 tdb_store(wcache->tdb, key, data, TDB_REPLACE);
936 free(kstr);
937}
938
939static void wcache_save_name_to_sid(struct winbindd_domain *domain,
940 NTSTATUS status, const char *domain_name,
941 const char *name, const struct dom_sid *sid,
942 enum lsa_SidType type)
943{
944 struct cache_entry *centry;
945 fstring uname;
946
947 centry = centry_start(domain, status);
948 if (!centry)
949 return;
950
951 if ((domain_name == NULL) || (domain_name[0] == '\0')) {
952 struct winbindd_domain *mydomain =
953 find_domain_from_sid_noinit(sid);
954 if (mydomain != NULL) {
955 domain_name = mydomain->name;
956 }
957 }
958
959 centry_put_uint32(centry, type);
960 centry_put_sid(centry, sid);
961 fstrcpy(uname, name);
962 (void)strupper_m(uname);
963 centry_end(centry, "NS/%s/%s", domain_name, uname);
964 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name,
965 uname, sid_string_dbg(sid), nt_errstr(status)));
966 centry_free(centry);
967}
968
969static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
970 const struct dom_sid *sid, const char *domain_name, const char *name, enum lsa_SidType type)
971{
972 struct cache_entry *centry;
973 fstring sid_string;
974
975 centry = centry_start(domain, status);
976 if (!centry)
977 return;
978
979 if ((domain_name == NULL) || (domain_name[0] == '\0')) {
980 struct winbindd_domain *mydomain =
981 find_domain_from_sid_noinit(sid);
982 if (mydomain != NULL) {
983 domain_name = mydomain->name;
984 }
985 }
986
987 if (NT_STATUS_IS_OK(status)) {
988 centry_put_uint32(centry, type);
989 centry_put_string(centry, domain_name);
990 centry_put_string(centry, name);
991 }
992
993 centry_end(centry, "SN/%s", sid_to_fstring(sid_string, sid));
994 DEBUG(10,("wcache_save_sid_to_name: %s -> %s\\%s (%s)\n", sid_string,
995 domain_name, name, nt_errstr(status)));
996 centry_free(centry);
997}
998
999
1000static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status,
1001 struct wbint_userinfo *info)
1002{
1003 struct cache_entry *centry;
1004 fstring sid_string;
1005
1006 if (is_null_sid(&info->user_sid)) {
1007 return;
1008 }
1009
1010 centry = centry_start(domain, status);
1011 if (!centry)
1012 return;
1013 centry_put_string(centry, info->acct_name);
1014 centry_put_string(centry, info->full_name);
1015 centry_put_string(centry, info->homedir);
1016 centry_put_string(centry, info->shell);
1017 centry_put_uint32(centry, info->primary_gid);
1018 centry_put_sid(centry, &info->user_sid);
1019 centry_put_sid(centry, &info->group_sid);
1020 centry_end(centry, "U/%s", sid_to_fstring(sid_string,
1021 &info->user_sid));
1022 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
1023 centry_free(centry);
1024}
1025
1026static void wcache_save_lockout_policy(struct winbindd_domain *domain,
1027 NTSTATUS status,
1028 struct samr_DomInfo12 *lockout_policy)
1029{
1030 struct cache_entry *centry;
1031
1032 centry = centry_start(domain, status);
1033 if (!centry)
1034 return;
1035
1036 centry_put_nttime(centry, lockout_policy->lockout_duration);
1037 centry_put_nttime(centry, lockout_policy->lockout_window);
1038 centry_put_uint16(centry, lockout_policy->lockout_threshold);
1039
1040 centry_end(centry, "LOC_POL/%s", domain->name);
1041
1042 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
1043
1044 centry_free(centry);
1045}
1046
1047
1048
1049static void wcache_save_password_policy(struct winbindd_domain *domain,
1050 NTSTATUS status,
1051 struct samr_DomInfo1 *policy)
1052{
1053 struct cache_entry *centry;
1054
1055 centry = centry_start(domain, status);
1056 if (!centry)
1057 return;
1058
1059 centry_put_uint16(centry, policy->min_password_length);
1060 centry_put_uint16(centry, policy->password_history_length);
1061 centry_put_uint32(centry, policy->password_properties);
1062 centry_put_nttime(centry, policy->max_password_age);
1063 centry_put_nttime(centry, policy->min_password_age);
1064
1065 centry_end(centry, "PWD_POL/%s", domain->name);
1066
1067 DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
1068
1069 centry_free(centry);
1070}
1071
1072/***************************************************************************
1073 ***************************************************************************/
1074
1075static void wcache_save_username_alias(struct winbindd_domain *domain,
1076 NTSTATUS status,
1077 const char *name, const char *alias)
1078{
1079 struct cache_entry *centry;
1080 fstring uname;
1081
1082 if ( (centry = centry_start(domain, status)) == NULL )
1083 return;
1084
1085 centry_put_string( centry, alias );
1086
1087 fstrcpy(uname, name);
1088 (void)strupper_m(uname);
1089 centry_end(centry, "NSS/NA/%s", uname);
1090
1091 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name, alias ));
1092
1093 centry_free(centry);
1094}
1095
1096static void wcache_save_alias_username(struct winbindd_domain *domain,
1097 NTSTATUS status,
1098 const char *alias, const char *name)
1099{
1100 struct cache_entry *centry;
1101 fstring uname;
1102
1103 if ( (centry = centry_start(domain, status)) == NULL )
1104 return;
1105
1106 centry_put_string( centry, name );
1107
1108 fstrcpy(uname, alias);
1109 (void)strupper_m(uname);
1110 centry_end(centry, "NSS/AN/%s", uname);
1111
1112 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias, name ));
1113
1114 centry_free(centry);
1115}
1116
1117/***************************************************************************
1118 ***************************************************************************/
1119
1120NTSTATUS resolve_username_to_alias( TALLOC_CTX *mem_ctx,
1121 struct winbindd_domain *domain,
1122 const char *name, char **alias )
1123{
1124 struct winbind_cache *cache = get_cache(domain);
1125 struct cache_entry *centry = NULL;
1126 NTSTATUS status;
1127 char *upper_name;
1128
1129 if ( domain->internal )
1130 return NT_STATUS_NOT_SUPPORTED;
1131
1132 if (!cache->tdb)
1133 goto do_query;
1134
1135 upper_name = talloc_strdup(mem_ctx, name);
1136 if (upper_name == NULL) {
1137 return NT_STATUS_NO_MEMORY;
1138 }
1139 if (!strupper_m(upper_name)) {
1140 talloc_free(upper_name);
1141 return NT_STATUS_INVALID_PARAMETER;
1142 }
1143
1144 centry = wcache_fetch(cache, domain, "NSS/NA/%s", upper_name);
1145
1146 talloc_free(upper_name);
1147
1148 if (!centry)
1149 goto do_query;
1150
1151 status = centry->status;
1152
1153 if (!NT_STATUS_IS_OK(status)) {
1154 centry_free(centry);
1155 return status;
1156 }
1157
1158 *alias = centry_string( centry, mem_ctx );
1159
1160 centry_free(centry);
1161
1162 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1163 name, *alias ? *alias : "(none)"));
1164
1165 return (*alias) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1166
1167do_query:
1168
1169 /* If its not in cache and we are offline, then fail */
1170
1171 if ( get_global_winbindd_state_offline() || !domain->online ) {
1172 DEBUG(8,("resolve_username_to_alias: rejecting query "
1173 "in offline mode\n"));
1174 return NT_STATUS_NOT_FOUND;
1175 }
1176
1177 status = nss_map_to_alias( mem_ctx, domain->name, name, alias );
1178
1179 if ( NT_STATUS_IS_OK( status ) ) {
1180 wcache_save_username_alias(domain, status, name, *alias);
1181 }
1182
1183 if ( NT_STATUS_EQUAL( status, NT_STATUS_NONE_MAPPED ) ) {
1184 wcache_save_username_alias(domain, status, name, "(NULL)");
1185 }
1186
1187 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1188 nt_errstr(status)));
1189
1190 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1191 set_domain_offline( domain );
1192 }
1193
1194 return status;
1195}
1196
1197/***************************************************************************
1198 ***************************************************************************/
1199
1200NTSTATUS resolve_alias_to_username( TALLOC_CTX *mem_ctx,
1201 struct winbindd_domain *domain,
1202 const char *alias, char **name )
1203{
1204 struct winbind_cache *cache = get_cache(domain);
1205 struct cache_entry *centry = NULL;
1206 NTSTATUS status;
1207 char *upper_name;
1208
1209 if ( domain->internal )
1210 return NT_STATUS_NOT_SUPPORTED;
1211
1212 if (!cache->tdb)
1213 goto do_query;
1214
1215 upper_name = talloc_strdup(mem_ctx, alias);
1216 if (upper_name == NULL) {
1217 return NT_STATUS_NO_MEMORY;
1218 }
1219 if (!strupper_m(upper_name)) {
1220 talloc_free(upper_name);
1221 return NT_STATUS_INVALID_PARAMETER;
1222 }
1223
1224 centry = wcache_fetch(cache, domain, "NSS/AN/%s", upper_name);
1225
1226 talloc_free(upper_name);
1227
1228 if (!centry)
1229 goto do_query;
1230
1231 status = centry->status;
1232
1233 if (!NT_STATUS_IS_OK(status)) {
1234 centry_free(centry);
1235 return status;
1236 }
1237
1238 *name = centry_string( centry, mem_ctx );
1239
1240 centry_free(centry);
1241
1242 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1243 alias, *name ? *name : "(none)"));
1244
1245 return (*name) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1246
1247do_query:
1248
1249 /* If its not in cache and we are offline, then fail */
1250
1251 if ( get_global_winbindd_state_offline() || !domain->online ) {
1252 DEBUG(8,("resolve_alias_to_username: rejecting query "
1253 "in offline mode\n"));
1254 return NT_STATUS_NOT_FOUND;
1255 }
1256
1257 /* an alias cannot contain a domain prefix or '@' */
1258
1259 if (strchr(alias, '\\') || strchr(alias, '@')) {
1260 DEBUG(10,("resolve_alias_to_username: skipping fully "
1261 "qualified name %s\n", alias));
1262 return NT_STATUS_OBJECT_NAME_INVALID;
1263 }
1264
1265 status = nss_map_from_alias( mem_ctx, domain->name, alias, name );
1266
1267 if ( NT_STATUS_IS_OK( status ) ) {
1268 wcache_save_alias_username( domain, status, alias, *name );
1269 }
1270
1271 if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1272 wcache_save_alias_username(domain, status, alias, "(NULL)");
1273 }
1274
1275 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1276 nt_errstr(status)));
1277
1278 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1279 set_domain_offline( domain );
1280 }
1281
1282 return status;
1283}
1284
1285NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const struct dom_sid *sid)
1286{
1287 struct winbind_cache *cache = get_cache(domain);
1288 TDB_DATA data;
1289 fstring key_str, tmp;
1290 uint32_t rid;
1291
1292 if (!cache->tdb) {
1293 return NT_STATUS_INTERNAL_DB_ERROR;
1294 }
1295
1296 if (is_null_sid(sid)) {
1297 return NT_STATUS_INVALID_SID;
1298 }
1299
1300 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1301 return NT_STATUS_INVALID_SID;
1302 }
1303
1304 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
1305
1306 data = tdb_fetch(cache->tdb, string_tdb_data(key_str));
1307 if (!data.dptr) {
1308 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1309 }
1310
1311 SAFE_FREE(data.dptr);
1312 return NT_STATUS_OK;
1313}
1314
1315/* Lookup creds for a SID - copes with old (unsalted) creds as well
1316 as new salted ones. */
1317
1318NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
1319 TALLOC_CTX *mem_ctx,
1320 const struct dom_sid *sid,
1321 const uint8_t **cached_nt_pass,
1322 const uint8_t **cached_salt)
1323{
1324 struct winbind_cache *cache = get_cache(domain);
1325 struct cache_entry *centry = NULL;
1326 NTSTATUS status;
1327 uint32_t rid;
1328 fstring tmp;
1329
1330 if (!cache->tdb) {
1331 return NT_STATUS_INTERNAL_DB_ERROR;
1332 }
1333
1334 if (is_null_sid(sid)) {
1335 return NT_STATUS_INVALID_SID;
1336 }
1337
1338 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1339 return NT_STATUS_INVALID_SID;
1340 }
1341
1342 /* Try and get a salted cred first. If we can't
1343 fall back to an unsalted cred. */
1344
1345 centry = wcache_fetch(cache, domain, "CRED/%s",
1346 sid_to_fstring(tmp, sid));
1347 if (!centry) {
1348 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1349 sid_string_dbg(sid)));
1350 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1351 }
1352
1353 /*
1354 * We don't use the time element at this moment,
1355 * but we have to consume it, so that we don't
1356 * neet to change the disk format of the cache.
1357 */
1358 (void)centry_time(centry);
1359
1360 /* In the salted case this isn't actually the nt_hash itself,
1361 but the MD5 of the salt + nt_hash. Let the caller
1362 sort this out. It can tell as we only return the cached_salt
1363 if we are returning a salted cred. */
1364
1365 *cached_nt_pass = (const uint8_t *)centry_hash16(centry, mem_ctx);
1366 if (*cached_nt_pass == NULL) {
1367 fstring sidstr;
1368
1369 sid_to_fstring(sidstr, sid);
1370
1371 /* Bad (old) cred cache. Delete and pretend we
1372 don't have it. */
1373 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1374 sidstr));
1375 wcache_delete("CRED/%s", sidstr);
1376 centry_free(centry);
1377 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1378 }
1379
1380 /* We only have 17 bytes more data in the salted cred case. */
1381 if (centry->len - centry->ofs == 17) {
1382 *cached_salt = (const uint8_t *)centry_hash16(centry, mem_ctx);
1383 } else {
1384 *cached_salt = NULL;
1385 }
1386
1387 dump_data_pw("cached_nt_pass", *cached_nt_pass, NT_HASH_LEN);
1388 if (*cached_salt) {
1389 dump_data_pw("cached_salt", *cached_salt, NT_HASH_LEN);
1390 }
1391
1392 status = centry->status;
1393
1394 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1395 sid_string_dbg(sid), nt_errstr(status) ));
1396
1397 centry_free(centry);
1398 return status;
1399}
1400
1401/* Store creds for a SID - only writes out new salted ones. */
1402
1403NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
1404 const struct dom_sid *sid,
1405 const uint8_t nt_pass[NT_HASH_LEN])
1406{
1407 struct cache_entry *centry;
1408 fstring sid_string;
1409 uint32_t rid;
1410 uint8_t cred_salt[NT_HASH_LEN];
1411 uint8_t salted_hash[NT_HASH_LEN];
1412
1413 if (is_null_sid(sid)) {
1414 return NT_STATUS_INVALID_SID;
1415 }
1416
1417 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1418 return NT_STATUS_INVALID_SID;
1419 }
1420
1421 centry = centry_start(domain, NT_STATUS_OK);
1422 if (!centry) {
1423 return NT_STATUS_INTERNAL_DB_ERROR;
1424 }
1425
1426 dump_data_pw("nt_pass", nt_pass, NT_HASH_LEN);
1427
1428 centry_put_time(centry, time(NULL));
1429
1430 /* Create a salt and then salt the hash. */
1431 generate_random_buffer(cred_salt, NT_HASH_LEN);
1432 E_md5hash(cred_salt, nt_pass, salted_hash);
1433
1434 centry_put_hash16(centry, salted_hash);
1435 centry_put_hash16(centry, cred_salt);
1436 centry_end(centry, "CRED/%s", sid_to_fstring(sid_string, sid));
1437
1438 DEBUG(10,("wcache_save_creds: %s\n", sid_string));
1439
1440 centry_free(centry);
1441
1442 return NT_STATUS_OK;
1443}
1444
1445
1446/* Query display info. This is the basic user list fn */
1447static NTSTATUS query_user_list(struct winbindd_domain *domain,
1448 TALLOC_CTX *mem_ctx,
1449 uint32_t *num_entries,
1450 struct wbint_userinfo **info)
1451{
1452 struct winbind_cache *cache = get_cache(domain);
1453 struct cache_entry *centry = NULL;
1454 NTSTATUS status;
1455 unsigned int i, retry;
1456 bool old_status = domain->online;
1457
1458 if (!cache->tdb)
1459 goto do_query;
1460
1461 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1462 if (!centry)
1463 goto do_query;
1464
1465do_fetch_cache:
1466 *num_entries = centry_uint32(centry);
1467
1468 if (*num_entries == 0)
1469 goto do_cached;
1470
1471 (*info) = talloc_array(mem_ctx, struct wbint_userinfo, *num_entries);
1472 if (! (*info)) {
1473 smb_panic_fn("query_user_list out of memory");
1474 }
1475 for (i=0; i<(*num_entries); i++) {
1476 (*info)[i].acct_name = centry_string(centry, mem_ctx);
1477 (*info)[i].full_name = centry_string(centry, mem_ctx);
1478 (*info)[i].homedir = centry_string(centry, mem_ctx);
1479 (*info)[i].shell = centry_string(centry, mem_ctx);
1480 centry_sid(centry, &(*info)[i].user_sid);
1481 centry_sid(centry, &(*info)[i].group_sid);
1482 }
1483
1484do_cached:
1485 status = centry->status;
1486
1487 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1488 domain->name, nt_errstr(status) ));
1489
1490 centry_free(centry);
1491 return status;
1492
1493do_query:
1494 *num_entries = 0;
1495 *info = NULL;
1496
1497 /* Return status value returned by seq number check */
1498
1499 if (!NT_STATUS_IS_OK(domain->last_status))
1500 return domain->last_status;
1501
1502 /* Put the query_user_list() in a retry loop. There appears to be
1503 * some bug either with Windows 2000 or Samba's handling of large
1504 * rpc replies. This manifests itself as sudden disconnection
1505 * at a random point in the enumeration of a large (60k) user list.
1506 * The retry loop simply tries the operation again. )-: It's not
1507 * pretty but an acceptable workaround until we work out what the
1508 * real problem is. */
1509
1510 retry = 0;
1511 do {
1512
1513 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1514 domain->name ));
1515
1516 status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
1517 if (!NT_STATUS_IS_OK(status)) {
1518 DEBUG(3, ("query_user_list: returned 0x%08x, "
1519 "retrying\n", NT_STATUS_V(status)));
1520 }
1521 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1522 DEBUG(3, ("query_user_list: flushing "
1523 "connection cache\n"));
1524 invalidate_cm_connection(domain);
1525 }
1526 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1527 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1528 if (!domain->internal && old_status) {
1529 set_domain_offline(domain);
1530 }
1531 /* store partial response. */
1532 if (*num_entries > 0) {
1533 /*
1534 * humm, what about the status used for cache?
1535 * Should it be NT_STATUS_OK?
1536 */
1537 break;
1538 }
1539 /*
1540 * domain is offline now, and there is no user entries,
1541 * try to fetch from cache again.
1542 */
1543 if (cache->tdb && !domain->online && !domain->internal && old_status) {
1544 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1545 /* partial response... */
1546 if (!centry) {
1547 goto skip_save;
1548 } else {
1549 goto do_fetch_cache;
1550 }
1551 } else {
1552 goto skip_save;
1553 }
1554 }
1555
1556 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
1557 (retry++ < 5));
1558
1559 /* and save it */
1560 refresh_sequence_number(domain);
1561 if (!NT_STATUS_IS_OK(status)) {
1562 return status;
1563 }
1564 centry = centry_start(domain, status);
1565 if (!centry)
1566 goto skip_save;
1567 centry_put_uint32(centry, *num_entries);
1568 for (i=0; i<(*num_entries); i++) {
1569 centry_put_string(centry, (*info)[i].acct_name);
1570 centry_put_string(centry, (*info)[i].full_name);
1571 centry_put_string(centry, (*info)[i].homedir);
1572 centry_put_string(centry, (*info)[i].shell);
1573 centry_put_sid(centry, &(*info)[i].user_sid);
1574 centry_put_sid(centry, &(*info)[i].group_sid);
1575 if (domain->backend && domain->backend->consistent) {
1576 /* when the backend is consistent we can pre-prime some mappings */
1577 wcache_save_name_to_sid(domain, NT_STATUS_OK,
1578 domain->name,
1579 (*info)[i].acct_name,
1580 &(*info)[i].user_sid,
1581 SID_NAME_USER);
1582 wcache_save_sid_to_name(domain, NT_STATUS_OK,
1583 &(*info)[i].user_sid,
1584 domain->name,
1585 (*info)[i].acct_name,
1586 SID_NAME_USER);
1587 wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
1588 }
1589 }
1590 centry_end(centry, "UL/%s", domain->name);
1591 centry_free(centry);
1592
1593skip_save:
1594 return status;
1595}
1596
1597/* list all domain groups */
1598static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
1599 TALLOC_CTX *mem_ctx,
1600 uint32_t *num_entries,
1601 struct wb_acct_info **info)
1602{
1603 struct winbind_cache *cache = get_cache(domain);
1604 struct cache_entry *centry = NULL;
1605 NTSTATUS status;
1606 unsigned int i;
1607 bool old_status;
1608
1609 old_status = domain->online;
1610 if (!cache->tdb)
1611 goto do_query;
1612
1613 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1614 if (!centry)
1615 goto do_query;
1616
1617do_fetch_cache:
1618 *num_entries = centry_uint32(centry);
1619
1620 if (*num_entries == 0)
1621 goto do_cached;
1622
1623 (*info) = talloc_array(mem_ctx, struct wb_acct_info, *num_entries);
1624 if (! (*info)) {
1625 smb_panic_fn("enum_dom_groups out of memory");
1626 }
1627 for (i=0; i<(*num_entries); i++) {
1628 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1629 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1630 (*info)[i].rid = centry_uint32(centry);
1631 }
1632
1633do_cached:
1634 status = centry->status;
1635
1636 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1637 domain->name, nt_errstr(status) ));
1638
1639 centry_free(centry);
1640 return status;
1641
1642do_query:
1643 *num_entries = 0;
1644 *info = NULL;
1645
1646 /* Return status value returned by seq number check */
1647
1648 if (!NT_STATUS_IS_OK(domain->last_status))
1649 return domain->last_status;
1650
1651 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1652 domain->name ));
1653
1654 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1655
1656 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1657 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1658 if (!domain->internal && old_status) {
1659 set_domain_offline(domain);
1660 }
1661 if (cache->tdb &&
1662 !domain->online &&
1663 !domain->internal &&
1664 old_status) {
1665 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1666 if (centry) {
1667 goto do_fetch_cache;
1668 }
1669 }
1670 }
1671 /* and save it */
1672 refresh_sequence_number(domain);
1673 if (!NT_STATUS_IS_OK(status)) {
1674 return status;
1675 }
1676 centry = centry_start(domain, status);
1677 if (!centry)
1678 goto skip_save;
1679 centry_put_uint32(centry, *num_entries);
1680 for (i=0; i<(*num_entries); i++) {
1681 centry_put_string(centry, (*info)[i].acct_name);
1682 centry_put_string(centry, (*info)[i].acct_desc);
1683 centry_put_uint32(centry, (*info)[i].rid);
1684 }
1685 centry_end(centry, "GL/%s/domain", domain->name);
1686 centry_free(centry);
1687
1688skip_save:
1689 return status;
1690}
1691
1692/* list all domain groups */
1693static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
1694 TALLOC_CTX *mem_ctx,
1695 uint32_t *num_entries,
1696 struct wb_acct_info **info)
1697{
1698 struct winbind_cache *cache = get_cache(domain);
1699 struct cache_entry *centry = NULL;
1700 NTSTATUS status;
1701 unsigned int i;
1702 bool old_status;
1703
1704 old_status = domain->online;
1705 if (!cache->tdb)
1706 goto do_query;
1707
1708 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1709 if (!centry)
1710 goto do_query;
1711
1712do_fetch_cache:
1713 *num_entries = centry_uint32(centry);
1714
1715 if (*num_entries == 0)
1716 goto do_cached;
1717
1718 (*info) = talloc_array(mem_ctx, struct wb_acct_info, *num_entries);
1719 if (! (*info)) {
1720 smb_panic_fn("enum_dom_groups out of memory");
1721 }
1722 for (i=0; i<(*num_entries); i++) {
1723 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1724 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1725 (*info)[i].rid = centry_uint32(centry);
1726 }
1727
1728do_cached:
1729
1730 /* If we are returning cached data and the domain controller
1731 is down then we don't know whether the data is up to date
1732 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1733 indicate this. */
1734
1735 if (wcache_server_down(domain)) {
1736 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1737 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1738 } else
1739 status = centry->status;
1740
1741 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1742 domain->name, nt_errstr(status) ));
1743
1744 centry_free(centry);
1745 return status;
1746
1747do_query:
1748 *num_entries = 0;
1749 *info = NULL;
1750
1751 /* Return status value returned by seq number check */
1752
1753 if (!NT_STATUS_IS_OK(domain->last_status))
1754 return domain->last_status;
1755
1756 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1757 domain->name ));
1758
1759 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1760
1761 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1762 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1763 if (!domain->internal && old_status) {
1764 set_domain_offline(domain);
1765 }
1766 if (cache->tdb &&
1767 !domain->internal &&
1768 !domain->online &&
1769 old_status) {
1770 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1771 if (centry) {
1772 goto do_fetch_cache;
1773 }
1774 }
1775 }
1776 /* and save it */
1777 refresh_sequence_number(domain);
1778 if (!NT_STATUS_IS_OK(status)) {
1779 return status;
1780 }
1781 centry = centry_start(domain, status);
1782 if (!centry)
1783 goto skip_save;
1784 centry_put_uint32(centry, *num_entries);
1785 for (i=0; i<(*num_entries); i++) {
1786 centry_put_string(centry, (*info)[i].acct_name);
1787 centry_put_string(centry, (*info)[i].acct_desc);
1788 centry_put_uint32(centry, (*info)[i].rid);
1789 }
1790 centry_end(centry, "GL/%s/local", domain->name);
1791 centry_free(centry);
1792
1793skip_save:
1794 return status;
1795}
1796
1797NTSTATUS wcache_name_to_sid(struct winbindd_domain *domain,
1798 const char *domain_name,
1799 const char *name,
1800 struct dom_sid *sid,
1801 enum lsa_SidType *type)
1802{
1803 struct winbind_cache *cache = get_cache(domain);
1804 struct cache_entry *centry;
1805 NTSTATUS status;
1806 char *uname;
1807
1808 if (cache->tdb == NULL) {
1809 return NT_STATUS_NOT_FOUND;
1810 }
1811
1812 uname = talloc_strdup_upper(talloc_tos(), name);
1813 if (uname == NULL) {
1814 return NT_STATUS_NO_MEMORY;
1815 }
1816
1817 if ((domain_name == NULL) || (domain_name[0] == '\0')) {
1818 domain_name = domain->name;
1819 }
1820
1821 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1822 TALLOC_FREE(uname);
1823 if (centry == NULL) {
1824 return NT_STATUS_NOT_FOUND;
1825 }
1826
1827 status = centry->status;
1828 if (NT_STATUS_IS_OK(status)) {
1829 *type = (enum lsa_SidType)centry_uint32(centry);
1830 centry_sid(centry, sid);
1831 }
1832
1833 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1834 "%s\n", domain->name, nt_errstr(status) ));
1835
1836 centry_free(centry);
1837 return status;
1838}
1839
1840/* convert a single name to a sid in a domain */
1841static NTSTATUS name_to_sid(struct winbindd_domain *domain,
1842 TALLOC_CTX *mem_ctx,
1843 const char *domain_name,
1844 const char *name,
1845 uint32_t flags,
1846 struct dom_sid *sid,
1847 enum lsa_SidType *type)
1848{
1849 NTSTATUS status;
1850 bool old_status;
1851
1852 old_status = domain->online;
1853
1854 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1855 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1856 return status;
1857 }
1858
1859 ZERO_STRUCTP(sid);
1860
1861 /* If the seq number check indicated that there is a problem
1862 * with this DC, then return that status... except for
1863 * access_denied. This is special because the dc may be in
1864 * "restrict anonymous = 1" mode, in which case it will deny
1865 * most unauthenticated operations, but *will* allow the LSA
1866 * name-to-sid that we try as a fallback. */
1867
1868 if (!(NT_STATUS_IS_OK(domain->last_status)
1869 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1870 return domain->last_status;
1871
1872 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1873 domain->name ));
1874
1875 status = domain->backend->name_to_sid(domain, mem_ctx, domain_name,
1876 name, flags, sid, type);
1877
1878 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1879 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1880 if (!domain->internal && old_status) {
1881 set_domain_offline(domain);
1882 }
1883 if (!domain->internal &&
1884 !domain->online &&
1885 old_status) {
1886 NTSTATUS cache_status;
1887 cache_status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1888 return cache_status;
1889 }
1890 }
1891 /* and save it */
1892 refresh_sequence_number(domain);
1893
1894 if (domain->online &&
1895 (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
1896 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1897
1898 /* Only save the reverse mapping if this was not a UPN */
1899 if (!strchr(name, '@')) {
1900 if (!strupper_m(discard_const_p(char, domain_name))) {
1901 return NT_STATUS_INVALID_PARAMETER;
1902 }
1903 (void)strlower_m(discard_const_p(char, name));
1904 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1905 }
1906 }
1907
1908 return status;
1909}
1910
1911static NTSTATUS wcache_sid_to_name(struct winbindd_domain *domain,
1912 const struct dom_sid *sid,
1913 TALLOC_CTX *mem_ctx,
1914 char **domain_name,
1915 char **name,
1916 enum lsa_SidType *type)
1917{
1918 struct winbind_cache *cache = get_cache(domain);
1919 struct cache_entry *centry;
1920 char *sid_string;
1921 NTSTATUS status;
1922
1923 if (cache->tdb == NULL) {
1924 return NT_STATUS_NOT_FOUND;
1925 }
1926
1927 sid_string = sid_string_tos(sid);
1928 if (sid_string == NULL) {
1929 return NT_STATUS_NO_MEMORY;
1930 }
1931
1932 centry = wcache_fetch(cache, domain, "SN/%s", sid_string);
1933 TALLOC_FREE(sid_string);
1934 if (centry == NULL) {
1935 return NT_STATUS_NOT_FOUND;
1936 }
1937
1938 if (NT_STATUS_IS_OK(centry->status)) {
1939 *type = (enum lsa_SidType)centry_uint32(centry);
1940 *domain_name = centry_string(centry, mem_ctx);
1941 *name = centry_string(centry, mem_ctx);
1942 }
1943
1944 status = centry->status;
1945 centry_free(centry);
1946
1947 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1948 "%s\n", domain->name, nt_errstr(status) ));
1949
1950 return status;
1951}
1952
1953/* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1954 given */
1955static NTSTATUS sid_to_name(struct winbindd_domain *domain,
1956 TALLOC_CTX *mem_ctx,
1957 const struct dom_sid *sid,
1958 char **domain_name,
1959 char **name,
1960 enum lsa_SidType *type)
1961{
1962 NTSTATUS status;
1963 bool old_status;
1964
1965 old_status = domain->online;
1966 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
1967 type);
1968 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1969 return status;
1970 }
1971
1972 *name = NULL;
1973 *domain_name = NULL;
1974
1975 /* If the seq number check indicated that there is a problem
1976 * with this DC, then return that status... except for
1977 * access_denied. This is special because the dc may be in
1978 * "restrict anonymous = 1" mode, in which case it will deny
1979 * most unauthenticated operations, but *will* allow the LSA
1980 * sid-to-name that we try as a fallback. */
1981
1982 if (!(NT_STATUS_IS_OK(domain->last_status)
1983 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1984 return domain->last_status;
1985
1986 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1987 domain->name ));
1988
1989 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1990
1991 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1992 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1993 if (!domain->internal && old_status) {
1994 set_domain_offline(domain);
1995 }
1996 if (!domain->internal &&
1997 !domain->online &&
1998 old_status) {
1999 NTSTATUS cache_status;
2000 cache_status = wcache_sid_to_name(domain, sid, mem_ctx,
2001 domain_name, name, type);
2002 return cache_status;
2003 }
2004 }
2005 /* and save it */
2006 refresh_sequence_number(domain);
2007 if (!NT_STATUS_IS_OK(status)) {
2008 return status;
2009 }
2010 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
2011
2012 /* We can't save the name to sid mapping here, as with sid history a
2013 * later name2sid would give the wrong sid. */
2014
2015 return status;
2016}
2017
2018static NTSTATUS rids_to_names(struct winbindd_domain *domain,
2019 TALLOC_CTX *mem_ctx,
2020 const struct dom_sid *domain_sid,
2021 uint32_t *rids,
2022 size_t num_rids,
2023 char **domain_name,
2024 char ***names,
2025 enum lsa_SidType **types)
2026{
2027 struct winbind_cache *cache = get_cache(domain);
2028 size_t i;
2029 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
2030 bool have_mapped;
2031 bool have_unmapped;
2032 bool old_status;
2033
2034 old_status = domain->online;
2035 *domain_name = NULL;
2036 *names = NULL;
2037 *types = NULL;
2038
2039 if (!cache->tdb) {
2040 goto do_query;
2041 }
2042
2043 if (num_rids == 0) {
2044 return NT_STATUS_OK;
2045 }
2046
2047 *names = talloc_array(mem_ctx, char *, num_rids);
2048 *types = talloc_array(mem_ctx, enum lsa_SidType, num_rids);
2049
2050 if ((*names == NULL) || (*types == NULL)) {
2051 result = NT_STATUS_NO_MEMORY;
2052 goto error;
2053 }
2054
2055 have_mapped = have_unmapped = false;
2056
2057 for (i=0; i<num_rids; i++) {
2058 struct dom_sid sid;
2059 struct cache_entry *centry;
2060 fstring tmp;
2061
2062 if (!sid_compose(&sid, domain_sid, rids[i])) {
2063 result = NT_STATUS_INTERNAL_ERROR;
2064 goto error;
2065 }
2066
2067 centry = wcache_fetch(cache, domain, "SN/%s",
2068 sid_to_fstring(tmp, &sid));
2069 if (!centry) {
2070 goto do_query;
2071 }
2072
2073 (*types)[i] = SID_NAME_UNKNOWN;
2074 (*names)[i] = talloc_strdup(*names, "");
2075
2076 if (NT_STATUS_IS_OK(centry->status)) {
2077 char *dom;
2078 have_mapped = true;
2079 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
2080
2081 dom = centry_string(centry, mem_ctx);
2082 if (*domain_name == NULL) {
2083 *domain_name = dom;
2084 } else {
2085 talloc_free(dom);
2086 }
2087
2088 (*names)[i] = centry_string(centry, *names);
2089
2090 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)
2091 || NT_STATUS_EQUAL(centry->status, STATUS_SOME_UNMAPPED)) {
2092 have_unmapped = true;
2093
2094 } else {
2095 /* something's definitely wrong */
2096 result = centry->status;
2097 centry_free(centry);
2098 goto error;
2099 }
2100
2101 centry_free(centry);
2102 }
2103
2104 if (!have_mapped) {
2105 return NT_STATUS_NONE_MAPPED;
2106 }
2107 if (!have_unmapped) {
2108 return NT_STATUS_OK;
2109 }
2110 return STATUS_SOME_UNMAPPED;
2111
2112 do_query:
2113
2114 TALLOC_FREE(*names);
2115 TALLOC_FREE(*types);
2116
2117 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
2118 rids, num_rids, domain_name,
2119 names, types);
2120
2121 if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
2122 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2123 if (!domain->internal && old_status) {
2124 set_domain_offline(domain);
2125 }
2126 if (cache->tdb &&
2127 !domain->internal &&
2128 !domain->online &&
2129 old_status) {
2130 have_mapped = have_unmapped = false;
2131
2132 *names = talloc_array(mem_ctx, char *, num_rids);
2133 if (*names == NULL) {
2134 result = NT_STATUS_NO_MEMORY;
2135 goto error;
2136 }
2137
2138 *types = talloc_array(mem_ctx, enum lsa_SidType,
2139 num_rids);
2140 if (*types == NULL) {
2141 result = NT_STATUS_NO_MEMORY;
2142 goto error;
2143 }
2144
2145 for (i=0; i<num_rids; i++) {
2146 struct dom_sid sid;
2147 struct cache_entry *centry;
2148 fstring tmp;
2149
2150 if (!sid_compose(&sid, domain_sid, rids[i])) {
2151 result = NT_STATUS_INTERNAL_ERROR;
2152 goto error;
2153 }
2154
2155 centry = wcache_fetch(cache, domain, "SN/%s",
2156 sid_to_fstring(tmp, &sid));
2157 if (!centry) {
2158 (*types)[i] = SID_NAME_UNKNOWN;
2159 (*names)[i] = talloc_strdup(*names, "");
2160 continue;
2161 }
2162
2163 (*types)[i] = SID_NAME_UNKNOWN;
2164 (*names)[i] = talloc_strdup(*names, "");
2165
2166 if (NT_STATUS_IS_OK(centry->status)) {
2167 char *dom;
2168 have_mapped = true;
2169 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
2170
2171 dom = centry_string(centry, mem_ctx);
2172 if (*domain_name == NULL) {
2173 *domain_name = dom;
2174 } else {
2175 talloc_free(dom);
2176 }
2177
2178 (*names)[i] = centry_string(centry, *names);
2179
2180 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
2181 have_unmapped = true;
2182
2183 } else {
2184 /* something's definitely wrong */
2185 result = centry->status;
2186 centry_free(centry);
2187 goto error;
2188 }
2189
2190 centry_free(centry);
2191 }
2192
2193 if (!have_mapped) {
2194 return NT_STATUS_NONE_MAPPED;
2195 }
2196 if (!have_unmapped) {
2197 return NT_STATUS_OK;
2198 }
2199 return STATUS_SOME_UNMAPPED;
2200 }
2201 }
2202 /*
2203 None of the queried rids has been found so save all negative entries
2204 */
2205 if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
2206 for (i = 0; i < num_rids; i++) {
2207 struct dom_sid sid;
2208 const char *name = "";
2209 const enum lsa_SidType type = SID_NAME_UNKNOWN;
2210 NTSTATUS status = NT_STATUS_NONE_MAPPED;
2211
2212 if (!sid_compose(&sid, domain_sid, rids[i])) {
2213 return NT_STATUS_INTERNAL_ERROR;
2214 }
2215
2216 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2217 name, type);
2218 }
2219
2220 return result;
2221 }
2222
2223 /*
2224 Some or all of the queried rids have been found.
2225 */
2226 if (!NT_STATUS_IS_OK(result) &&
2227 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
2228 return result;
2229 }
2230
2231 refresh_sequence_number(domain);
2232
2233 for (i=0; i<num_rids; i++) {
2234 struct dom_sid sid;
2235 NTSTATUS status;
2236
2237 if (!sid_compose(&sid, domain_sid, rids[i])) {
2238 result = NT_STATUS_INTERNAL_ERROR;
2239 goto error;
2240 }
2241
2242 status = (*types)[i] == SID_NAME_UNKNOWN ?
2243 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
2244
2245 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2246 (*names)[i], (*types)[i]);
2247 }
2248
2249 return result;
2250
2251 error:
2252 TALLOC_FREE(*names);
2253 TALLOC_FREE(*types);
2254 return result;
2255}
2256
2257NTSTATUS wcache_query_user(struct winbindd_domain *domain,
2258 TALLOC_CTX *mem_ctx,
2259 const struct dom_sid *user_sid,
2260 struct wbint_userinfo *info)
2261{
2262 struct winbind_cache *cache = get_cache(domain);
2263 struct cache_entry *centry = NULL;
2264 NTSTATUS status;
2265 char *sid_string;
2266
2267 if (cache->tdb == NULL) {
2268 return NT_STATUS_NOT_FOUND;
2269 }
2270
2271 sid_string = sid_string_tos(user_sid);
2272 if (sid_string == NULL) {
2273 return NT_STATUS_NO_MEMORY;
2274 }
2275
2276 centry = wcache_fetch(cache, domain, "U/%s", sid_string);
2277 TALLOC_FREE(sid_string);
2278 if (centry == NULL) {
2279 return NT_STATUS_NOT_FOUND;
2280 }
2281
2282 /*
2283 * If we have an access denied cache entry and a cached info3
2284 * in the samlogon cache then do a query. This will force the
2285 * rpc back end to return the info3 data.
2286 */
2287
2288 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED) &&
2289 netsamlogon_cache_have(user_sid)) {
2290 DEBUG(10, ("query_user: cached access denied and have cached "
2291 "info3\n"));
2292 domain->last_status = NT_STATUS_OK;
2293 centry_free(centry);
2294 return NT_STATUS_NOT_FOUND;
2295 }
2296
2297 /* if status is not ok then this is a negative hit
2298 and the rest of the data doesn't matter */
2299 status = centry->status;
2300 if (NT_STATUS_IS_OK(status)) {
2301 info->acct_name = centry_string(centry, mem_ctx);
2302 info->full_name = centry_string(centry, mem_ctx);
2303 info->homedir = centry_string(centry, mem_ctx);
2304 info->shell = centry_string(centry, mem_ctx);
2305 info->primary_gid = centry_uint32(centry);
2306 centry_sid(centry, &info->user_sid);
2307 centry_sid(centry, &info->group_sid);
2308 }
2309
2310 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2311 "%s\n", domain->name, nt_errstr(status) ));
2312
2313 centry_free(centry);
2314 return status;
2315}
2316
2317
2318/**
2319* @brief Query a fullname from the username cache (for further gecos processing)
2320*
2321* @param domain A pointer to the winbindd_domain struct.
2322* @param mem_ctx The talloc context.
2323* @param user_sid The user sid.
2324* @param full_name A pointer to the full_name string.
2325*
2326* @return NTSTATUS code
2327*/
2328NTSTATUS wcache_query_user_fullname(struct winbindd_domain *domain,
2329 TALLOC_CTX *mem_ctx,
2330 const struct dom_sid *user_sid,
2331 const char **full_name)
2332{
2333 NTSTATUS status;
2334 struct wbint_userinfo info;
2335
2336 status = wcache_query_user(domain, mem_ctx, user_sid, &info);
2337 if (!NT_STATUS_IS_OK(status)) {
2338 return status;
2339 }
2340
2341 if (info.full_name != NULL) {
2342 *full_name = talloc_strdup(mem_ctx, info.full_name);
2343 if (*full_name == NULL) {
2344 return NT_STATUS_NO_MEMORY;
2345 }
2346 }
2347
2348 return NT_STATUS_OK;
2349}
2350
2351/* Lookup user information from a rid */
2352static NTSTATUS query_user(struct winbindd_domain *domain,
2353 TALLOC_CTX *mem_ctx,
2354 const struct dom_sid *user_sid,
2355 struct wbint_userinfo *info)
2356{
2357 NTSTATUS status;
2358 bool old_status;
2359
2360 old_status = domain->online;
2361 status = wcache_query_user(domain, mem_ctx, user_sid, info);
2362 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2363 return status;
2364 }
2365
2366 ZERO_STRUCTP(info);
2367
2368 /* Return status value returned by seq number check */
2369
2370 if (!NT_STATUS_IS_OK(domain->last_status))
2371 return domain->last_status;
2372
2373 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2374 domain->name ));
2375
2376 status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
2377
2378 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2379 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2380 if (!domain->internal && old_status) {
2381 set_domain_offline(domain);
2382 }
2383 if (!domain->internal &&
2384 !domain->online &&
2385 old_status) {
2386 NTSTATUS cache_status;
2387 cache_status = wcache_query_user(domain, mem_ctx, user_sid, info);
2388 return cache_status;
2389 }
2390 }
2391 /* and save it */
2392 refresh_sequence_number(domain);
2393 if (!NT_STATUS_IS_OK(status)) {
2394 return status;
2395 }
2396 wcache_save_user(domain, status, info);
2397
2398 return status;
2399}
2400
2401NTSTATUS wcache_lookup_usergroups(struct winbindd_domain *domain,
2402 TALLOC_CTX *mem_ctx,
2403 const struct dom_sid *user_sid,
2404 uint32_t *pnum_sids,
2405 struct dom_sid **psids)
2406{
2407 struct winbind_cache *cache = get_cache(domain);
2408 struct cache_entry *centry = NULL;
2409 NTSTATUS status;
2410 uint32_t i, num_sids;
2411 struct dom_sid *sids;
2412 fstring sid_string;
2413
2414 if (cache->tdb == NULL) {
2415 return NT_STATUS_NOT_FOUND;
2416 }
2417
2418 centry = wcache_fetch(cache, domain, "UG/%s",
2419 sid_to_fstring(sid_string, user_sid));
2420 if (centry == NULL) {
2421 return NT_STATUS_NOT_FOUND;
2422 }
2423
2424 /* If we have an access denied cache entry and a cached info3 in the
2425 samlogon cache then do a query. This will force the rpc back end
2426 to return the info3 data. */
2427
2428 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)
2429 && netsamlogon_cache_have(user_sid)) {
2430 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2431 "cached info3\n"));
2432 domain->last_status = NT_STATUS_OK;
2433 centry_free(centry);
2434 return NT_STATUS_NOT_FOUND;
2435 }
2436
2437 num_sids = centry_uint32(centry);
2438 sids = talloc_array(mem_ctx, struct dom_sid, num_sids);
2439 if (sids == NULL) {
2440 centry_free(centry);
2441 return NT_STATUS_NO_MEMORY;
2442 }
2443
2444 for (i=0; i<num_sids; i++) {
2445 centry_sid(centry, &sids[i]);
2446 }
2447
2448 status = centry->status;
2449
2450 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2451 "status: %s\n", domain->name, nt_errstr(status)));
2452
2453 centry_free(centry);
2454
2455 *pnum_sids = num_sids;
2456 *psids = sids;
2457 return status;
2458}
2459
2460/* Lookup groups a user is a member of. */
2461static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
2462 TALLOC_CTX *mem_ctx,
2463 const struct dom_sid *user_sid,
2464 uint32_t *num_groups, struct dom_sid **user_gids)
2465{
2466 struct cache_entry *centry = NULL;
2467 NTSTATUS status;
2468 unsigned int i;
2469 fstring sid_string;
2470 bool old_status;
2471
2472 old_status = domain->online;
2473 status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2474 num_groups, user_gids);
2475 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2476 return status;
2477 }
2478
2479 (*num_groups) = 0;
2480 (*user_gids) = NULL;
2481
2482 /* Return status value returned by seq number check */
2483
2484 if (!NT_STATUS_IS_OK(domain->last_status))
2485 return domain->last_status;
2486
2487 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2488 domain->name ));
2489
2490 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
2491
2492 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2493 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2494 if (!domain->internal && old_status) {
2495 set_domain_offline(domain);
2496 }
2497 if (!domain->internal &&
2498 !domain->online &&
2499 old_status) {
2500 NTSTATUS cache_status;
2501 cache_status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2502 num_groups, user_gids);
2503 return cache_status;
2504 }
2505 }
2506 if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
2507 goto skip_save;
2508
2509 /* and save it */
2510 refresh_sequence_number(domain);
2511 if (!NT_STATUS_IS_OK(status)) {
2512 return status;
2513 }
2514 centry = centry_start(domain, status);
2515 if (!centry)
2516 goto skip_save;
2517
2518 centry_put_uint32(centry, *num_groups);
2519 for (i=0; i<(*num_groups); i++) {
2520 centry_put_sid(centry, &(*user_gids)[i]);
2521 }
2522
2523 centry_end(centry, "UG/%s", sid_to_fstring(sid_string, user_sid));
2524 centry_free(centry);
2525
2526skip_save:
2527 return status;
2528}
2529
2530static char *wcache_make_sidlist(TALLOC_CTX *mem_ctx, uint32_t num_sids,
2531 const struct dom_sid *sids)
2532{
2533 uint32_t i;
2534 char *sidlist;
2535
2536 sidlist = talloc_strdup(mem_ctx, "");
2537 if (sidlist == NULL) {
2538 return NULL;
2539 }
2540 for (i=0; i<num_sids; i++) {
2541 fstring tmp;
2542 sidlist = talloc_asprintf_append_buffer(
2543 sidlist, "/%s", sid_to_fstring(tmp, &sids[i]));
2544 if (sidlist == NULL) {
2545 return NULL;
2546 }
2547 }
2548 return sidlist;
2549}
2550
2551NTSTATUS wcache_lookup_useraliases(struct winbindd_domain *domain,
2552 TALLOC_CTX *mem_ctx, uint32_t num_sids,
2553 const struct dom_sid *sids,
2554 uint32_t *pnum_aliases, uint32_t **paliases)
2555{
2556 struct winbind_cache *cache = get_cache(domain);
2557 struct cache_entry *centry = NULL;
2558 uint32_t num_aliases;
2559 uint32_t *aliases;
2560 NTSTATUS status;
2561 char *sidlist;
2562 int i;
2563
2564 if (cache->tdb == NULL) {
2565 return NT_STATUS_NOT_FOUND;
2566 }
2567
2568 if (num_sids == 0) {
2569 *pnum_aliases = 0;
2570 *paliases = NULL;
2571 return NT_STATUS_OK;
2572 }
2573
2574 /* We need to cache indexed by the whole list of SIDs, the aliases
2575 * resulting might come from any of the SIDs. */
2576
2577 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2578 if (sidlist == NULL) {
2579 return NT_STATUS_NO_MEMORY;
2580 }
2581
2582 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
2583 TALLOC_FREE(sidlist);
2584 if (centry == NULL) {
2585 return NT_STATUS_NOT_FOUND;
2586 }
2587
2588 num_aliases = centry_uint32(centry);
2589 aliases = talloc_array(mem_ctx, uint32_t, num_aliases);
2590 if (aliases == NULL) {
2591 centry_free(centry);
2592 return NT_STATUS_NO_MEMORY;
2593 }
2594
2595 for (i=0; i<num_aliases; i++) {
2596 aliases[i] = centry_uint32(centry);
2597 }
2598
2599 status = centry->status;
2600
2601 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2602 "status %s\n", domain->name, nt_errstr(status)));
2603
2604 centry_free(centry);
2605
2606 *pnum_aliases = num_aliases;
2607 *paliases = aliases;
2608
2609 return status;
2610}
2611
2612static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
2613 TALLOC_CTX *mem_ctx,
2614 uint32_t num_sids, const struct dom_sid *sids,
2615 uint32_t *num_aliases, uint32_t **alias_rids)
2616{
2617 struct cache_entry *centry = NULL;
2618 NTSTATUS status;
2619 char *sidlist;
2620 int i;
2621 bool old_status;
2622
2623 old_status = domain->online;
2624 status = wcache_lookup_useraliases(domain, mem_ctx, num_sids, sids,
2625 num_aliases, alias_rids);
2626 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2627 return status;
2628 }
2629
2630 (*num_aliases) = 0;
2631 (*alias_rids) = NULL;
2632
2633 if (!NT_STATUS_IS_OK(domain->last_status))
2634 return domain->last_status;
2635
2636 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2637 "for domain %s\n", domain->name ));
2638
2639 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2640 if (sidlist == NULL) {
2641 return NT_STATUS_NO_MEMORY;
2642 }
2643
2644 status = domain->backend->lookup_useraliases(domain, mem_ctx,
2645 num_sids, sids,
2646 num_aliases, alias_rids);
2647
2648 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2649 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2650 if (!domain->internal && old_status) {
2651 set_domain_offline(domain);
2652 }
2653 if (!domain->internal &&
2654 !domain->online &&
2655 old_status) {
2656 NTSTATUS cache_status;
2657 cache_status = wcache_lookup_useraliases(domain, mem_ctx, num_sids,
2658 sids, num_aliases, alias_rids);
2659 return cache_status;
2660 }
2661 }
2662 /* and save it */
2663 refresh_sequence_number(domain);
2664 if (!NT_STATUS_IS_OK(status)) {
2665 return status;
2666 }
2667 centry = centry_start(domain, status);
2668 if (!centry)
2669 goto skip_save;
2670 centry_put_uint32(centry, *num_aliases);
2671 for (i=0; i<(*num_aliases); i++)
2672 centry_put_uint32(centry, (*alias_rids)[i]);
2673 centry_end(centry, "UA%s", sidlist);
2674 centry_free(centry);
2675
2676 skip_save:
2677 return status;
2678}
2679
2680NTSTATUS wcache_lookup_groupmem(struct winbindd_domain *domain,
2681 TALLOC_CTX *mem_ctx,
2682 const struct dom_sid *group_sid,
2683 uint32_t *num_names,
2684 struct dom_sid **sid_mem, char ***names,
2685 uint32_t **name_types)
2686{
2687 struct winbind_cache *cache = get_cache(domain);
2688 struct cache_entry *centry = NULL;
2689 NTSTATUS status;
2690 unsigned int i;
2691 char *sid_string;
2692
2693 if (cache->tdb == NULL) {
2694 return NT_STATUS_NOT_FOUND;
2695 }
2696
2697 sid_string = sid_string_tos(group_sid);
2698 if (sid_string == NULL) {
2699 return NT_STATUS_NO_MEMORY;
2700 }
2701
2702 centry = wcache_fetch(cache, domain, "GM/%s", sid_string);
2703 TALLOC_FREE(sid_string);
2704 if (centry == NULL) {
2705 return NT_STATUS_NOT_FOUND;
2706 }
2707
2708 *sid_mem = NULL;
2709 *names = NULL;
2710 *name_types = NULL;
2711
2712 *num_names = centry_uint32(centry);
2713 if (*num_names == 0) {
2714 centry_free(centry);
2715 return NT_STATUS_OK;
2716 }
2717
2718 *sid_mem = talloc_array(mem_ctx, struct dom_sid, *num_names);
2719 *names = talloc_array(mem_ctx, char *, *num_names);
2720 *name_types = talloc_array(mem_ctx, uint32_t, *num_names);
2721
2722 if ((*sid_mem == NULL) || (*names == NULL) || (*name_types == NULL)) {
2723 TALLOC_FREE(*sid_mem);
2724 TALLOC_FREE(*names);
2725 TALLOC_FREE(*name_types);
2726 centry_free(centry);
2727 return NT_STATUS_NO_MEMORY;
2728 }
2729
2730 for (i=0; i<(*num_names); i++) {
2731 centry_sid(centry, &(*sid_mem)[i]);
2732 (*names)[i] = centry_string(centry, mem_ctx);
2733 (*name_types)[i] = centry_uint32(centry);
2734 }
2735
2736 status = centry->status;
2737
2738 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2739 "status: %s\n", domain->name, nt_errstr(status)));
2740
2741 centry_free(centry);
2742 return status;
2743}
2744
2745static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
2746 TALLOC_CTX *mem_ctx,
2747 const struct dom_sid *group_sid,
2748 enum lsa_SidType type,
2749 uint32_t *num_names,
2750 struct dom_sid **sid_mem, char ***names,
2751 uint32_t **name_types)
2752{
2753 struct cache_entry *centry = NULL;
2754 NTSTATUS status;
2755 unsigned int i;
2756 fstring sid_string;
2757 bool old_status;
2758
2759 old_status = domain->online;
2760 status = wcache_lookup_groupmem(domain, mem_ctx, group_sid, num_names,
2761 sid_mem, names, name_types);
2762 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2763 return status;
2764 }
2765
2766 (*num_names) = 0;
2767 (*sid_mem) = NULL;
2768 (*names) = NULL;
2769 (*name_types) = NULL;
2770
2771 /* Return status value returned by seq number check */
2772
2773 if (!NT_STATUS_IS_OK(domain->last_status))
2774 return domain->last_status;
2775
2776 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2777 domain->name ));
2778
2779 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid,
2780 type, num_names,
2781 sid_mem, names, name_types);
2782
2783 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2784 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2785 if (!domain->internal && old_status) {
2786 set_domain_offline(domain);
2787 }
2788 if (!domain->internal &&
2789 !domain->online &&
2790 old_status) {
2791 NTSTATUS cache_status;
2792 cache_status = wcache_lookup_groupmem(domain, mem_ctx, group_sid,
2793 num_names, sid_mem, names,
2794 name_types);
2795 return cache_status;
2796 }
2797 }
2798 /* and save it */
2799 refresh_sequence_number(domain);
2800 if (!NT_STATUS_IS_OK(status)) {
2801 return status;
2802 }
2803 centry = centry_start(domain, status);
2804 if (!centry)
2805 goto skip_save;
2806 centry_put_uint32(centry, *num_names);
2807 for (i=0; i<(*num_names); i++) {
2808 centry_put_sid(centry, &(*sid_mem)[i]);
2809 centry_put_string(centry, (*names)[i]);
2810 centry_put_uint32(centry, (*name_types)[i]);
2811 }
2812 centry_end(centry, "GM/%s", sid_to_fstring(sid_string, group_sid));
2813 centry_free(centry);
2814
2815skip_save:
2816 return status;
2817}
2818
2819/* find the sequence number for a domain */
2820static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32_t *seq)
2821{
2822 refresh_sequence_number(domain);
2823
2824 *seq = domain->sequence_number;
2825
2826 return NT_STATUS_OK;
2827}
2828
2829/* enumerate trusted domains
2830 * (we need to have the list of trustdoms in the cache when we go offline) -
2831 * Guenther */
2832static NTSTATUS trusted_domains(struct winbindd_domain *domain,
2833 TALLOC_CTX *mem_ctx,
2834 struct netr_DomainTrustList *trusts)
2835{
2836 NTSTATUS status;
2837 struct winbind_cache *cache;
2838 struct winbindd_tdc_domain *dom_list = NULL;
2839 size_t num_domains = 0;
2840 bool retval = false;
2841 int i;
2842 bool old_status;
2843
2844 old_status = domain->online;
2845 trusts->count = 0;
2846 trusts->array = NULL;
2847
2848 cache = get_cache(domain);
2849 if (!cache || !cache->tdb) {
2850 goto do_query;
2851 }
2852
2853 if (domain->online) {
2854 goto do_query;
2855 }
2856
2857 retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2858 if (!retval || !num_domains || !dom_list) {
2859 TALLOC_FREE(dom_list);
2860 goto do_query;
2861 }
2862
2863do_fetch_cache:
2864 trusts->array = talloc_zero_array(mem_ctx, struct netr_DomainTrust, num_domains);
2865 if (!trusts->array) {
2866 TALLOC_FREE(dom_list);
2867 return NT_STATUS_NO_MEMORY;
2868 }
2869
2870 for (i = 0; i < num_domains; i++) {
2871 struct netr_DomainTrust *trust;
2872 struct dom_sid *sid;
2873 struct winbindd_domain *dom;
2874
2875 dom = find_domain_from_name_noinit(dom_list[i].domain_name);
2876 if (dom && dom->internal) {
2877 continue;
2878 }
2879
2880 trust = &trusts->array[trusts->count];
2881 trust->netbios_name = talloc_strdup(trusts->array, dom_list[i].domain_name);
2882 trust->dns_name = talloc_strdup(trusts->array, dom_list[i].dns_name);
2883 sid = talloc(trusts->array, struct dom_sid);
2884 if (!trust->netbios_name || !trust->dns_name ||
2885 !sid) {
2886 TALLOC_FREE(dom_list);
2887 TALLOC_FREE(trusts->array);
2888 return NT_STATUS_NO_MEMORY;
2889 }
2890
2891 trust->trust_flags = dom_list[i].trust_flags;
2892 trust->trust_attributes = dom_list[i].trust_attribs;
2893 trust->trust_type = dom_list[i].trust_type;
2894 sid_copy(sid, &dom_list[i].sid);
2895 trust->sid = sid;
2896 trusts->count++;
2897 }
2898
2899 TALLOC_FREE(dom_list);
2900 return NT_STATUS_OK;
2901
2902do_query:
2903 /* Return status value returned by seq number check */
2904
2905 if (!NT_STATUS_IS_OK(domain->last_status))
2906 return domain->last_status;
2907
2908 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2909 domain->name ));
2910
2911 status = domain->backend->trusted_domains(domain, mem_ctx, trusts);
2912
2913 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2914 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2915 if (!domain->internal && old_status) {
2916 set_domain_offline(domain);
2917 }
2918 if (!domain->internal &&
2919 !domain->online &&
2920 old_status) {
2921 retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2922 if (retval && num_domains && dom_list) {
2923 TALLOC_FREE(trusts->array);
2924 trusts->count = 0;
2925 goto do_fetch_cache;
2926 }
2927 }
2928 }
2929 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2930 * so that the generic centry handling still applies correctly -
2931 * Guenther*/
2932
2933 if (!NT_STATUS_IS_ERR(status)) {
2934 status = NT_STATUS_OK;
2935 }
2936 return status;
2937}
2938
2939/* get lockout policy */
2940static NTSTATUS lockout_policy(struct winbindd_domain *domain,
2941 TALLOC_CTX *mem_ctx,
2942 struct samr_DomInfo12 *policy)
2943{
2944 struct winbind_cache *cache = get_cache(domain);
2945 struct cache_entry *centry = NULL;
2946 NTSTATUS status;
2947 bool old_status;
2948
2949 old_status = domain->online;
2950 if (!cache->tdb)
2951 goto do_query;
2952
2953 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2954
2955 if (!centry)
2956 goto do_query;
2957
2958do_fetch_cache:
2959 policy->lockout_duration = centry_nttime(centry);
2960 policy->lockout_window = centry_nttime(centry);
2961 policy->lockout_threshold = centry_uint16(centry);
2962
2963 status = centry->status;
2964
2965 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2966 domain->name, nt_errstr(status) ));
2967
2968 centry_free(centry);
2969 return status;
2970
2971do_query:
2972 ZERO_STRUCTP(policy);
2973
2974 /* Return status value returned by seq number check */
2975
2976 if (!NT_STATUS_IS_OK(domain->last_status))
2977 return domain->last_status;
2978
2979 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2980 domain->name ));
2981
2982 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2983
2984 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2985 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2986 if (!domain->internal && old_status) {
2987 set_domain_offline(domain);
2988 }
2989 if (cache->tdb &&
2990 !domain->internal &&
2991 !domain->online &&
2992 old_status) {
2993 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2994 if (centry) {
2995 goto do_fetch_cache;
2996 }
2997 }
2998 }
2999 /* and save it */
3000 refresh_sequence_number(domain);
3001 if (!NT_STATUS_IS_OK(status)) {
3002 return status;
3003 }
3004 wcache_save_lockout_policy(domain, status, policy);
3005
3006 return status;
3007}
3008
3009/* get password policy */
3010static NTSTATUS password_policy(struct winbindd_domain *domain,
3011 TALLOC_CTX *mem_ctx,
3012 struct samr_DomInfo1 *policy)
3013{
3014 struct winbind_cache *cache = get_cache(domain);
3015 struct cache_entry *centry = NULL;
3016 NTSTATUS status;
3017 bool old_status;
3018
3019 old_status = domain->online;
3020 if (!cache->tdb)
3021 goto do_query;
3022
3023 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
3024
3025 if (!centry)
3026 goto do_query;
3027
3028do_fetch_cache:
3029 policy->min_password_length = centry_uint16(centry);
3030 policy->password_history_length = centry_uint16(centry);
3031 policy->password_properties = centry_uint32(centry);
3032 policy->max_password_age = centry_nttime(centry);
3033 policy->min_password_age = centry_nttime(centry);
3034
3035 status = centry->status;
3036
3037 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
3038 domain->name, nt_errstr(status) ));
3039
3040 centry_free(centry);
3041 return status;
3042
3043do_query:
3044 ZERO_STRUCTP(policy);
3045
3046 /* Return status value returned by seq number check */
3047
3048 if (!NT_STATUS_IS_OK(domain->last_status))
3049 return domain->last_status;
3050
3051 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
3052 domain->name ));
3053
3054 status = domain->backend->password_policy(domain, mem_ctx, policy);
3055
3056 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
3057 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
3058 if (!domain->internal && old_status) {
3059 set_domain_offline(domain);
3060 }
3061 if (cache->tdb &&
3062 !domain->internal &&
3063 !domain->online &&
3064 old_status) {
3065 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
3066 if (centry) {
3067 goto do_fetch_cache;
3068 }
3069 }
3070 }
3071 /* and save it */
3072 refresh_sequence_number(domain);
3073 if (!NT_STATUS_IS_OK(status)) {
3074 return status;
3075 }
3076 wcache_save_password_policy(domain, status, policy);
3077
3078 return status;
3079}
3080
3081
3082/* Invalidate cached user and group lists coherently */
3083
3084static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3085 void *state)
3086{
3087 if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
3088 strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
3089 tdb_delete(the_tdb, kbuf);
3090
3091 return 0;
3092}
3093
3094/* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3095
3096void wcache_invalidate_samlogon(struct winbindd_domain *domain,
3097 const struct dom_sid *sid)
3098{
3099 fstring key_str, sid_string;
3100 struct winbind_cache *cache;
3101
3102 /* don't clear cached U/SID and UG/SID entries when we want to logon
3103 * offline - gd */
3104
3105 if (lp_winbind_offline_logon()) {
3106 return;
3107 }
3108
3109 if (!domain)
3110 return;
3111
3112 cache = get_cache(domain);
3113
3114 if (!cache->tdb) {
3115 return;
3116 }
3117
3118 /* Clear U/SID cache entry */
3119 fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, sid));
3120 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
3121 tdb_delete(cache->tdb, string_tdb_data(key_str));
3122
3123 /* Clear UG/SID cache entry */
3124 fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, sid));
3125 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
3126 tdb_delete(cache->tdb, string_tdb_data(key_str));
3127
3128 /* Samba/winbindd never needs this. */
3129 netsamlogon_clear_cached_user(sid);
3130}
3131
3132bool wcache_invalidate_cache(void)
3133{
3134 struct winbindd_domain *domain;
3135
3136 for (domain = domain_list(); domain; domain = domain->next) {
3137 struct winbind_cache *cache = get_cache(domain);
3138
3139 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3140 "entries for %s\n", domain->name));
3141 if (cache) {
3142 if (cache->tdb) {
3143 tdb_traverse(cache->tdb, traverse_fn, NULL);
3144 } else {
3145 return false;
3146 }
3147 }
3148 }
3149 return true;
3150}
3151
3152bool wcache_invalidate_cache_noinit(void)
3153{
3154 struct winbindd_domain *domain;
3155
3156 for (domain = domain_list(); domain; domain = domain->next) {
3157 struct winbind_cache *cache;
3158
3159 /* Skip uninitialized domains. */
3160 if (!domain->initialized && !domain->internal) {
3161 continue;
3162 }
3163
3164 cache = get_cache(domain);
3165
3166 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3167 "entries for %s\n", domain->name));
3168 if (cache) {
3169 if (cache->tdb) {
3170 tdb_traverse(cache->tdb, traverse_fn, NULL);
3171 /*
3172 * Flushing cache has nothing to with domains.
3173 * return here if we successfully flushed once.
3174 * To avoid unnecessary traversing the cache.
3175 */
3176 return true;
3177 } else {
3178 return false;
3179 }
3180 }
3181 }
3182 return true;
3183}
3184
3185bool init_wcache(void)
3186{
3187 char *db_path;
3188
3189 if (wcache == NULL) {
3190 wcache = SMB_XMALLOC_P(struct winbind_cache);
3191 ZERO_STRUCTP(wcache);
3192 }
3193
3194 if (wcache->tdb != NULL)
3195 return true;
3196
3197 db_path = state_path("winbindd_cache.tdb");
3198 if (db_path == NULL) {
3199 return false;
3200 }
3201
3202 /* when working offline we must not clear the cache on restart */
3203 wcache->tdb = tdb_open_log(db_path,
3204 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3205 TDB_INCOMPATIBLE_HASH |
3206 (lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
3207 O_RDWR|O_CREAT, 0600);
3208 TALLOC_FREE(db_path);
3209 if (wcache->tdb == NULL) {
3210 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3211 return false;
3212 }
3213
3214 return true;
3215}
3216
3217/************************************************************************
3218 This is called by the parent to initialize the cache file.
3219 We don't need sophisticated locking here as we know we're the
3220 only opener.
3221************************************************************************/
3222
3223bool initialize_winbindd_cache(void)
3224{
3225 bool cache_bad = true;
3226 uint32_t vers;
3227
3228 if (!init_wcache()) {
3229 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3230 return false;
3231 }
3232
3233 /* Check version number. */
3234 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
3235 vers == WINBINDD_CACHE_VERSION) {
3236 cache_bad = false;
3237 }
3238
3239 if (cache_bad) {
3240 char *db_path;
3241
3242 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3243 "and re-creating with version number %d\n",
3244 WINBINDD_CACHE_VERSION ));
3245
3246 tdb_close(wcache->tdb);
3247 wcache->tdb = NULL;
3248
3249 db_path = state_path("winbindd_cache.tdb");
3250 if (db_path == NULL) {
3251 return false;
3252 }
3253
3254 if (unlink(db_path) == -1) {
3255 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3256 db_path,
3257 strerror(errno) ));
3258 TALLOC_FREE(db_path);
3259 return false;
3260 }
3261 TALLOC_FREE(db_path);
3262 if (!init_wcache()) {
3263 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3264 "init_wcache failed.\n"));
3265 return false;
3266 }
3267
3268 /* Write the version. */
3269 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
3270 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3271 tdb_errorstr(wcache->tdb) ));
3272 return false;
3273 }
3274 }
3275
3276 tdb_close(wcache->tdb);
3277 wcache->tdb = NULL;
3278 return true;
3279}
3280
3281void close_winbindd_cache(void)
3282{
3283 if (!wcache) {
3284 return;
3285 }
3286 if (wcache->tdb) {
3287 tdb_close(wcache->tdb);
3288 wcache->tdb = NULL;
3289 }
3290}
3291
3292bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
3293 char **domain_name, char **name,
3294 enum lsa_SidType *type)
3295{
3296 struct winbindd_domain *domain;
3297 NTSTATUS status;
3298
3299 domain = find_lookup_domain_from_sid(sid);
3300 if (domain == NULL) {
3301 return false;
3302 }
3303 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
3304 type);
3305 return NT_STATUS_IS_OK(status);
3306}
3307
3308bool lookup_cached_name(const char *domain_name,
3309 const char *name,
3310 struct dom_sid *sid,
3311 enum lsa_SidType *type)
3312{
3313 struct winbindd_domain *domain;
3314 NTSTATUS status;
3315 bool original_online_state;
3316
3317 domain = find_lookup_domain_from_name(domain_name);
3318 if (domain == NULL) {
3319 return false;
3320 }
3321
3322 /* If we are doing a cached logon, temporarily set the domain
3323 offline so the cache won't expire the entry */
3324
3325 original_online_state = domain->online;
3326 domain->online = false;
3327 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
3328 domain->online = original_online_state;
3329
3330 return NT_STATUS_IS_OK(status);
3331}
3332
3333/*
3334 * Cache a name to sid without checking the sequence number.
3335 * Used when caching from a trusted PAC.
3336 */
3337
3338void cache_name2sid_trusted(struct winbindd_domain *domain,
3339 const char *domain_name,
3340 const char *name,
3341 enum lsa_SidType type,
3342 const struct dom_sid *sid)
3343{
3344 /*
3345 * Ensure we store the mapping with the
3346 * existing sequence number from the cache.
3347 */
3348 get_cache(domain);
3349 (void)fetch_cache_seqnum(domain, time(NULL));
3350 wcache_save_name_to_sid(domain,
3351 NT_STATUS_OK,
3352 domain_name,
3353 name,
3354 sid,
3355 type);
3356}
3357
3358void cache_name2sid(struct winbindd_domain *domain,
3359 const char *domain_name, const char *name,
3360 enum lsa_SidType type, const struct dom_sid *sid)
3361{
3362 refresh_sequence_number(domain);
3363 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
3364 sid, type);
3365}
3366
3367/*
3368 * The original idea that this cache only contains centries has
3369 * been blurred - now other stuff gets put in here. Ensure we
3370 * ignore these things on cleanup.
3371 */
3372
3373static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
3374 TDB_DATA dbuf, void *state)
3375{
3376 struct cache_entry *centry;
3377
3378 if (is_non_centry_key(kbuf)) {
3379 return 0;
3380 }
3381
3382 centry = wcache_fetch_raw((char *)kbuf.dptr);
3383 if (!centry) {
3384 return 0;
3385 }
3386
3387 if (!NT_STATUS_IS_OK(centry->status)) {
3388 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
3389 tdb_delete(the_tdb, kbuf);
3390 }
3391
3392 centry_free(centry);
3393 return 0;
3394}
3395
3396/* flush the cache */
3397void wcache_flush_cache(void)
3398{
3399 char *db_path;
3400
3401 if (!wcache)
3402 return;
3403 if (wcache->tdb) {
3404 tdb_close(wcache->tdb);
3405 wcache->tdb = NULL;
3406 }
3407 if (!winbindd_use_cache()) {
3408 return;
3409 }
3410
3411 db_path = state_path("winbindd_cache.tdb");
3412 if (db_path == NULL) {
3413 return;
3414 }
3415
3416 /* when working offline we must not clear the cache on restart */
3417 wcache->tdb = tdb_open_log(db_path,
3418 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3419 TDB_INCOMPATIBLE_HASH |
3420 (lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
3421 O_RDWR|O_CREAT, 0600);
3422 TALLOC_FREE(db_path);
3423 if (!wcache->tdb) {
3424 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3425 return;
3426 }
3427
3428 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
3429
3430 DEBUG(10,("wcache_flush_cache success\n"));
3431}
3432
3433/* Count cached creds */
3434
3435static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3436 void *state)
3437{
3438 int *cred_count = (int*)state;
3439
3440 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3441 (*cred_count)++;
3442 }
3443 return 0;
3444}
3445
3446NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
3447{
3448 struct winbind_cache *cache = get_cache(domain);
3449
3450 *count = 0;
3451
3452 if (!cache->tdb) {
3453 return NT_STATUS_INTERNAL_DB_ERROR;
3454 }
3455
3456 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
3457
3458 return NT_STATUS_OK;
3459}
3460
3461struct cred_list {
3462 struct cred_list *prev, *next;
3463 TDB_DATA key;
3464 fstring name;
3465 time_t created;
3466};
3467static struct cred_list *wcache_cred_list;
3468
3469static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3470 void *state)
3471{
3472 struct cred_list *cred;
3473
3474 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3475
3476 cred = SMB_MALLOC_P(struct cred_list);
3477 if (cred == NULL) {
3478 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3479 return -1;
3480 }
3481
3482 ZERO_STRUCTP(cred);
3483
3484 /* save a copy of the key */
3485
3486 fstrcpy(cred->name, (const char *)kbuf.dptr);
3487 DLIST_ADD(wcache_cred_list, cred);
3488 }
3489
3490 return 0;
3491}
3492
3493NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const struct dom_sid *sid)
3494{
3495 struct winbind_cache *cache = get_cache(domain);
3496 NTSTATUS status;
3497 int ret;
3498 struct cred_list *cred, *next, *oldest = NULL;
3499
3500 if (!cache->tdb) {
3501 return NT_STATUS_INTERNAL_DB_ERROR;
3502 }
3503
3504 /* we possibly already have an entry */
3505 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
3506
3507 fstring key_str, tmp;
3508
3509 DEBUG(11,("we already have an entry, deleting that\n"));
3510
3511 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
3512
3513 tdb_delete(cache->tdb, string_tdb_data(key_str));
3514
3515 return NT_STATUS_OK;
3516 }
3517
3518 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
3519 if (ret == 0) {
3520 return NT_STATUS_OK;
3521 } else if ((ret < 0) || (wcache_cred_list == NULL)) {
3522 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3523 }
3524
3525 ZERO_STRUCTP(oldest);
3526
3527 for (cred = wcache_cred_list; cred; cred = cred->next) {
3528
3529 TDB_DATA data;
3530 time_t t;
3531
3532 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
3533 if (!data.dptr) {
3534 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3535 cred->name));
3536 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
3537 goto done;
3538 }
3539
3540 t = IVAL(data.dptr, 0);
3541 SAFE_FREE(data.dptr);
3542
3543 if (!oldest) {
3544 oldest = SMB_MALLOC_P(struct cred_list);
3545 if (oldest == NULL) {
3546 status = NT_STATUS_NO_MEMORY;
3547 goto done;
3548 }
3549
3550 fstrcpy(oldest->name, cred->name);
3551 oldest->created = t;
3552 continue;
3553 }
3554
3555 if (t < oldest->created) {
3556 fstrcpy(oldest->name, cred->name);
3557 oldest->created = t;
3558 }
3559 }
3560
3561 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
3562 status = NT_STATUS_OK;
3563 } else {
3564 status = NT_STATUS_UNSUCCESSFUL;
3565 }
3566done:
3567 for (cred = wcache_cred_list; cred; cred = next) {
3568 next = cred->next;
3569 DLIST_REMOVE(wcache_cred_list, cred);
3570 SAFE_FREE(cred);
3571 }
3572 SAFE_FREE(oldest);
3573
3574 return status;
3575}
3576
3577/* Change the global online/offline state. */
3578bool set_global_winbindd_state_offline(void)
3579{
3580 TDB_DATA data;
3581
3582 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3583
3584 /* Only go offline if someone has created
3585 the key "WINBINDD_OFFLINE" in the cache tdb. */
3586
3587 if (wcache == NULL || wcache->tdb == NULL) {
3588 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3589 return false;
3590 }
3591
3592 if (!lp_winbind_offline_logon()) {
3593 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3594 return false;
3595 }
3596
3597 if (global_winbindd_offline_state) {
3598 /* Already offline. */
3599 return true;
3600 }
3601
3602 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
3603
3604 if (!data.dptr || data.dsize != 4) {
3605 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3606 SAFE_FREE(data.dptr);
3607 return false;
3608 } else {
3609 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3610 global_winbindd_offline_state = true;
3611 SAFE_FREE(data.dptr);
3612 return true;
3613 }
3614}
3615
3616void set_global_winbindd_state_online(void)
3617{
3618 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3619
3620 if (!lp_winbind_offline_logon()) {
3621 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3622 return;
3623 }
3624
3625 if (!global_winbindd_offline_state) {
3626 /* Already online. */
3627 return;
3628 }
3629 global_winbindd_offline_state = false;
3630
3631 if (!wcache->tdb) {
3632 return;
3633 }
3634
3635 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3636 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
3637}
3638
3639bool get_global_winbindd_state_offline(void)
3640{
3641 return global_winbindd_offline_state;
3642}
3643
3644/***********************************************************************
3645 Validate functions for all possible cache tdb keys.
3646***********************************************************************/
3647
3648static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
3649 struct tdb_validation_status *state)
3650{
3651 struct cache_entry *centry;
3652
3653 centry = SMB_XMALLOC_P(struct cache_entry);
3654 centry->data = (unsigned char *)smb_memdup(data.dptr, data.dsize);
3655 if (!centry->data) {
3656 SAFE_FREE(centry);
3657 return NULL;
3658 }
3659 centry->len = data.dsize;
3660 centry->ofs = 0;
3661
3662 if (centry->len < 16) {
3663 /* huh? corrupt cache? */
3664 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3665 "(len < 16) ?\n", kstr));
3666 centry_free(centry);
3667 state->bad_entry = true;
3668 state->success = false;
3669 return NULL;
3670 }
3671
3672 centry->status = NT_STATUS(centry_uint32(centry));
3673 centry->sequence_number = centry_uint32(centry);
3674 centry->timeout = centry_uint64_t(centry);
3675 return centry;
3676}
3677
3678static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3679 struct tdb_validation_status *state)
3680{
3681 if (dbuf.dsize != 8) {
3682 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3683 keystr, (unsigned int)dbuf.dsize ));
3684 state->bad_entry = true;
3685 return 1;
3686 }
3687 return 0;
3688}
3689
3690static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3691 struct tdb_validation_status *state)
3692{
3693 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3694 if (!centry) {
3695 return 1;
3696 }
3697
3698 (void)centry_uint32(centry);
3699 if (NT_STATUS_IS_OK(centry->status)) {
3700 struct dom_sid sid;
3701 (void)centry_sid(centry, &sid);
3702 }
3703
3704 centry_free(centry);
3705
3706 if (!(state->success)) {
3707 return 1;
3708 }
3709 DEBUG(10,("validate_ns: %s ok\n", keystr));
3710 return 0;
3711}
3712
3713static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3714 struct tdb_validation_status *state)
3715{
3716 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3717 if (!centry) {
3718 return 1;
3719 }
3720
3721 if (NT_STATUS_IS_OK(centry->status)) {
3722 (void)centry_uint32(centry);
3723 (void)centry_string(centry, mem_ctx);
3724 (void)centry_string(centry, mem_ctx);
3725 }
3726
3727 centry_free(centry);
3728
3729 if (!(state->success)) {
3730 return 1;
3731 }
3732 DEBUG(10,("validate_sn: %s ok\n", keystr));
3733 return 0;
3734}
3735
3736static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3737 struct tdb_validation_status *state)
3738{
3739 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3740 struct dom_sid sid;
3741
3742 if (!centry) {
3743 return 1;
3744 }
3745
3746 (void)centry_string(centry, mem_ctx);
3747 (void)centry_string(centry, mem_ctx);
3748 (void)centry_string(centry, mem_ctx);
3749 (void)centry_string(centry, mem_ctx);
3750 (void)centry_uint32(centry);
3751 (void)centry_sid(centry, &sid);
3752 (void)centry_sid(centry, &sid);
3753
3754 centry_free(centry);
3755
3756 if (!(state->success)) {
3757 return 1;
3758 }
3759 DEBUG(10,("validate_u: %s ok\n", keystr));
3760 return 0;
3761}
3762
3763static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3764 struct tdb_validation_status *state)
3765{
3766 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3767
3768 if (!centry) {
3769 return 1;
3770 }
3771
3772 (void)centry_nttime(centry);
3773 (void)centry_nttime(centry);
3774 (void)centry_uint16(centry);
3775
3776 centry_free(centry);
3777
3778 if (!(state->success)) {
3779 return 1;
3780 }
3781 DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
3782 return 0;
3783}
3784
3785static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3786 struct tdb_validation_status *state)
3787{
3788 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3789
3790 if (!centry) {
3791 return 1;
3792 }
3793
3794 (void)centry_uint16(centry);
3795 (void)centry_uint16(centry);
3796 (void)centry_uint32(centry);
3797 (void)centry_nttime(centry);
3798 (void)centry_nttime(centry);
3799
3800 centry_free(centry);
3801
3802 if (!(state->success)) {
3803 return 1;
3804 }
3805 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
3806 return 0;
3807}
3808
3809static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3810 struct tdb_validation_status *state)
3811{
3812 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3813
3814 if (!centry) {
3815 return 1;
3816 }
3817
3818 (void)centry_time(centry);
3819 (void)centry_hash16(centry, mem_ctx);
3820
3821 /* We only have 17 bytes more data in the salted cred case. */
3822 if (centry->len - centry->ofs == 17) {
3823 (void)centry_hash16(centry, mem_ctx);
3824 }
3825
3826 centry_free(centry);
3827
3828 if (!(state->success)) {
3829 return 1;
3830 }
3831 DEBUG(10,("validate_cred: %s ok\n", keystr));
3832 return 0;
3833}
3834
3835static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3836 struct tdb_validation_status *state)
3837{
3838 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3839 int32_t num_entries, i;
3840
3841 if (!centry) {
3842 return 1;
3843 }
3844
3845 num_entries = (int32_t)centry_uint32(centry);
3846
3847 for (i=0; i< num_entries; i++) {
3848 struct dom_sid sid;
3849 (void)centry_string(centry, mem_ctx);
3850 (void)centry_string(centry, mem_ctx);
3851 (void)centry_string(centry, mem_ctx);
3852 (void)centry_string(centry, mem_ctx);
3853 (void)centry_sid(centry, &sid);
3854 (void)centry_sid(centry, &sid);
3855 }
3856
3857 centry_free(centry);
3858
3859 if (!(state->success)) {
3860 return 1;
3861 }
3862 DEBUG(10,("validate_ul: %s ok\n", keystr));
3863 return 0;
3864}
3865
3866static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3867 struct tdb_validation_status *state)
3868{
3869 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3870 int32_t num_entries, i;
3871
3872 if (!centry) {
3873 return 1;
3874 }
3875
3876 num_entries = centry_uint32(centry);
3877
3878 for (i=0; i< num_entries; i++) {
3879 (void)centry_string(centry, mem_ctx);
3880 (void)centry_string(centry, mem_ctx);
3881 (void)centry_uint32(centry);
3882 }
3883
3884 centry_free(centry);
3885
3886 if (!(state->success)) {
3887 return 1;
3888 }
3889 DEBUG(10,("validate_gl: %s ok\n", keystr));
3890 return 0;
3891}
3892
3893static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3894 struct tdb_validation_status *state)
3895{
3896 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3897 int32_t num_groups, i;
3898
3899 if (!centry) {
3900 return 1;
3901 }
3902
3903 num_groups = centry_uint32(centry);
3904
3905 for (i=0; i< num_groups; i++) {
3906 struct dom_sid sid;
3907 centry_sid(centry, &sid);
3908 }
3909
3910 centry_free(centry);
3911
3912 if (!(state->success)) {
3913 return 1;
3914 }
3915 DEBUG(10,("validate_ug: %s ok\n", keystr));
3916 return 0;
3917}
3918
3919static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3920 struct tdb_validation_status *state)
3921{
3922 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3923 int32_t num_aliases, i;
3924
3925 if (!centry) {
3926 return 1;
3927 }
3928
3929 num_aliases = centry_uint32(centry);
3930
3931 for (i=0; i < num_aliases; i++) {
3932 (void)centry_uint32(centry);
3933 }
3934
3935 centry_free(centry);
3936
3937 if (!(state->success)) {
3938 return 1;
3939 }
3940 DEBUG(10,("validate_ua: %s ok\n", keystr));
3941 return 0;
3942}
3943
3944static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3945 struct tdb_validation_status *state)
3946{
3947 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3948 int32_t num_names, i;
3949
3950 if (!centry) {
3951 return 1;
3952 }
3953
3954 num_names = centry_uint32(centry);
3955
3956 for (i=0; i< num_names; i++) {
3957 struct dom_sid sid;
3958 centry_sid(centry, &sid);
3959 (void)centry_string(centry, mem_ctx);
3960 (void)centry_uint32(centry);
3961 }
3962
3963 centry_free(centry);
3964
3965 if (!(state->success)) {
3966 return 1;
3967 }
3968 DEBUG(10,("validate_gm: %s ok\n", keystr));
3969 return 0;
3970}
3971
3972static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3973 struct tdb_validation_status *state)
3974{
3975 /* Can't say anything about this other than must be nonzero. */
3976 if (dbuf.dsize == 0) {
3977 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3978 keystr));
3979 state->bad_entry = true;
3980 state->success = false;
3981 return 1;
3982 }
3983
3984 DEBUG(10,("validate_dr: %s ok\n", keystr));
3985 return 0;
3986}
3987
3988static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3989 struct tdb_validation_status *state)
3990{
3991 /* Can't say anything about this other than must be nonzero. */
3992 if (dbuf.dsize == 0) {
3993 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3994 keystr));
3995 state->bad_entry = true;
3996 state->success = false;
3997 return 1;
3998 }
3999
4000 DEBUG(10,("validate_de: %s ok\n", keystr));
4001 return 0;
4002}
4003
4004static int validate_pwinfo(TALLOC_CTX *mem_ctx, const char *keystr,
4005 TDB_DATA dbuf, struct tdb_validation_status *state)
4006{
4007 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
4008
4009 if (!centry) {
4010 return 1;
4011 }
4012
4013 (void)centry_string(centry, mem_ctx);
4014 (void)centry_string(centry, mem_ctx);
4015 (void)centry_string(centry, mem_ctx);
4016 (void)centry_uint32(centry);
4017
4018 centry_free(centry);
4019
4020 if (!(state->success)) {
4021 return 1;
4022 }
4023 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
4024 return 0;
4025}
4026
4027static int validate_nss_an(TALLOC_CTX *mem_ctx, const char *keystr,
4028 TDB_DATA dbuf,
4029 struct tdb_validation_status *state)
4030{
4031 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
4032
4033 if (!centry) {
4034 return 1;
4035 }
4036
4037 (void)centry_string( centry, mem_ctx );
4038
4039 centry_free(centry);
4040
4041 if (!(state->success)) {
4042 return 1;
4043 }
4044 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
4045 return 0;
4046}
4047
4048static int validate_nss_na(TALLOC_CTX *mem_ctx, const char *keystr,
4049 TDB_DATA dbuf,
4050 struct tdb_validation_status *state)
4051{
4052 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
4053
4054 if (!centry) {
4055 return 1;
4056 }
4057
4058 (void)centry_string( centry, mem_ctx );
4059
4060 centry_free(centry);
4061
4062 if (!(state->success)) {
4063 return 1;
4064 }
4065 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
4066 return 0;
4067}
4068
4069static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
4070 TDB_DATA dbuf,
4071 struct tdb_validation_status *state)
4072{
4073 if (dbuf.dsize == 0) {
4074 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
4075 "key %s (len ==0) ?\n", keystr));
4076 state->bad_entry = true;
4077 state->success = false;
4078 return 1;
4079 }
4080
4081 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
4082 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
4083 return 0;
4084}
4085
4086static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
4087 struct tdb_validation_status *state)
4088{
4089 if (dbuf.dsize != 4) {
4090 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
4091 keystr, (unsigned int)dbuf.dsize ));
4092 state->bad_entry = true;
4093 state->success = false;
4094 return 1;
4095 }
4096 DEBUG(10,("validate_offline: %s ok\n", keystr));
4097 return 0;
4098}
4099
4100static int validate_ndr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
4101 struct tdb_validation_status *state)
4102{
4103 /*
4104 * Ignore validation for now. The proper way to do this is with a
4105 * checksum. Just pure parsing does not really catch much.
4106 */
4107 return 0;
4108}
4109
4110static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
4111 struct tdb_validation_status *state)
4112{
4113 if (dbuf.dsize != 4) {
4114 DEBUG(0, ("validate_cache_version: Corrupt cache for "
4115 "key %s (len %u != 4) ?\n",
4116 keystr, (unsigned int)dbuf.dsize));
4117 state->bad_entry = true;
4118 state->success = false;
4119 return 1;
4120 }
4121
4122 DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
4123 return 0;
4124}
4125
4126/***********************************************************************
4127 A list of all possible cache tdb keys with associated validation
4128 functions.
4129***********************************************************************/
4130
4131struct key_val_struct {
4132 const char *keyname;
4133 int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
4134} key_val[] = {
4135 {"SEQNUM/", validate_seqnum},
4136 {"NS/", validate_ns},
4137 {"SN/", validate_sn},
4138 {"U/", validate_u},
4139 {"LOC_POL/", validate_loc_pol},
4140 {"PWD_POL/", validate_pwd_pol},
4141 {"CRED/", validate_cred},
4142 {"UL/", validate_ul},
4143 {"GL/", validate_gl},
4144 {"UG/", validate_ug},
4145 {"UA", validate_ua},
4146 {"GM/", validate_gm},
4147 {"DR/", validate_dr},
4148 {"DE/", validate_de},
4149 {"NSS/PWINFO/", validate_pwinfo},
4150 {"TRUSTDOMCACHE/", validate_trustdomcache},
4151 {"NSS/NA/", validate_nss_na},
4152 {"NSS/AN/", validate_nss_an},
4153 {"WINBINDD_OFFLINE", validate_offline},
4154 {"NDR/", validate_ndr},
4155 {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
4156 {NULL, NULL}
4157};
4158
4159/***********************************************************************
4160 Function to look at every entry in the tdb and validate it as far as
4161 possible.
4162***********************************************************************/
4163
4164static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
4165{
4166 int i;
4167 unsigned int max_key_len = 1024;
4168 struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
4169
4170 /* Paranoia check. */
4171 if (strncmp("UA/", (const char *)kbuf.dptr, 3) == 0 ||
4172 strncmp("NDR/", (const char *)kbuf.dptr, 4) == 0) {
4173 max_key_len = 1024 * 1024;
4174 }
4175 if (kbuf.dsize > max_key_len) {
4176 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4177 "(%u) > (%u)\n\n",
4178 (unsigned int)kbuf.dsize, (unsigned int)max_key_len));
4179 return 1;
4180 }
4181
4182 for (i = 0; key_val[i].keyname; i++) {
4183 size_t namelen = strlen(key_val[i].keyname);
4184 if (kbuf.dsize >= namelen && (
4185 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
4186 TALLOC_CTX *mem_ctx;
4187 char *keystr;
4188 int ret;
4189
4190 keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
4191 if (!keystr) {
4192 return 1;
4193 }
4194 memcpy(keystr, kbuf.dptr, kbuf.dsize);
4195 keystr[kbuf.dsize] = '\0';
4196
4197 mem_ctx = talloc_init("validate_ctx");
4198 if (!mem_ctx) {
4199 SAFE_FREE(keystr);
4200 return 1;
4201 }
4202
4203 ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
4204 v_state);
4205
4206 SAFE_FREE(keystr);
4207 talloc_destroy(mem_ctx);
4208 return ret;
4209 }
4210 }
4211
4212 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4213 dump_data(0, (uint8_t *)kbuf.dptr, kbuf.dsize);
4214 DEBUG(0,("data :\n"));
4215 dump_data(0, (uint8_t *)dbuf.dptr, dbuf.dsize);
4216 v_state->unknown_key = true;
4217 v_state->success = false;
4218 return 1; /* terminate. */
4219}
4220
4221static void validate_panic(const char *const why)
4222{
4223 DEBUG(0,("validating cache: would panic %s\n", why ));
4224 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4225 exit(47);
4226}
4227
4228static int wbcache_update_centry_fn(TDB_CONTEXT *tdb,
4229 TDB_DATA key,
4230 TDB_DATA data,
4231 void *state)
4232{
4233 uint64_t ctimeout;
4234 TDB_DATA blob;
4235
4236 if (is_non_centry_key(key)) {
4237 return 0;
4238 }
4239
4240 if (data.dptr == NULL || data.dsize == 0) {
4241 if (tdb_delete(tdb, key) < 0) {
4242 DEBUG(0, ("tdb_delete for [%s] failed!\n",
4243 key.dptr));
4244 return 1;
4245 }
4246 }
4247
4248 /* add timeout to blob (uint64_t) */
4249 blob.dsize = data.dsize + 8;
4250
4251 blob.dptr = SMB_XMALLOC_ARRAY(uint8_t, blob.dsize);
4252 if (blob.dptr == NULL) {
4253 return 1;
4254 }
4255 memset(blob.dptr, 0, blob.dsize);
4256
4257 /* copy status and seqnum */
4258 memcpy(blob.dptr, data.dptr, 8);
4259
4260 /* add timeout */
4261 ctimeout = lp_winbind_cache_time() + time(NULL);
4262 SBVAL(blob.dptr, 8, ctimeout);
4263
4264 /* copy the rest */
4265 memcpy(blob.dptr + 16, data.dptr + 8, data.dsize - 8);
4266
4267 if (tdb_store(tdb, key, blob, TDB_REPLACE) < 0) {
4268 DEBUG(0, ("tdb_store to update [%s] failed!\n",
4269 key.dptr));
4270 SAFE_FREE(blob.dptr);
4271 return 1;
4272 }
4273
4274 SAFE_FREE(blob.dptr);
4275 return 0;
4276}
4277
4278static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT *tdb)
4279{
4280 int rc;
4281
4282 DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
4283
4284 rc = tdb_traverse(tdb, wbcache_update_centry_fn, NULL);
4285 if (rc < 0) {
4286 return false;
4287 }
4288
4289 return true;
4290}
4291
4292/***********************************************************************
4293 Try and validate every entry in the winbindd cache. If we fail here,
4294 delete the cache tdb and return non-zero.
4295***********************************************************************/
4296
4297int winbindd_validate_cache(void)
4298{
4299 int ret = -1;
4300 char *tdb_path = NULL;
4301 TDB_CONTEXT *tdb = NULL;
4302 uint32_t vers_id;
4303 bool ok;
4304
4305 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4306 smb_panic_fn = validate_panic;
4307
4308 tdb_path = state_path("winbindd_cache.tdb");
4309 if (tdb_path == NULL) {
4310 goto done;
4311 }
4312
4313 tdb = tdb_open_log(tdb_path,
4314 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
4315 TDB_INCOMPATIBLE_HASH |
4316 ( lp_winbind_offline_logon()
4317 ? TDB_DEFAULT
4318 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
4319 O_RDWR|O_CREAT,
4320 0600);
4321 if (!tdb) {
4322 DEBUG(0, ("winbindd_validate_cache: "
4323 "error opening/initializing tdb\n"));
4324 goto done;
4325 }
4326
4327 /* Version check and upgrade code. */
4328 if (!tdb_fetch_uint32(tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers_id)) {
4329 DEBUG(10, ("Fresh database\n"));
4330 tdb_store_uint32(tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION);
4331 vers_id = WINBINDD_CACHE_VERSION;
4332 }
4333
4334 if (vers_id != WINBINDD_CACHE_VERSION) {
4335 if (vers_id == WINBINDD_CACHE_VER1) {
4336 ok = wbcache_upgrade_v1_to_v2(tdb);
4337 if (!ok) {
4338 DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
4339 unlink(tdb_path);
4340 goto done;
4341 }
4342
4343 tdb_store_uint32(tdb,
4344 WINBINDD_CACHE_VERSION_KEYSTR,
4345 WINBINDD_CACHE_VERSION);
4346 vers_id = WINBINDD_CACHE_VER2;
4347 }
4348 }
4349
4350 tdb_close(tdb);
4351
4352 ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
4353
4354 if (ret != 0) {
4355 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4356 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
4357 unlink(tdb_path);
4358 }
4359
4360done:
4361 TALLOC_FREE(tdb_path);
4362 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4363 smb_panic_fn = smb_panic;
4364 return ret;
4365}
4366
4367/***********************************************************************
4368 Try and validate every entry in the winbindd cache.
4369***********************************************************************/
4370
4371int winbindd_validate_cache_nobackup(void)
4372{
4373 int ret = -1;
4374 char *tdb_path;
4375
4376 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4377 smb_panic_fn = validate_panic;
4378
4379 tdb_path = state_path("winbindd_cache.tdb");
4380 if (tdb_path == NULL) {
4381 goto err_panic_restore;
4382 }
4383
4384 if (wcache == NULL || wcache->tdb == NULL) {
4385 ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
4386 } else {
4387 ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
4388 }
4389
4390 if (ret != 0) {
4391 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4392 "successful.\n"));
4393 }
4394
4395 TALLOC_FREE(tdb_path);
4396err_panic_restore:
4397 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4398 "function\n"));
4399 smb_panic_fn = smb_panic;
4400 return ret;
4401}
4402
4403bool winbindd_cache_validate_and_initialize(void)
4404{
4405 close_winbindd_cache();
4406
4407 if (lp_winbind_offline_logon()) {
4408 if (winbindd_validate_cache() < 0) {
4409 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4410 "could be restored.\n"));
4411 }
4412 }
4413
4414 return initialize_winbindd_cache();
4415}
4416
4417/*********************************************************************
4418 ********************************************************************/
4419
4420static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
4421 struct winbindd_tdc_domain **domains,
4422 size_t *num_domains )
4423{
4424 struct winbindd_tdc_domain *list = NULL;
4425 size_t idx;
4426 int i;
4427 bool set_only = false;
4428
4429 /* don't allow duplicates */
4430
4431 idx = *num_domains;
4432 list = *domains;
4433
4434 for ( i=0; i< (*num_domains); i++ ) {
4435 if ( strequal( new_dom->name, list[i].domain_name ) ) {
4436 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4437 new_dom->name));
4438 idx = i;
4439 set_only = true;
4440
4441 break;
4442 }
4443 }
4444
4445 if ( !set_only ) {
4446 if ( !*domains ) {
4447 list = talloc_array( NULL, struct winbindd_tdc_domain, 1 );
4448 idx = 0;
4449 } else {
4450 list = talloc_realloc( *domains, *domains,
4451 struct winbindd_tdc_domain,
4452 (*num_domains)+1);
4453 idx = *num_domains;
4454 }
4455
4456 ZERO_STRUCT( list[idx] );
4457 }
4458
4459 if ( !list )
4460 return false;
4461
4462 list[idx].domain_name = talloc_strdup(list, new_dom->name);
4463 if (list[idx].domain_name == NULL) {
4464 return false;
4465 }
4466 if (new_dom->alt_name != NULL) {
4467 list[idx].dns_name = talloc_strdup(list, new_dom->alt_name);
4468 if (list[idx].dns_name == NULL) {
4469 return false;
4470 }
4471 }
4472
4473 if ( !is_null_sid( &new_dom->sid ) ) {
4474 sid_copy( &list[idx].sid, &new_dom->sid );
4475 } else {
4476 sid_copy(&list[idx].sid, &global_sid_NULL);
4477 }
4478
4479 if ( new_dom->domain_flags != 0x0 )
4480 list[idx].trust_flags = new_dom->domain_flags;
4481
4482 if ( new_dom->domain_type != 0x0 )
4483 list[idx].trust_type = new_dom->domain_type;
4484
4485 if ( new_dom->domain_trust_attribs != 0x0 )
4486 list[idx].trust_attribs = new_dom->domain_trust_attribs;
4487
4488 if ( !set_only ) {
4489 *domains = list;
4490 *num_domains = idx + 1;
4491 }
4492
4493 return true;
4494}
4495
4496/*********************************************************************
4497 ********************************************************************/
4498
4499static TDB_DATA make_tdc_key( const char *domain_name )
4500{
4501 char *keystr = NULL;
4502 TDB_DATA key = { NULL, 0 };
4503
4504 if ( !domain_name ) {
4505 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4506 return key;
4507 }
4508
4509 if (asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name ) == -1) {
4510 return key;
4511 }
4512 key = string_term_tdb_data(keystr);
4513
4514 return key;
4515}
4516
4517/*********************************************************************
4518 ********************************************************************/
4519
4520static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
4521 size_t num_domains,
4522 unsigned char **buf )
4523{
4524 unsigned char *buffer = NULL;
4525 int len = 0;
4526 int buflen = 0;
4527 int i = 0;
4528
4529 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4530 (int)num_domains));
4531
4532 buflen = 0;
4533
4534 again:
4535 len = 0;
4536
4537 /* Store the number of array items first */
4538 len += tdb_pack( buffer+len, buflen-len, "d",
4539 num_domains );
4540
4541 /* now pack each domain trust record */
4542 for ( i=0; i<num_domains; i++ ) {
4543
4544 fstring tmp;
4545
4546 if ( buflen > 0 ) {
4547 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4548 domains[i].domain_name,
4549 domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
4550 }
4551
4552 len += tdb_pack( buffer+len, buflen-len, "fffddd",
4553 domains[i].domain_name,
4554 domains[i].dns_name ? domains[i].dns_name : "",
4555 sid_to_fstring(tmp, &domains[i].sid),
4556 domains[i].trust_flags,
4557 domains[i].trust_attribs,
4558 domains[i].trust_type );
4559 }
4560
4561 if ( buflen < len ) {
4562 SAFE_FREE(buffer);
4563 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
4564 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4565 buflen = -1;
4566 goto done;
4567 }
4568 buflen = len;
4569 goto again;
4570 }
4571
4572 *buf = buffer;
4573
4574 done:
4575 return buflen;
4576}
4577
4578/*********************************************************************
4579 ********************************************************************/
4580
4581static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
4582 struct winbindd_tdc_domain **domains )
4583{
4584 fstring domain_name, dns_name, sid_string;
4585 uint32_t type, attribs, flags;
4586 int num_domains;
4587 int len = 0;
4588 int i;
4589 struct winbindd_tdc_domain *list = NULL;
4590
4591 /* get the number of domains */
4592 len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
4593 if ( len == -1 ) {
4594 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4595 return 0;
4596 }
4597
4598 list = talloc_array( NULL, struct winbindd_tdc_domain, num_domains );
4599 if ( !list ) {
4600 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4601 return 0;
4602 }
4603
4604 for ( i=0; i<num_domains; i++ ) {
4605 int this_len;
4606
4607 this_len = tdb_unpack( buf+len, buflen-len, "fffddd",
4608 domain_name,
4609 dns_name,
4610 sid_string,
4611 &flags,
4612 &attribs,
4613 &type );
4614
4615 if ( this_len == -1 ) {
4616 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4617 TALLOC_FREE( list );
4618 return 0;
4619 }
4620 len += this_len;
4621
4622 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4623 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4624 domain_name, dns_name, sid_string,
4625 flags, attribs, type));
4626
4627 list[i].domain_name = talloc_strdup( list, domain_name );
4628 list[i].dns_name = NULL;
4629 if (dns_name[0] != '\0') {
4630 list[i].dns_name = talloc_strdup(list, dns_name);
4631 }
4632 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
4633 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4634 domain_name));
4635 }
4636 list[i].trust_flags = flags;
4637 list[i].trust_attribs = attribs;
4638 list[i].trust_type = type;
4639 }
4640
4641 *domains = list;
4642
4643 return num_domains;
4644}
4645
4646/*********************************************************************
4647 ********************************************************************/
4648
4649static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
4650{
4651 TDB_DATA key = make_tdc_key( lp_workgroup() );
4652 TDB_DATA data = { NULL, 0 };
4653 int ret;
4654
4655 if ( !key.dptr )
4656 return false;
4657
4658 /* See if we were asked to delete the cache entry */
4659
4660 if ( !domains ) {
4661 ret = tdb_delete( wcache->tdb, key );
4662 goto done;
4663 }
4664
4665 data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
4666
4667 if ( !data.dptr ) {
4668 ret = -1;
4669 goto done;
4670 }
4671
4672 ret = tdb_store( wcache->tdb, key, data, 0 );
4673
4674 done:
4675 SAFE_FREE( data.dptr );
4676 SAFE_FREE( key.dptr );
4677
4678 return ( ret == 0 );
4679}
4680
4681/*********************************************************************
4682 ********************************************************************/
4683
4684bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
4685{
4686 TDB_DATA key = make_tdc_key( lp_workgroup() );
4687 TDB_DATA data = { NULL, 0 };
4688
4689 *domains = NULL;
4690 *num_domains = 0;
4691
4692 if ( !key.dptr )
4693 return false;
4694
4695 data = tdb_fetch( wcache->tdb, key );
4696
4697 SAFE_FREE( key.dptr );
4698
4699 if ( !data.dptr )
4700 return false;
4701
4702 *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
4703
4704 SAFE_FREE( data.dptr );
4705
4706 if ( !*domains )
4707 return false;
4708
4709 return true;
4710}
4711
4712/*********************************************************************
4713 ********************************************************************/
4714
4715bool wcache_tdc_add_domain( struct winbindd_domain *domain )
4716{
4717 struct winbindd_tdc_domain *dom_list = NULL;
4718 size_t num_domains = 0;
4719 bool ret = false;
4720
4721 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4722 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4723 domain->name, domain->alt_name,
4724 sid_string_dbg(&domain->sid),
4725 domain->domain_flags,
4726 domain->domain_trust_attribs,
4727 domain->domain_type));
4728
4729 if ( !init_wcache() ) {
4730 return false;
4731 }
4732
4733 /* fetch the list */
4734
4735 wcache_tdc_fetch_list( &dom_list, &num_domains );
4736
4737 /* add the new domain */
4738
4739 if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
4740 goto done;
4741 }
4742
4743 /* pack the domain */
4744
4745 if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
4746 goto done;
4747 }
4748
4749 /* Success */
4750
4751 ret = true;
4752 done:
4753 TALLOC_FREE( dom_list );
4754
4755 return ret;
4756}
4757
4758static struct winbindd_tdc_domain *wcache_tdc_dup_domain(
4759 TALLOC_CTX *mem_ctx, const struct winbindd_tdc_domain *src)
4760{
4761 struct winbindd_tdc_domain *dst;
4762
4763 dst = talloc(mem_ctx, struct winbindd_tdc_domain);
4764 if (dst == NULL) {
4765 goto fail;
4766 }
4767 dst->domain_name = talloc_strdup(dst, src->domain_name);
4768 if (dst->domain_name == NULL) {
4769 goto fail;
4770 }
4771
4772 dst->dns_name = NULL;
4773 if (src->dns_name != NULL) {
4774 dst->dns_name = talloc_strdup(dst, src->dns_name);
4775 if (dst->dns_name == NULL) {
4776 goto fail;
4777 }
4778 }
4779
4780 sid_copy(&dst->sid, &src->sid);
4781 dst->trust_flags = src->trust_flags;
4782 dst->trust_type = src->trust_type;
4783 dst->trust_attribs = src->trust_attribs;
4784 return dst;
4785fail:
4786 TALLOC_FREE(dst);
4787 return NULL;
4788}
4789
4790/*********************************************************************
4791 ********************************************************************/
4792
4793struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
4794{
4795 struct winbindd_tdc_domain *dom_list = NULL;
4796 size_t num_domains = 0;
4797 int i;
4798 struct winbindd_tdc_domain *d = NULL;
4799
4800 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
4801
4802 if ( !init_wcache() ) {
4803 return NULL;
4804 }
4805
4806 /* fetch the list */
4807
4808 wcache_tdc_fetch_list( &dom_list, &num_domains );
4809
4810 for ( i=0; i<num_domains; i++ ) {
4811 if ( strequal(name, dom_list[i].domain_name) ||
4812 strequal(name, dom_list[i].dns_name) )
4813 {
4814 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4815 name));
4816
4817 d = wcache_tdc_dup_domain(ctx, &dom_list[i]);
4818 break;
4819 }
4820 }
4821
4822 TALLOC_FREE( dom_list );
4823
4824 return d;
4825}
4826
4827/*********************************************************************
4828 ********************************************************************/
4829
4830struct winbindd_tdc_domain*
4831 wcache_tdc_fetch_domainbysid(TALLOC_CTX *ctx,
4832 const struct dom_sid *sid)
4833{
4834 struct winbindd_tdc_domain *dom_list = NULL;
4835 size_t num_domains = 0;
4836 int i;
4837 struct winbindd_tdc_domain *d = NULL;
4838
4839 DEBUG(10,("wcache_tdc_fetch_domainbysid: Searching for domain %s\n",
4840 sid_string_dbg(sid)));
4841
4842 if (!init_wcache()) {
4843 return NULL;
4844 }
4845
4846 /* fetch the list */
4847
4848 wcache_tdc_fetch_list(&dom_list, &num_domains);
4849
4850 for (i = 0; i<num_domains; i++) {
4851 if (dom_sid_equal(sid, &(dom_list[i].sid))) {
4852 DEBUG(10, ("wcache_tdc_fetch_domainbysid: "
4853 "Found domain %s for SID %s\n",
4854 dom_list[i].domain_name,
4855 sid_string_dbg(sid)));
4856
4857 d = wcache_tdc_dup_domain(ctx, &dom_list[i]);
4858 break;
4859 }
4860 }
4861
4862 TALLOC_FREE(dom_list);
4863
4864 return d;
4865}
4866
4867
4868/*********************************************************************
4869 ********************************************************************/
4870
4871void wcache_tdc_clear( void )
4872{
4873 if ( !init_wcache() )
4874 return;
4875
4876 wcache_tdc_store_list( NULL, 0 );
4877
4878 return;
4879}
4880
4881
4882/*********************************************************************
4883 ********************************************************************/
4884
4885static void wcache_save_user_pwinfo(struct winbindd_domain *domain,
4886 NTSTATUS status,
4887 const struct dom_sid *user_sid,
4888 const char *homedir,
4889 const char *shell,
4890 const char *gecos,
4891 uint32_t gid)
4892{
4893 struct cache_entry *centry;
4894 fstring tmp;
4895
4896 if ( (centry = centry_start(domain, status)) == NULL )
4897 return;
4898
4899 centry_put_string( centry, homedir );
4900 centry_put_string( centry, shell );
4901 centry_put_string( centry, gecos );
4902 centry_put_uint32( centry, gid );
4903
4904 centry_end(centry, "NSS/PWINFO/%s", sid_to_fstring(tmp, user_sid) );
4905
4906 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid) ));
4907
4908 centry_free(centry);
4909}
4910
4911#ifdef HAVE_ADS
4912
4913NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
4914 const struct dom_sid *user_sid,
4915 TALLOC_CTX *ctx,
4916 const char **homedir, const char **shell,
4917 const char **gecos, gid_t *p_gid)
4918{
4919 struct winbind_cache *cache = get_cache(domain);
4920 struct cache_entry *centry = NULL;
4921 NTSTATUS nt_status;
4922 fstring tmp;
4923
4924 if (!cache->tdb)
4925 goto do_query;
4926
4927 centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s",
4928 sid_to_fstring(tmp, user_sid));
4929
4930 if (!centry)
4931 goto do_query;
4932
4933 *homedir = centry_string( centry, ctx );
4934 *shell = centry_string( centry, ctx );
4935 *gecos = centry_string( centry, ctx );
4936 *p_gid = centry_uint32( centry );
4937
4938 centry_free(centry);
4939
4940 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4941 sid_string_dbg(user_sid)));
4942
4943 return NT_STATUS_OK;
4944
4945do_query:
4946
4947 nt_status = nss_get_info( domain->name, user_sid, ctx,
4948 homedir, shell, gecos, p_gid );
4949
4950 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status)));
4951
4952 if ( NT_STATUS_IS_OK(nt_status) ) {
4953 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir));
4954 DEBUGADD(10, ("\tshell = '%s'\n", *shell));
4955 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos));
4956 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid));
4957
4958 wcache_save_user_pwinfo( domain, nt_status, user_sid,
4959 *homedir, *shell, *gecos, *p_gid );
4960 }
4961
4962 if ( NT_STATUS_EQUAL( nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
4963 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4964 domain->name ));
4965 set_domain_offline( domain );
4966 }
4967
4968 return nt_status;
4969}
4970
4971#endif
4972
4973/* the cache backend methods are exposed via this structure */
4974struct winbindd_methods cache_methods = {
4975 true,
4976 query_user_list,
4977 enum_dom_groups,
4978 enum_local_groups,
4979 name_to_sid,
4980 sid_to_name,
4981 rids_to_names,
4982 query_user,
4983 lookup_usergroups,
4984 lookup_useraliases,
4985 lookup_groupmem,
4986 sequence_number,
4987 lockout_policy,
4988 password_policy,
4989 trusted_domains
4990};
4991
4992static bool wcache_ndr_key(TALLOC_CTX *mem_ctx, const char *domain_name,
4993 uint32_t opnum, const DATA_BLOB *req,
4994 TDB_DATA *pkey)
4995{
4996 char *key;
4997 size_t keylen;
4998
4999 key = talloc_asprintf(mem_ctx, "NDR/%s/%d/", domain_name, (int)opnum);
5000 if (key == NULL) {
5001 return false;
5002 }
5003 keylen = talloc_get_size(key) - 1;
5004
5005 key = talloc_realloc(mem_ctx, key, char, keylen + req->length);
5006 if (key == NULL) {
5007 return false;
5008 }
5009 memcpy(key + keylen, req->data, req->length);
5010
5011 pkey->dptr = (uint8_t *)key;
5012 pkey->dsize = talloc_get_size(key);
5013 return true;
5014}
5015
5016static bool wcache_opnum_cacheable(uint32_t opnum)
5017{
5018 switch (opnum) {
5019 case NDR_WBINT_PING:
5020 case NDR_WBINT_QUERYSEQUENCENUMBER:
5021 case NDR_WBINT_ALLOCATEUID:
5022 case NDR_WBINT_ALLOCATEGID:
5023 case NDR_WBINT_CHECKMACHINEACCOUNT:
5024 case NDR_WBINT_CHANGEMACHINEACCOUNT:
5025 case NDR_WBINT_PINGDC:
5026 return false;
5027 }
5028 return true;
5029}
5030
5031bool wcache_fetch_ndr(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
5032 uint32_t opnum, const DATA_BLOB *req, DATA_BLOB *resp)
5033{
5034 TDB_DATA key, data;
5035 bool ret = false;
5036
5037 if (!wcache_opnum_cacheable(opnum) ||
5038 is_my_own_sam_domain(domain) ||
5039 is_builtin_domain(domain)) {
5040 return false;
5041 }
5042
5043 if (wcache->tdb == NULL) {
5044 return false;
5045 }
5046
5047 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
5048 return false;
5049 }
5050 data = tdb_fetch(wcache->tdb, key);
5051 TALLOC_FREE(key.dptr);
5052
5053 if (data.dptr == NULL) {
5054 return false;
5055 }
5056 if (data.dsize < 12) {
5057 goto fail;
5058 }
5059
5060 if (!is_domain_offline(domain)) {
5061 uint32_t entry_seqnum, dom_seqnum, last_check;
5062 uint64_t entry_timeout;
5063
5064 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum,
5065 &last_check)) {
5066 goto fail;
5067 }
5068 entry_seqnum = IVAL(data.dptr, 0);
5069 if (entry_seqnum != dom_seqnum) {
5070 DEBUG(10, ("Entry has wrong sequence number: %d\n",
5071 (int)entry_seqnum));
5072 goto fail;
5073 }
5074 entry_timeout = BVAL(data.dptr, 4);
5075 if (time(NULL) > entry_timeout) {
5076 DEBUG(10, ("Entry has timed out\n"));
5077 goto fail;
5078 }
5079 }
5080
5081 resp->data = (uint8_t *)talloc_memdup(mem_ctx, data.dptr + 12,
5082 data.dsize - 12);
5083 if (resp->data == NULL) {
5084 DEBUG(10, ("talloc failed\n"));
5085 goto fail;
5086 }
5087 resp->length = data.dsize - 12;
5088
5089 ret = true;
5090fail:
5091 SAFE_FREE(data.dptr);
5092 return ret;
5093}
5094
5095void wcache_store_ndr(struct winbindd_domain *domain, uint32_t opnum,
5096 const DATA_BLOB *req, const DATA_BLOB *resp)
5097{
5098 TDB_DATA key, data;
5099 uint32_t dom_seqnum, last_check;
5100 uint64_t timeout;
5101
5102 if (!wcache_opnum_cacheable(opnum) ||
5103 is_my_own_sam_domain(domain) ||
5104 is_builtin_domain(domain)) {
5105 return;
5106 }
5107
5108 if (wcache->tdb == NULL) {
5109 return;
5110 }
5111
5112 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum, &last_check)) {
5113 DEBUG(10, ("could not fetch seqnum for domain %s\n",
5114 domain->name));
5115 return;
5116 }
5117
5118 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
5119 return;
5120 }
5121
5122 timeout = time(NULL) + lp_winbind_cache_time();
5123
5124 data.dsize = resp->length + 12;
5125 data.dptr = talloc_array(key.dptr, uint8_t, data.dsize);
5126 if (data.dptr == NULL) {
5127 goto done;
5128 }
5129
5130 SIVAL(data.dptr, 0, dom_seqnum);
5131 SBVAL(data.dptr, 4, timeout);
5132 memcpy(data.dptr + 12, resp->data, resp->length);
5133
5134 tdb_store(wcache->tdb, key, data, 0);
5135
5136done:
5137 TALLOC_FREE(key.dptr);
5138 return;
5139}
Note: See TracBrowser for help on using the repository browser.