2 Unix SMB/CIFS implementation.
4 Winbind cache backend functions
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
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.
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.
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/>.
27 #include "system/filesys.h"
29 #include "tdb_validate.h"
30 #include "../libcli/auth/libcli_auth.h"
31 #include "../librpc/gen_ndr/ndr_winbind.h"
34 #include "../libcli/security/security.h"
35 #include "passdb/machine_sid.h"
37 #include "libsmb/samlogon_cache.h"
40 #define DBGC_CLASS DBGC_WINBIND
42 #define WINBINDD_CACHE_VER1 1 /* initial db version */
43 #define WINBINDD_CACHE_VER2 2 /* second version with timeouts for NDR entries */
45 #define WINBINDD_CACHE_VERSION WINBINDD_CACHE_VER2
46 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
48 extern struct winbindd_methods reconnect_methods;
50 extern struct winbindd_methods reconnect_ads_methods;
52 extern struct winbindd_methods builtin_passdb_methods;
53 extern struct winbindd_methods sam_passdb_methods;
56 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
57 * Here are the list of entry types that are *not* stored
58 * as form struct cache_entry in the cache.
61 static const char *non_centry_keys[] = {
64 WINBINDD_CACHE_VERSION_KEYSTR,
68 /************************************************************************
69 Is this key a non-centry type ?
70 ************************************************************************/
72 static bool is_non_centry_key(TDB_DATA kbuf)
76 if (kbuf.dptr == NULL || kbuf.dsize == 0) {
79 for (i = 0; non_centry_keys[i] != NULL; i++) {
80 size_t namelen = strlen(non_centry_keys[i]);
81 if (kbuf.dsize < namelen) {
84 if (strncmp(non_centry_keys[i], (const char *)kbuf.dptr, namelen) == 0) {
91 /* Global online/offline state - False when online. winbindd starts up online
92 and sets this to true if the first query fails and there's an entry in
93 the cache tdb telling us to stay offline. */
95 static bool global_winbindd_offline_state;
97 struct winbind_cache {
103 uint32_t sequence_number;
109 void (*smb_panic_fn)(const char *const why) = smb_panic;
111 static struct winbind_cache *wcache;
113 static char *wcache_path(void)
116 * Data needs to be kept persistent in state directory for
117 * running with "winbindd offline logon".
119 return state_path("winbindd_cache.tdb");
122 /* get the winbind_cache structure */
123 static struct winbind_cache *get_cache(struct winbindd_domain *domain)
125 struct winbind_cache *ret = wcache;
127 /* We have to know what type of domain we are dealing with first. */
129 if (domain->internal) {
130 domain->backend = &builtin_passdb_methods;
133 if (dom_sid_equal(&domain->sid, &global_sid_Builtin)) {
134 domain->initialized = true;
137 if (strequal(domain->name, get_global_sam_name()) &&
138 sid_check_is_our_sam(&domain->sid)) {
139 domain->backend = &sam_passdb_methods;
142 if ( !domain->initialized ) {
143 /* We do not need a connection to an RW DC for cache operation */
144 init_dc_connection(domain, false);
148 OK. Listen up because I'm only going to say this once.
149 We have the following scenarios to consider
150 (a) trusted AD domains on a Samba DC,
151 (b) trusted AD domains and we are joined to a non-kerberos domain
152 (c) trusted AD domains and we are joined to a kerberos (AD) domain
154 For (a) we can always contact the trusted domain using krb5
155 since we have the domain trust account password
157 For (b) we can only use RPC since we have no way of
158 getting a krb5 ticket in our own domain
160 For (c) we can always use krb5 since we have a kerberos trust
165 if (!domain->backend) {
167 struct winbindd_domain *our_domain = domain;
169 /* find our domain first so we can figure out if we
170 are joined to a kerberized domain */
172 if ( !domain->primary )
173 our_domain = find_our_domain();
175 if ((our_domain->active_directory || IS_DC)
176 && domain->active_directory
177 && !lp_winbind_rpc_only()) {
178 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain->name));
179 domain->backend = &reconnect_ads_methods;
181 #endif /* HAVE_ADS */
182 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain->name));
183 domain->backend = &reconnect_methods;
186 #endif /* HAVE_ADS */
192 ret = SMB_XMALLOC_P(struct winbind_cache);
196 wcache_flush_cache();
202 free a centry structure
204 static void centry_free(struct cache_entry *centry)
208 SAFE_FREE(centry->data);
212 static bool centry_check_bytes(struct cache_entry *centry, size_t nbytes)
214 if (centry->len - centry->ofs < nbytes) {
215 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
216 (unsigned int)nbytes,
217 centry->len - centry->ofs));
224 pull a uint64_t from a cache entry
226 static uint64_t centry_uint64_t(struct cache_entry *centry)
230 if (!centry_check_bytes(centry, 8)) {
231 smb_panic_fn("centry_uint64_t");
233 ret = BVAL(centry->data, centry->ofs);
239 pull a uint32_t from a cache entry
241 static uint32_t centry_uint32(struct cache_entry *centry)
245 if (!centry_check_bytes(centry, 4)) {
246 smb_panic_fn("centry_uint32");
248 ret = IVAL(centry->data, centry->ofs);
254 pull a uint16_t from a cache entry
256 static uint16_t centry_uint16(struct cache_entry *centry)
259 if (!centry_check_bytes(centry, 2)) {
260 smb_panic_fn("centry_uint16");
262 ret = SVAL(centry->data, centry->ofs);
268 pull a uint8_t from a cache entry
270 static uint8_t centry_uint8(struct cache_entry *centry)
273 if (!centry_check_bytes(centry, 1)) {
274 smb_panic_fn("centry_uint8");
276 ret = CVAL(centry->data, centry->ofs);
282 pull a NTTIME from a cache entry
284 static NTTIME centry_nttime(struct cache_entry *centry)
287 if (!centry_check_bytes(centry, 8)) {
288 smb_panic_fn("centry_nttime");
290 ret = IVAL(centry->data, centry->ofs);
292 ret += (uint64_t)IVAL(centry->data, centry->ofs) << 32;
298 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
300 static time_t centry_time(struct cache_entry *centry)
302 return (time_t)centry_nttime(centry);
305 /* pull a string from a cache entry, using the supplied
308 static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
313 len = centry_uint8(centry);
316 /* a deliberate NULL string */
320 if (!centry_check_bytes(centry, (size_t)len)) {
321 smb_panic_fn("centry_string");
324 ret = talloc_array(mem_ctx, char, len+1);
326 smb_panic_fn("centry_string out of memory\n");
328 memcpy(ret,centry->data + centry->ofs, len);
334 /* pull a hash16 from a cache entry, using the supplied
337 static char *centry_hash16(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
342 len = centry_uint8(centry);
345 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
350 if (!centry_check_bytes(centry, 16)) {
354 ret = talloc_array(mem_ctx, char, 16);
356 smb_panic_fn("centry_hash out of memory\n");
358 memcpy(ret,centry->data + centry->ofs, 16);
363 /* pull a sid from a cache entry, using the supplied
366 static bool centry_sid(struct cache_entry *centry, struct dom_sid *sid)
371 sid_string = centry_string(centry, talloc_tos());
372 if (sid_string == NULL) {
375 ret = string_to_sid(sid, sid_string);
376 TALLOC_FREE(sid_string);
382 pull a NTSTATUS from a cache entry
384 static NTSTATUS centry_ntstatus(struct cache_entry *centry)
388 status = NT_STATUS(centry_uint32(centry));
393 /* the server is considered down if it can't give us a sequence number */
394 static bool wcache_server_down(struct winbindd_domain *domain)
401 ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
404 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
409 struct wcache_seqnum_state {
411 uint32_t *last_seq_check;
414 static int wcache_seqnum_parser(TDB_DATA key, TDB_DATA data,
417 struct wcache_seqnum_state *state = private_data;
419 if (data.dsize != 8) {
420 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
425 *state->seqnum = IVAL(data.dptr, 0);
426 *state->last_seq_check = IVAL(data.dptr, 4);
430 static bool wcache_fetch_seqnum(const char *domain_name, uint32_t *seqnum,
431 uint32_t *last_seq_check)
433 struct wcache_seqnum_state state = {
434 .seqnum = seqnum, .last_seq_check = last_seq_check
436 size_t len = strlen(domain_name);
438 TDB_DATA key = { .dptr = (uint8_t *)keystr, .dsize = sizeof(keystr) };
441 if (wcache->tdb == NULL) {
442 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
446 snprintf(keystr, sizeof(keystr), "SEQNUM/%s", domain_name);
448 ret = tdb_parse_record(wcache->tdb, key, wcache_seqnum_parser,
453 static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
455 uint32_t last_check, time_diff;
457 if (!wcache_fetch_seqnum(domain->name, &domain->sequence_number,
459 return NT_STATUS_UNSUCCESSFUL;
461 domain->last_seq_check = last_check;
463 /* have we expired? */
465 time_diff = now - domain->last_seq_check;
466 if ( time_diff > lp_winbind_cache_time() ) {
467 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
468 domain->name, domain->sequence_number,
469 (uint32_t)domain->last_seq_check));
470 return NT_STATUS_UNSUCCESSFUL;
473 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
474 domain->name, domain->sequence_number,
475 (uint32_t)domain->last_seq_check));
480 bool wcache_store_seqnum(const char *domain_name, uint32_t seqnum,
481 time_t last_seq_check)
483 size_t len = strlen(domain_name);
485 TDB_DATA key = { .dptr = (uint8_t *)keystr, .dsize = sizeof(keystr) };
489 if (wcache->tdb == NULL) {
490 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
494 snprintf(keystr, sizeof(keystr), "SEQNUM/%s", domain_name);
496 SIVAL(buf, 0, seqnum);
497 SIVAL(buf, 4, last_seq_check);
499 ret = tdb_store(wcache->tdb, key, make_tdb_data(buf, sizeof(buf)),
502 DEBUG(10, ("tdb_store_bystring failed: %s\n",
503 tdb_errorstr(wcache->tdb)));
507 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
508 domain_name, seqnum, (unsigned)last_seq_check));
513 static bool store_cache_seqnum( struct winbindd_domain *domain )
515 return wcache_store_seqnum(domain->name, domain->sequence_number,
516 domain->last_seq_check);
520 refresh the domain sequence number on timeout.
523 static void refresh_sequence_number(struct winbindd_domain *domain)
527 time_t t = time(NULL);
528 unsigned cache_time = lp_winbind_cache_time();
530 if (is_domain_offline(domain)) {
536 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
537 /* trying to reconnect is expensive, don't do it too often */
538 if (domain->sequence_number == DOM_SEQUENCE_NONE) {
543 time_diff = t - domain->last_seq_check;
545 /* see if we have to refetch the domain sequence number */
546 if ((time_diff < cache_time) &&
547 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
548 NT_STATUS_IS_OK(domain->last_status)) {
549 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
553 /* try to get the sequence number from the tdb cache first */
554 /* this will update the timestamp as well */
556 status = fetch_cache_seqnum( domain, t );
557 if (NT_STATUS_IS_OK(status) &&
558 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
559 NT_STATUS_IS_OK(domain->last_status)) {
563 /* important! make sure that we know if this is a native
564 mode domain or not. And that we can contact it. */
566 if ( winbindd_can_contact_domain( domain ) ) {
567 status = domain->backend->sequence_number(domain,
568 &domain->sequence_number);
570 /* just use the current time */
571 status = NT_STATUS_OK;
572 domain->sequence_number = time(NULL);
576 /* the above call could have set our domain->backend to NULL when
577 * coming from offline to online mode, make sure to reinitialize the
578 * backend - Guenther */
581 if (!NT_STATUS_IS_OK(status)) {
582 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status)));
583 domain->sequence_number = DOM_SEQUENCE_NONE;
586 domain->last_status = status;
587 domain->last_seq_check = time(NULL);
589 /* save the new sequence number in the cache */
590 store_cache_seqnum( domain );
593 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
594 domain->name, domain->sequence_number));
600 decide if a cache entry has expired
602 static bool centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
604 /* If we've been told to be offline - stay in that state... */
605 if (lp_winbind_offline_logon() && global_winbindd_offline_state) {
606 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
607 keystr, domain->name ));
611 /* when the domain is offline return the cached entry.
612 * This deals with transient offline states... */
614 if (!domain->online) {
615 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
616 keystr, domain->name ));
620 /* if the server is OK and our cache entry came from when it was down then
621 the entry is invalid */
622 if ((domain->sequence_number != DOM_SEQUENCE_NONE) &&
623 (centry->sequence_number == DOM_SEQUENCE_NONE)) {
624 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
625 keystr, domain->name ));
629 /* if the server is down or the cache entry is not older than the
630 current sequence number or it did not timeout then it is OK */
631 if (wcache_server_down(domain)
632 || ((centry->sequence_number == domain->sequence_number)
633 && (centry->timeout > time(NULL)))) {
634 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
635 keystr, domain->name ));
639 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
640 keystr, domain->name ));
646 static struct cache_entry *wcache_fetch_raw(char *kstr)
649 struct cache_entry *centry;
652 key = string_tdb_data(kstr);
653 data = tdb_fetch(wcache->tdb, key);
659 centry = SMB_XMALLOC_P(struct cache_entry);
660 centry->data = (unsigned char *)data.dptr;
661 centry->len = data.dsize;
664 if (centry->len < 16) {
665 /* huh? corrupt cache? */
666 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s "
667 "(len < 16)?\n", kstr));
672 centry->status = centry_ntstatus(centry);
673 centry->sequence_number = centry_uint32(centry);
674 centry->timeout = centry_uint64_t(centry);
679 static bool is_my_own_sam_domain(struct winbindd_domain *domain)
681 if (strequal(domain->name, get_global_sam_name()) &&
682 sid_check_is_our_sam(&domain->sid)) {
689 static bool is_builtin_domain(struct winbindd_domain *domain)
691 if (strequal(domain->name, "BUILTIN") &&
692 sid_check_is_builtin(&domain->sid)) {
700 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
701 number and return status
703 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
704 struct winbindd_domain *domain,
705 const char *format, ...) PRINTF_ATTRIBUTE(3,4);
706 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
707 struct winbindd_domain *domain,
708 const char *format, ...)
712 struct cache_entry *centry;
714 if (!winbindd_use_cache() ||
715 is_my_own_sam_domain(domain) ||
716 is_builtin_domain(domain)) {
720 refresh_sequence_number(domain);
722 va_start(ap, format);
723 smb_xvasprintf(&kstr, format, ap);
726 centry = wcache_fetch_raw(kstr);
727 if (centry == NULL) {
732 if (centry_expired(domain, kstr, centry)) {
734 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
735 kstr, domain->name ));
742 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
743 kstr, domain->name ));
749 static void wcache_delete(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
750 static void wcache_delete(const char *format, ...)
756 va_start(ap, format);
757 smb_xvasprintf(&kstr, format, ap);
760 key = string_tdb_data(kstr);
762 tdb_delete(wcache->tdb, key);
767 make sure we have at least len bytes available in a centry
769 static void centry_expand(struct cache_entry *centry, uint32_t len)
771 if (centry->len - centry->ofs >= len)
774 centry->data = SMB_REALLOC_ARRAY(centry->data, unsigned char,
777 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
778 smb_panic_fn("out of memory in centry_expand");
783 push a uint64_t into a centry
785 static void centry_put_uint64_t(struct cache_entry *centry, uint64_t v)
787 centry_expand(centry, 8);
788 SBVAL(centry->data, centry->ofs, v);
793 push a uint32_t into a centry
795 static void centry_put_uint32(struct cache_entry *centry, uint32_t v)
797 centry_expand(centry, 4);
798 SIVAL(centry->data, centry->ofs, v);
803 push a uint16_t into a centry
805 static void centry_put_uint16(struct cache_entry *centry, uint16_t v)
807 centry_expand(centry, 2);
808 SSVAL(centry->data, centry->ofs, v);
813 push a uint8_t into a centry
815 static void centry_put_uint8(struct cache_entry *centry, uint8_t v)
817 centry_expand(centry, 1);
818 SCVAL(centry->data, centry->ofs, v);
823 push a string into a centry
825 static void centry_put_string(struct cache_entry *centry, const char *s)
830 /* null strings are marked as len 0xFFFF */
831 centry_put_uint8(centry, 0xFF);
836 /* can't handle more than 254 char strings. Truncating is probably best */
838 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len));
841 centry_put_uint8(centry, len);
842 centry_expand(centry, len);
843 memcpy(centry->data + centry->ofs, s, len);
848 push a 16 byte hash into a centry - treat as 16 byte string.
850 static void centry_put_hash16(struct cache_entry *centry, const uint8_t val[16])
852 centry_put_uint8(centry, 16);
853 centry_expand(centry, 16);
854 memcpy(centry->data + centry->ofs, val, 16);
858 static void centry_put_sid(struct cache_entry *centry, const struct dom_sid *sid)
861 centry_put_string(centry, sid_to_fstring(sid_string, sid));
866 put NTSTATUS into a centry
868 static void centry_put_ntstatus(struct cache_entry *centry, NTSTATUS status)
870 uint32_t status_value = NT_STATUS_V(status);
871 centry_put_uint32(centry, status_value);
876 push a NTTIME into a centry
878 static void centry_put_nttime(struct cache_entry *centry, NTTIME nt)
880 centry_expand(centry, 8);
881 SIVAL(centry->data, centry->ofs, nt & 0xFFFFFFFF);
883 SIVAL(centry->data, centry->ofs, nt >> 32);
888 push a time_t into a centry - use a 64 bit size.
889 NTTIME here is being used as a convenient 64-bit size.
891 static void centry_put_time(struct cache_entry *centry, time_t t)
893 NTTIME nt = (NTTIME)t;
894 centry_put_nttime(centry, nt);
898 start a centry for output. When finished, call centry_end()
900 static struct cache_entry *centry_start(struct winbindd_domain *domain,
903 struct cache_entry *centry;
908 centry = SMB_XMALLOC_P(struct cache_entry);
910 centry->len = 8192; /* reasonable default */
911 centry->data = SMB_XMALLOC_ARRAY(uint8_t, centry->len);
913 centry->sequence_number = domain->sequence_number;
914 centry->timeout = lp_winbind_cache_time() + time(NULL);
915 centry_put_ntstatus(centry, status);
916 centry_put_uint32(centry, centry->sequence_number);
917 centry_put_uint64_t(centry, centry->timeout);
922 finish a centry and write it to the tdb
924 static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
925 static void centry_end(struct cache_entry *centry, const char *format, ...)
931 if (!winbindd_use_cache()) {
935 va_start(ap, format);
936 smb_xvasprintf(&kstr, format, ap);
939 key = string_tdb_data(kstr);
940 data.dptr = centry->data;
941 data.dsize = centry->ofs;
943 tdb_store(wcache->tdb, key, data, TDB_REPLACE);
947 static void wcache_save_name_to_sid(struct winbindd_domain *domain,
948 NTSTATUS status, const char *domain_name,
949 const char *name, const struct dom_sid *sid,
950 enum lsa_SidType type)
952 struct cache_entry *centry;
955 centry = centry_start(domain, status);
959 if ((domain_name == NULL) || (domain_name[0] == '\0')) {
960 struct winbindd_domain *mydomain =
961 find_domain_from_sid_noinit(sid);
962 if (mydomain != NULL) {
963 domain_name = mydomain->name;
967 centry_put_uint32(centry, type);
968 centry_put_sid(centry, sid);
969 fstrcpy(uname, name);
970 (void)strupper_m(uname);
971 centry_end(centry, "NS/%s/%s", domain_name, uname);
972 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name,
973 uname, sid_string_dbg(sid), nt_errstr(status)));
977 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
978 const struct dom_sid *sid, const char *domain_name, const char *name, enum lsa_SidType type)
980 struct cache_entry *centry;
983 centry = centry_start(domain, status);
987 if ((domain_name == NULL) || (domain_name[0] == '\0')) {
988 struct winbindd_domain *mydomain =
989 find_domain_from_sid_noinit(sid);
990 if (mydomain != NULL) {
991 domain_name = mydomain->name;
995 if (NT_STATUS_IS_OK(status)) {
996 centry_put_uint32(centry, type);
997 centry_put_string(centry, domain_name);
998 centry_put_string(centry, name);
1001 centry_end(centry, "SN/%s", sid_to_fstring(sid_string, sid));
1002 DEBUG(10,("wcache_save_sid_to_name: %s -> %s\\%s (%s)\n", sid_string,
1003 domain_name, name, nt_errstr(status)));
1004 centry_free(centry);
1007 static void wcache_save_lockout_policy(struct winbindd_domain *domain,
1009 struct samr_DomInfo12 *lockout_policy)
1011 struct cache_entry *centry;
1013 centry = centry_start(domain, status);
1017 centry_put_nttime(centry, lockout_policy->lockout_duration);
1018 centry_put_nttime(centry, lockout_policy->lockout_window);
1019 centry_put_uint16(centry, lockout_policy->lockout_threshold);
1021 centry_end(centry, "LOC_POL/%s", domain->name);
1023 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
1025 centry_free(centry);
1030 static void wcache_save_password_policy(struct winbindd_domain *domain,
1032 struct samr_DomInfo1 *policy)
1034 struct cache_entry *centry;
1036 centry = centry_start(domain, status);
1040 centry_put_uint16(centry, policy->min_password_length);
1041 centry_put_uint16(centry, policy->password_history_length);
1042 centry_put_uint32(centry, policy->password_properties);
1043 centry_put_nttime(centry, policy->max_password_age);
1044 centry_put_nttime(centry, policy->min_password_age);
1046 centry_end(centry, "PWD_POL/%s", domain->name);
1048 DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
1050 centry_free(centry);
1053 /***************************************************************************
1054 ***************************************************************************/
1056 static void wcache_save_username_alias(struct winbindd_domain *domain,
1058 const char *name, const char *alias)
1060 struct cache_entry *centry;
1063 if ( (centry = centry_start(domain, status)) == NULL )
1066 centry_put_string( centry, alias );
1068 fstrcpy(uname, name);
1069 (void)strupper_m(uname);
1070 centry_end(centry, "NSS/NA/%s", uname);
1072 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name, alias ));
1074 centry_free(centry);
1077 static void wcache_save_alias_username(struct winbindd_domain *domain,
1079 const char *alias, const char *name)
1081 struct cache_entry *centry;
1084 if ( (centry = centry_start(domain, status)) == NULL )
1087 centry_put_string( centry, name );
1089 fstrcpy(uname, alias);
1090 (void)strupper_m(uname);
1091 centry_end(centry, "NSS/AN/%s", uname);
1093 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias, name ));
1095 centry_free(centry);
1098 /***************************************************************************
1099 ***************************************************************************/
1101 NTSTATUS resolve_username_to_alias( TALLOC_CTX *mem_ctx,
1102 struct winbindd_domain *domain,
1103 const char *name, char **alias )
1105 struct winbind_cache *cache = get_cache(domain);
1106 struct cache_entry *centry = NULL;
1110 if ( domain->internal )
1111 return NT_STATUS_NOT_SUPPORTED;
1116 upper_name = talloc_strdup_upper(mem_ctx, name);
1117 if (upper_name == NULL) {
1118 return NT_STATUS_NO_MEMORY;
1121 centry = wcache_fetch(cache, domain, "NSS/NA/%s", upper_name);
1123 talloc_free(upper_name);
1128 status = centry->status;
1130 if (!NT_STATUS_IS_OK(status)) {
1131 centry_free(centry);
1135 *alias = centry_string( centry, mem_ctx );
1137 centry_free(centry);
1139 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1140 name, *alias ? *alias : "(none)"));
1142 return (*alias) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1146 /* If its not in cache and we are offline, then fail */
1148 if ( get_global_winbindd_state_offline() || !domain->online ) {
1149 DEBUG(8,("resolve_username_to_alias: rejecting query "
1150 "in offline mode\n"));
1151 return NT_STATUS_NOT_FOUND;
1154 status = nss_map_to_alias( mem_ctx, domain->name, name, alias );
1156 if ( NT_STATUS_IS_OK( status ) ) {
1157 wcache_save_username_alias(domain, status, name, *alias);
1160 if ( NT_STATUS_EQUAL( status, NT_STATUS_NONE_MAPPED ) ) {
1161 wcache_save_username_alias(domain, status, name, "(NULL)");
1164 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1165 nt_errstr(status)));
1167 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1168 set_domain_offline( domain );
1174 /***************************************************************************
1175 ***************************************************************************/
1177 NTSTATUS resolve_alias_to_username( TALLOC_CTX *mem_ctx,
1178 struct winbindd_domain *domain,
1179 const char *alias, char **name )
1181 struct winbind_cache *cache = get_cache(domain);
1182 struct cache_entry *centry = NULL;
1186 if ( domain->internal )
1187 return NT_STATUS_NOT_SUPPORTED;
1192 upper_name = talloc_strdup(mem_ctx, alias);
1193 if (upper_name == NULL) {
1194 return NT_STATUS_NO_MEMORY;
1196 if (!strupper_m(upper_name)) {
1197 talloc_free(upper_name);
1198 return NT_STATUS_INVALID_PARAMETER;
1201 centry = wcache_fetch(cache, domain, "NSS/AN/%s", upper_name);
1203 talloc_free(upper_name);
1208 status = centry->status;
1210 if (!NT_STATUS_IS_OK(status)) {
1211 centry_free(centry);
1215 *name = centry_string( centry, mem_ctx );
1217 centry_free(centry);
1219 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1220 alias, *name ? *name : "(none)"));
1222 return (*name) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1226 /* If its not in cache and we are offline, then fail */
1228 if ( get_global_winbindd_state_offline() || !domain->online ) {
1229 DEBUG(8,("resolve_alias_to_username: rejecting query "
1230 "in offline mode\n"));
1231 return NT_STATUS_NOT_FOUND;
1234 /* an alias cannot contain a domain prefix or '@' */
1236 if (strchr(alias, '\\') || strchr(alias, '@')) {
1237 DEBUG(10,("resolve_alias_to_username: skipping fully "
1238 "qualified name %s\n", alias));
1239 return NT_STATUS_OBJECT_NAME_INVALID;
1242 status = nss_map_from_alias( mem_ctx, domain->name, alias, name );
1244 if ( NT_STATUS_IS_OK( status ) ) {
1245 wcache_save_alias_username( domain, status, alias, *name );
1248 if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1249 wcache_save_alias_username(domain, status, alias, "(NULL)");
1252 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1253 nt_errstr(status)));
1255 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1256 set_domain_offline( domain );
1262 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const struct dom_sid *sid)
1264 struct winbind_cache *cache = get_cache(domain);
1266 fstring key_str, tmp;
1270 return NT_STATUS_INTERNAL_DB_ERROR;
1273 if (is_null_sid(sid)) {
1274 return NT_STATUS_INVALID_SID;
1277 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1278 return NT_STATUS_INVALID_SID;
1281 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
1283 data = tdb_fetch(cache->tdb, string_tdb_data(key_str));
1285 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1288 SAFE_FREE(data.dptr);
1289 return NT_STATUS_OK;
1292 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1293 as new salted ones. */
1295 NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
1296 TALLOC_CTX *mem_ctx,
1297 const struct dom_sid *sid,
1298 const uint8_t **cached_nt_pass,
1299 const uint8_t **cached_salt)
1301 struct winbind_cache *cache = get_cache(domain);
1302 struct cache_entry *centry = NULL;
1308 return NT_STATUS_INTERNAL_DB_ERROR;
1311 if (is_null_sid(sid)) {
1312 return NT_STATUS_INVALID_SID;
1315 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1316 return NT_STATUS_INVALID_SID;
1319 /* Try and get a salted cred first. If we can't
1320 fall back to an unsalted cred. */
1322 centry = wcache_fetch(cache, domain, "CRED/%s",
1323 sid_to_fstring(tmp, sid));
1325 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1326 sid_string_dbg(sid)));
1327 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1331 * We don't use the time element at this moment,
1332 * but we have to consume it, so that we don't
1333 * neet to change the disk format of the cache.
1335 (void)centry_time(centry);
1337 /* In the salted case this isn't actually the nt_hash itself,
1338 but the MD5 of the salt + nt_hash. Let the caller
1339 sort this out. It can tell as we only return the cached_salt
1340 if we are returning a salted cred. */
1342 *cached_nt_pass = (const uint8_t *)centry_hash16(centry, mem_ctx);
1343 if (*cached_nt_pass == NULL) {
1346 sid_to_fstring(sidstr, sid);
1348 /* Bad (old) cred cache. Delete and pretend we
1350 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1352 wcache_delete("CRED/%s", sidstr);
1353 centry_free(centry);
1354 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1357 /* We only have 17 bytes more data in the salted cred case. */
1358 if (centry->len - centry->ofs == 17) {
1359 *cached_salt = (const uint8_t *)centry_hash16(centry, mem_ctx);
1361 *cached_salt = NULL;
1364 dump_data_pw("cached_nt_pass", *cached_nt_pass, NT_HASH_LEN);
1366 dump_data_pw("cached_salt", *cached_salt, NT_HASH_LEN);
1369 status = centry->status;
1371 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1372 sid_string_dbg(sid), nt_errstr(status) ));
1374 centry_free(centry);
1378 /* Store creds for a SID - only writes out new salted ones. */
1380 NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
1381 const struct dom_sid *sid,
1382 const uint8_t nt_pass[NT_HASH_LEN])
1384 struct cache_entry *centry;
1387 uint8_t cred_salt[NT_HASH_LEN];
1388 uint8_t salted_hash[NT_HASH_LEN];
1390 if (is_null_sid(sid)) {
1391 return NT_STATUS_INVALID_SID;
1394 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1395 return NT_STATUS_INVALID_SID;
1398 centry = centry_start(domain, NT_STATUS_OK);
1400 return NT_STATUS_INTERNAL_DB_ERROR;
1403 dump_data_pw("nt_pass", nt_pass, NT_HASH_LEN);
1405 centry_put_time(centry, time(NULL));
1407 /* Create a salt and then salt the hash. */
1408 generate_random_buffer(cred_salt, NT_HASH_LEN);
1409 E_md5hash(cred_salt, nt_pass, salted_hash);
1411 centry_put_hash16(centry, salted_hash);
1412 centry_put_hash16(centry, cred_salt);
1413 centry_end(centry, "CRED/%s", sid_to_fstring(sid_string, sid));
1415 DEBUG(10,("wcache_save_creds: %s\n", sid_string));
1417 centry_free(centry);
1419 return NT_STATUS_OK;
1423 /* Query display info. This is the basic user list fn */
1424 NTSTATUS wb_cache_query_user_list(struct winbindd_domain *domain,
1425 TALLOC_CTX *mem_ctx,
1428 struct winbind_cache *cache = get_cache(domain);
1429 struct cache_entry *centry = NULL;
1430 uint32_t num_rids = 0;
1431 uint32_t *rids = NULL;
1433 unsigned int i, retry;
1434 bool old_status = domain->online;
1441 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1446 num_rids = centry_uint32(centry);
1448 if (num_rids == 0) {
1452 rids = talloc_array(mem_ctx, uint32_t, num_rids);
1454 centry_free(centry);
1455 return NT_STATUS_NO_MEMORY;
1458 for (i=0; i<num_rids; i++) {
1459 rids[i] = centry_uint32(centry);
1463 status = centry->status;
1465 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1466 domain->name, nt_errstr(status) ));
1468 centry_free(centry);
1473 /* Return status value returned by seq number check */
1475 if (!NT_STATUS_IS_OK(domain->last_status))
1476 return domain->last_status;
1478 /* Put the query_user_list() in a retry loop. There appears to be
1479 * some bug either with Windows 2000 or Samba's handling of large
1480 * rpc replies. This manifests itself as sudden disconnection
1481 * at a random point in the enumeration of a large (60k) user list.
1482 * The retry loop simply tries the operation again. )-: It's not
1483 * pretty but an acceptable workaround until we work out what the
1484 * real problem is. */
1489 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1493 status = domain->backend->query_user_list(domain, mem_ctx,
1495 num_rids = talloc_array_length(rids);
1497 if (!NT_STATUS_IS_OK(status)) {
1498 DEBUG(3, ("query_user_list: returned 0x%08x, "
1499 "retrying\n", NT_STATUS_V(status)));
1501 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1502 DEBUG(3, ("query_user_list: flushing "
1503 "connection cache\n"));
1504 invalidate_cm_connection(domain);
1506 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1507 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1508 if (!domain->internal && old_status) {
1509 set_domain_offline(domain);
1511 /* store partial response. */
1514 * humm, what about the status used for cache?
1515 * Should it be NT_STATUS_OK?
1520 * domain is offline now, and there is no user entries,
1521 * try to fetch from cache again.
1523 if (cache->tdb && !domain->online && !domain->internal && old_status) {
1524 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1525 /* partial response... */
1529 goto do_fetch_cache;
1536 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
1540 refresh_sequence_number(domain);
1541 if (!NT_STATUS_IS_OK(status)) {
1544 centry = centry_start(domain, status);
1547 centry_put_uint32(centry, num_rids);
1548 for (i=0; i<num_rids; i++) {
1549 centry_put_uint32(centry, rids[i]);
1551 centry_end(centry, "UL/%s", domain->name);
1552 centry_free(centry);
1560 /* list all domain groups */
1561 NTSTATUS wb_cache_enum_dom_groups(struct winbindd_domain *domain,
1562 TALLOC_CTX *mem_ctx,
1563 uint32_t *num_entries,
1564 struct wb_acct_info **info)
1566 struct winbind_cache *cache = get_cache(domain);
1567 struct cache_entry *centry = NULL;
1572 old_status = domain->online;
1576 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1581 *num_entries = centry_uint32(centry);
1583 if (*num_entries == 0)
1586 (*info) = talloc_array(mem_ctx, struct wb_acct_info, *num_entries);
1588 smb_panic_fn("enum_dom_groups out of memory");
1590 for (i=0; i<(*num_entries); i++) {
1591 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1592 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1593 (*info)[i].rid = centry_uint32(centry);
1597 status = centry->status;
1599 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1600 domain->name, nt_errstr(status) ));
1602 centry_free(centry);
1609 /* Return status value returned by seq number check */
1611 if (!NT_STATUS_IS_OK(domain->last_status))
1612 return domain->last_status;
1614 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1617 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1619 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1620 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1621 if (!domain->internal && old_status) {
1622 set_domain_offline(domain);
1626 !domain->internal &&
1628 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1630 goto do_fetch_cache;
1635 refresh_sequence_number(domain);
1636 if (!NT_STATUS_IS_OK(status)) {
1639 centry = centry_start(domain, status);
1642 centry_put_uint32(centry, *num_entries);
1643 for (i=0; i<(*num_entries); i++) {
1644 centry_put_string(centry, (*info)[i].acct_name);
1645 centry_put_string(centry, (*info)[i].acct_desc);
1646 centry_put_uint32(centry, (*info)[i].rid);
1648 centry_end(centry, "GL/%s/domain", domain->name);
1649 centry_free(centry);
1655 /* list all domain groups */
1656 NTSTATUS wb_cache_enum_local_groups(struct winbindd_domain *domain,
1657 TALLOC_CTX *mem_ctx,
1658 uint32_t *num_entries,
1659 struct wb_acct_info **info)
1661 struct winbind_cache *cache = get_cache(domain);
1662 struct cache_entry *centry = NULL;
1667 old_status = domain->online;
1671 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1676 *num_entries = centry_uint32(centry);
1678 if (*num_entries == 0)
1681 (*info) = talloc_array(mem_ctx, struct wb_acct_info, *num_entries);
1683 smb_panic_fn("enum_dom_groups out of memory");
1685 for (i=0; i<(*num_entries); i++) {
1686 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1687 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1688 (*info)[i].rid = centry_uint32(centry);
1693 /* If we are returning cached data and the domain controller
1694 is down then we don't know whether the data is up to date
1695 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1698 if (wcache_server_down(domain)) {
1699 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1700 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1702 status = centry->status;
1704 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1705 domain->name, nt_errstr(status) ));
1707 centry_free(centry);
1714 /* Return status value returned by seq number check */
1716 if (!NT_STATUS_IS_OK(domain->last_status))
1717 return domain->last_status;
1719 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1722 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1724 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1725 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1726 if (!domain->internal && old_status) {
1727 set_domain_offline(domain);
1730 !domain->internal &&
1733 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1735 goto do_fetch_cache;
1740 refresh_sequence_number(domain);
1741 if (!NT_STATUS_IS_OK(status)) {
1744 centry = centry_start(domain, status);
1747 centry_put_uint32(centry, *num_entries);
1748 for (i=0; i<(*num_entries); i++) {
1749 centry_put_string(centry, (*info)[i].acct_name);
1750 centry_put_string(centry, (*info)[i].acct_desc);
1751 centry_put_uint32(centry, (*info)[i].rid);
1753 centry_end(centry, "GL/%s/local", domain->name);
1754 centry_free(centry);
1760 NTSTATUS wcache_name_to_sid(struct winbindd_domain *domain,
1761 const char *domain_name,
1763 struct dom_sid *sid,
1764 enum lsa_SidType *type)
1766 struct winbind_cache *cache = get_cache(domain);
1767 struct cache_entry *centry;
1771 if (cache->tdb == NULL) {
1772 return NT_STATUS_NOT_FOUND;
1775 uname = talloc_strdup_upper(talloc_tos(), name);
1776 if (uname == NULL) {
1777 return NT_STATUS_NO_MEMORY;
1780 if ((domain_name == NULL) || (domain_name[0] == '\0')) {
1781 domain_name = domain->name;
1784 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1786 if (centry == NULL) {
1787 return NT_STATUS_NOT_FOUND;
1790 status = centry->status;
1791 if (NT_STATUS_IS_OK(status)) {
1792 *type = (enum lsa_SidType)centry_uint32(centry);
1793 centry_sid(centry, sid);
1796 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1797 "%s\n", domain->name, nt_errstr(status) ));
1799 centry_free(centry);
1803 /* convert a single name to a sid in a domain */
1804 NTSTATUS wb_cache_name_to_sid(struct winbindd_domain *domain,
1805 TALLOC_CTX *mem_ctx,
1806 const char *domain_name,
1809 struct dom_sid *sid,
1810 enum lsa_SidType *type)
1815 old_status = domain->online;
1817 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1818 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1824 /* If the seq number check indicated that there is a problem
1825 * with this DC, then return that status... except for
1826 * access_denied. This is special because the dc may be in
1827 * "restrict anonymous = 1" mode, in which case it will deny
1828 * most unauthenticated operations, but *will* allow the LSA
1829 * name-to-sid that we try as a fallback. */
1831 if (!(NT_STATUS_IS_OK(domain->last_status)
1832 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1833 return domain->last_status;
1835 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1838 status = domain->backend->name_to_sid(domain, mem_ctx, domain_name,
1839 name, flags, sid, type);
1841 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1842 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1843 if (!domain->internal && old_status) {
1844 set_domain_offline(domain);
1846 if (!domain->internal &&
1849 NTSTATUS cache_status;
1850 cache_status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1851 return cache_status;
1855 refresh_sequence_number(domain);
1857 if (domain->online &&
1858 (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
1859 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1861 /* Only save the reverse mapping if this was not a UPN */
1862 if (!strchr(name, '@')) {
1863 if (!strupper_m(discard_const_p(char, domain_name))) {
1864 return NT_STATUS_INVALID_PARAMETER;
1866 (void)strlower_m(discard_const_p(char, name));
1867 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1874 static NTSTATUS wcache_sid_to_name(struct winbindd_domain *domain,
1875 const struct dom_sid *sid,
1876 TALLOC_CTX *mem_ctx,
1879 enum lsa_SidType *type)
1881 struct winbind_cache *cache = get_cache(domain);
1882 struct cache_entry *centry;
1886 if (cache->tdb == NULL) {
1887 return NT_STATUS_NOT_FOUND;
1890 sid_string = sid_string_tos(sid);
1891 if (sid_string == NULL) {
1892 return NT_STATUS_NO_MEMORY;
1895 centry = wcache_fetch(cache, domain, "SN/%s", sid_string);
1896 TALLOC_FREE(sid_string);
1897 if (centry == NULL) {
1898 return NT_STATUS_NOT_FOUND;
1901 if (NT_STATUS_IS_OK(centry->status)) {
1902 *type = (enum lsa_SidType)centry_uint32(centry);
1903 *domain_name = centry_string(centry, mem_ctx);
1904 *name = centry_string(centry, mem_ctx);
1907 status = centry->status;
1908 centry_free(centry);
1910 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1911 "%s\n", domain->name, nt_errstr(status) ));
1916 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1918 NTSTATUS wb_cache_sid_to_name(struct winbindd_domain *domain,
1919 TALLOC_CTX *mem_ctx,
1920 const struct dom_sid *sid,
1923 enum lsa_SidType *type)
1928 old_status = domain->online;
1929 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
1931 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1936 *domain_name = NULL;
1938 /* If the seq number check indicated that there is a problem
1939 * with this DC, then return that status... except for
1940 * access_denied. This is special because the dc may be in
1941 * "restrict anonymous = 1" mode, in which case it will deny
1942 * most unauthenticated operations, but *will* allow the LSA
1943 * sid-to-name that we try as a fallback. */
1945 if (!(NT_STATUS_IS_OK(domain->last_status)
1946 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1947 return domain->last_status;
1949 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1952 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1954 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1955 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1956 if (!domain->internal && old_status) {
1957 set_domain_offline(domain);
1959 if (!domain->internal &&
1962 NTSTATUS cache_status;
1963 cache_status = wcache_sid_to_name(domain, sid, mem_ctx,
1964 domain_name, name, type);
1965 return cache_status;
1969 refresh_sequence_number(domain);
1970 if (!NT_STATUS_IS_OK(status)) {
1973 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1975 /* We can't save the name to sid mapping here, as with sid history a
1976 * later name2sid would give the wrong sid. */
1981 NTSTATUS wb_cache_rids_to_names(struct winbindd_domain *domain,
1982 TALLOC_CTX *mem_ctx,
1983 const struct dom_sid *domain_sid,
1988 enum lsa_SidType **types)
1990 struct winbind_cache *cache = get_cache(domain);
1992 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1997 old_status = domain->online;
1998 *domain_name = NULL;
2006 if (num_rids == 0) {
2007 return NT_STATUS_OK;
2010 *names = talloc_array(mem_ctx, char *, num_rids);
2011 *types = talloc_array(mem_ctx, enum lsa_SidType, num_rids);
2013 if ((*names == NULL) || (*types == NULL)) {
2014 result = NT_STATUS_NO_MEMORY;
2018 have_mapped = have_unmapped = false;
2020 for (i=0; i<num_rids; i++) {
2022 struct cache_entry *centry;
2025 if (!sid_compose(&sid, domain_sid, rids[i])) {
2026 result = NT_STATUS_INTERNAL_ERROR;
2030 centry = wcache_fetch(cache, domain, "SN/%s",
2031 sid_to_fstring(tmp, &sid));
2036 (*types)[i] = SID_NAME_UNKNOWN;
2037 (*names)[i] = talloc_strdup(*names, "");
2039 if (NT_STATUS_IS_OK(centry->status)) {
2042 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
2044 dom = centry_string(centry, mem_ctx);
2045 if (*domain_name == NULL) {
2051 (*names)[i] = centry_string(centry, *names);
2053 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)
2054 || NT_STATUS_EQUAL(centry->status, STATUS_SOME_UNMAPPED)) {
2055 have_unmapped = true;
2058 /* something's definitely wrong */
2059 result = centry->status;
2060 centry_free(centry);
2064 centry_free(centry);
2068 return NT_STATUS_NONE_MAPPED;
2070 if (!have_unmapped) {
2071 return NT_STATUS_OK;
2073 return STATUS_SOME_UNMAPPED;
2077 TALLOC_FREE(*names);
2078 TALLOC_FREE(*types);
2080 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
2081 rids, num_rids, domain_name,
2084 if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
2085 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2086 if (!domain->internal && old_status) {
2087 set_domain_offline(domain);
2090 !domain->internal &&
2093 have_mapped = have_unmapped = false;
2095 *names = talloc_array(mem_ctx, char *, num_rids);
2096 if (*names == NULL) {
2097 result = NT_STATUS_NO_MEMORY;
2101 *types = talloc_array(mem_ctx, enum lsa_SidType,
2103 if (*types == NULL) {
2104 result = NT_STATUS_NO_MEMORY;
2108 for (i=0; i<num_rids; i++) {
2110 struct cache_entry *centry;
2113 if (!sid_compose(&sid, domain_sid, rids[i])) {
2114 result = NT_STATUS_INTERNAL_ERROR;
2118 centry = wcache_fetch(cache, domain, "SN/%s",
2119 sid_to_fstring(tmp, &sid));
2121 (*types)[i] = SID_NAME_UNKNOWN;
2122 (*names)[i] = talloc_strdup(*names, "");
2126 (*types)[i] = SID_NAME_UNKNOWN;
2127 (*names)[i] = talloc_strdup(*names, "");
2129 if (NT_STATUS_IS_OK(centry->status)) {
2132 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
2134 dom = centry_string(centry, mem_ctx);
2135 if (*domain_name == NULL) {
2141 (*names)[i] = centry_string(centry, *names);
2143 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
2144 have_unmapped = true;
2147 /* something's definitely wrong */
2148 result = centry->status;
2149 centry_free(centry);
2153 centry_free(centry);
2157 return NT_STATUS_NONE_MAPPED;
2159 if (!have_unmapped) {
2160 return NT_STATUS_OK;
2162 return STATUS_SOME_UNMAPPED;
2166 None of the queried rids has been found so save all negative entries
2168 if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
2169 for (i = 0; i < num_rids; i++) {
2171 const char *name = "";
2172 const enum lsa_SidType type = SID_NAME_UNKNOWN;
2173 NTSTATUS status = NT_STATUS_NONE_MAPPED;
2175 if (!sid_compose(&sid, domain_sid, rids[i])) {
2176 return NT_STATUS_INTERNAL_ERROR;
2179 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2187 Some or all of the queried rids have been found.
2189 if (!NT_STATUS_IS_OK(result) &&
2190 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
2194 refresh_sequence_number(domain);
2196 for (i=0; i<num_rids; i++) {
2200 if (!sid_compose(&sid, domain_sid, rids[i])) {
2201 result = NT_STATUS_INTERNAL_ERROR;
2205 status = (*types)[i] == SID_NAME_UNKNOWN ?
2206 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
2208 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2209 (*names)[i], (*types)[i]);
2215 TALLOC_FREE(*names);
2216 TALLOC_FREE(*types);
2220 NTSTATUS wcache_query_user(struct winbindd_domain *domain,
2221 TALLOC_CTX *mem_ctx,
2222 const struct dom_sid *user_sid,
2223 struct wbint_userinfo *info)
2225 struct winbind_cache *cache = get_cache(domain);
2226 struct cache_entry *centry = NULL;
2230 if (cache->tdb == NULL) {
2231 return NT_STATUS_NOT_FOUND;
2234 sid_string = sid_string_tos(user_sid);
2235 if (sid_string == NULL) {
2236 return NT_STATUS_NO_MEMORY;
2239 centry = wcache_fetch(cache, domain, "U/%s", sid_string);
2240 TALLOC_FREE(sid_string);
2241 if (centry == NULL) {
2242 return NT_STATUS_NOT_FOUND;
2246 * If we have an access denied cache entry and a cached info3
2247 * in the samlogon cache then do a query. This will force the
2248 * rpc back end to return the info3 data.
2251 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED) &&
2252 netsamlogon_cache_have(user_sid)) {
2253 DEBUG(10, ("query_user: cached access denied and have cached "
2255 domain->last_status = NT_STATUS_OK;
2256 centry_free(centry);
2257 return NT_STATUS_NOT_FOUND;
2260 /* if status is not ok then this is a negative hit
2261 and the rest of the data doesn't matter */
2262 status = centry->status;
2263 if (NT_STATUS_IS_OK(status)) {
2264 info->domain_name = centry_string(centry, mem_ctx);
2265 info->acct_name = centry_string(centry, mem_ctx);
2266 info->full_name = centry_string(centry, mem_ctx);
2267 info->homedir = centry_string(centry, mem_ctx);
2268 info->shell = centry_string(centry, mem_ctx);
2269 info->uid = centry_uint32(centry);
2270 info->primary_gid = centry_uint32(centry);
2271 info->primary_group_name = centry_string(centry, mem_ctx);
2272 centry_sid(centry, &info->user_sid);
2273 centry_sid(centry, &info->group_sid);
2276 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2277 "%s\n", domain->name, nt_errstr(status) ));
2279 centry_free(centry);
2285 * @brief Query a fullname from the username cache (for further gecos processing)
2287 * @param domain A pointer to the winbindd_domain struct.
2288 * @param mem_ctx The talloc context.
2289 * @param user_sid The user sid.
2290 * @param full_name A pointer to the full_name string.
2292 * @return NTSTATUS code
2294 NTSTATUS wcache_query_user_fullname(struct winbindd_domain *domain,
2295 TALLOC_CTX *mem_ctx,
2296 const struct dom_sid *user_sid,
2297 const char **full_name)
2300 struct wbint_userinfo info;
2302 status = wcache_query_user(domain, mem_ctx, user_sid, &info);
2303 if (!NT_STATUS_IS_OK(status)) {
2307 if (info.full_name != NULL) {
2308 *full_name = talloc_strdup(mem_ctx, info.full_name);
2309 if (*full_name == NULL) {
2310 return NT_STATUS_NO_MEMORY;
2314 return NT_STATUS_OK;
2317 NTSTATUS wcache_lookup_usergroups(struct winbindd_domain *domain,
2318 TALLOC_CTX *mem_ctx,
2319 const struct dom_sid *user_sid,
2320 uint32_t *pnum_sids,
2321 struct dom_sid **psids)
2323 struct winbind_cache *cache = get_cache(domain);
2324 struct cache_entry *centry = NULL;
2326 uint32_t i, num_sids;
2327 struct dom_sid *sids;
2330 if (cache->tdb == NULL) {
2331 return NT_STATUS_NOT_FOUND;
2334 centry = wcache_fetch(cache, domain, "UG/%s",
2335 sid_to_fstring(sid_string, user_sid));
2336 if (centry == NULL) {
2337 return NT_STATUS_NOT_FOUND;
2340 /* If we have an access denied cache entry and a cached info3 in the
2341 samlogon cache then do a query. This will force the rpc back end
2342 to return the info3 data. */
2344 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)
2345 && netsamlogon_cache_have(user_sid)) {
2346 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2348 domain->last_status = NT_STATUS_OK;
2349 centry_free(centry);
2350 return NT_STATUS_NOT_FOUND;
2353 num_sids = centry_uint32(centry);
2354 sids = talloc_array(mem_ctx, struct dom_sid, num_sids);
2356 centry_free(centry);
2357 return NT_STATUS_NO_MEMORY;
2360 for (i=0; i<num_sids; i++) {
2361 centry_sid(centry, &sids[i]);
2364 status = centry->status;
2366 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2367 "status: %s\n", domain->name, nt_errstr(status)));
2369 centry_free(centry);
2371 *pnum_sids = num_sids;
2376 /* Lookup groups a user is a member of. */
2377 NTSTATUS wb_cache_lookup_usergroups(struct winbindd_domain *domain,
2378 TALLOC_CTX *mem_ctx,
2379 const struct dom_sid *user_sid,
2380 uint32_t *num_groups,
2381 struct dom_sid **user_gids)
2383 struct cache_entry *centry = NULL;
2389 old_status = domain->online;
2390 status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2391 num_groups, user_gids);
2392 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2397 (*user_gids) = NULL;
2399 /* Return status value returned by seq number check */
2401 if (!NT_STATUS_IS_OK(domain->last_status))
2402 return domain->last_status;
2404 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2407 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
2409 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2410 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2411 if (!domain->internal && old_status) {
2412 set_domain_offline(domain);
2414 if (!domain->internal &&
2417 NTSTATUS cache_status;
2418 cache_status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2419 num_groups, user_gids);
2420 return cache_status;
2423 if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
2427 refresh_sequence_number(domain);
2428 if (!NT_STATUS_IS_OK(status)) {
2431 centry = centry_start(domain, status);
2435 centry_put_uint32(centry, *num_groups);
2436 for (i=0; i<(*num_groups); i++) {
2437 centry_put_sid(centry, &(*user_gids)[i]);
2440 centry_end(centry, "UG/%s", sid_to_fstring(sid_string, user_sid));
2441 centry_free(centry);
2447 static char *wcache_make_sidlist(TALLOC_CTX *mem_ctx, uint32_t num_sids,
2448 const struct dom_sid *sids)
2453 sidlist = talloc_strdup(mem_ctx, "");
2454 if (sidlist == NULL) {
2457 for (i=0; i<num_sids; i++) {
2459 sidlist = talloc_asprintf_append_buffer(
2460 sidlist, "/%s", sid_to_fstring(tmp, &sids[i]));
2461 if (sidlist == NULL) {
2468 NTSTATUS wcache_lookup_useraliases(struct winbindd_domain *domain,
2469 TALLOC_CTX *mem_ctx, uint32_t num_sids,
2470 const struct dom_sid *sids,
2471 uint32_t *pnum_aliases, uint32_t **paliases)
2473 struct winbind_cache *cache = get_cache(domain);
2474 struct cache_entry *centry = NULL;
2475 uint32_t num_aliases;
2481 if (cache->tdb == NULL) {
2482 return NT_STATUS_NOT_FOUND;
2485 if (num_sids == 0) {
2488 return NT_STATUS_OK;
2491 /* We need to cache indexed by the whole list of SIDs, the aliases
2492 * resulting might come from any of the SIDs. */
2494 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2495 if (sidlist == NULL) {
2496 return NT_STATUS_NO_MEMORY;
2499 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
2500 TALLOC_FREE(sidlist);
2501 if (centry == NULL) {
2502 return NT_STATUS_NOT_FOUND;
2505 num_aliases = centry_uint32(centry);
2506 aliases = talloc_array(mem_ctx, uint32_t, num_aliases);
2507 if (aliases == NULL) {
2508 centry_free(centry);
2509 return NT_STATUS_NO_MEMORY;
2512 for (i=0; i<num_aliases; i++) {
2513 aliases[i] = centry_uint32(centry);
2516 status = centry->status;
2518 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2519 "status %s\n", domain->name, nt_errstr(status)));
2521 centry_free(centry);
2523 *pnum_aliases = num_aliases;
2524 *paliases = aliases;
2529 NTSTATUS wb_cache_lookup_useraliases(struct winbindd_domain *domain,
2530 TALLOC_CTX *mem_ctx,
2532 const struct dom_sid *sids,
2533 uint32_t *num_aliases,
2534 uint32_t **alias_rids)
2536 struct cache_entry *centry = NULL;
2542 old_status = domain->online;
2543 status = wcache_lookup_useraliases(domain, mem_ctx, num_sids, sids,
2544 num_aliases, alias_rids);
2545 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2550 (*alias_rids) = NULL;
2552 if (!NT_STATUS_IS_OK(domain->last_status))
2553 return domain->last_status;
2555 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2556 "for domain %s\n", domain->name ));
2558 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2559 if (sidlist == NULL) {
2560 return NT_STATUS_NO_MEMORY;
2563 status = domain->backend->lookup_useraliases(domain, mem_ctx,
2565 num_aliases, alias_rids);
2567 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2568 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2569 if (!domain->internal && old_status) {
2570 set_domain_offline(domain);
2572 if (!domain->internal &&
2575 NTSTATUS cache_status;
2576 cache_status = wcache_lookup_useraliases(domain, mem_ctx, num_sids,
2577 sids, num_aliases, alias_rids);
2578 return cache_status;
2582 refresh_sequence_number(domain);
2583 if (!NT_STATUS_IS_OK(status)) {
2586 centry = centry_start(domain, status);
2589 centry_put_uint32(centry, *num_aliases);
2590 for (i=0; i<(*num_aliases); i++)
2591 centry_put_uint32(centry, (*alias_rids)[i]);
2592 centry_end(centry, "UA%s", sidlist);
2593 centry_free(centry);
2599 NTSTATUS wcache_lookup_groupmem(struct winbindd_domain *domain,
2600 TALLOC_CTX *mem_ctx,
2601 const struct dom_sid *group_sid,
2602 uint32_t *num_names,
2603 struct dom_sid **sid_mem, char ***names,
2604 uint32_t **name_types)
2606 struct winbind_cache *cache = get_cache(domain);
2607 struct cache_entry *centry = NULL;
2612 if (cache->tdb == NULL) {
2613 return NT_STATUS_NOT_FOUND;
2616 sid_string = sid_string_tos(group_sid);
2617 if (sid_string == NULL) {
2618 return NT_STATUS_NO_MEMORY;
2621 centry = wcache_fetch(cache, domain, "GM/%s", sid_string);
2622 TALLOC_FREE(sid_string);
2623 if (centry == NULL) {
2624 return NT_STATUS_NOT_FOUND;
2631 *num_names = centry_uint32(centry);
2632 if (*num_names == 0) {
2633 centry_free(centry);
2634 return NT_STATUS_OK;
2637 *sid_mem = talloc_array(mem_ctx, struct dom_sid, *num_names);
2638 *names = talloc_array(mem_ctx, char *, *num_names);
2639 *name_types = talloc_array(mem_ctx, uint32_t, *num_names);
2641 if ((*sid_mem == NULL) || (*names == NULL) || (*name_types == NULL)) {
2642 TALLOC_FREE(*sid_mem);
2643 TALLOC_FREE(*names);
2644 TALLOC_FREE(*name_types);
2645 centry_free(centry);
2646 return NT_STATUS_NO_MEMORY;
2649 for (i=0; i<(*num_names); i++) {
2650 centry_sid(centry, &(*sid_mem)[i]);
2651 (*names)[i] = centry_string(centry, mem_ctx);
2652 (*name_types)[i] = centry_uint32(centry);
2655 status = centry->status;
2657 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2658 "status: %s\n", domain->name, nt_errstr(status)));
2660 centry_free(centry);
2664 NTSTATUS wb_cache_lookup_groupmem(struct winbindd_domain *domain,
2665 TALLOC_CTX *mem_ctx,
2666 const struct dom_sid *group_sid,
2667 enum lsa_SidType type,
2668 uint32_t *num_names,
2669 struct dom_sid **sid_mem,
2671 uint32_t **name_types)
2673 struct cache_entry *centry = NULL;
2679 old_status = domain->online;
2680 status = wcache_lookup_groupmem(domain, mem_ctx, group_sid, num_names,
2681 sid_mem, names, name_types);
2682 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2689 (*name_types) = NULL;
2691 /* Return status value returned by seq number check */
2693 if (!NT_STATUS_IS_OK(domain->last_status))
2694 return domain->last_status;
2696 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2699 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid,
2701 sid_mem, names, name_types);
2703 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2704 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2705 if (!domain->internal && old_status) {
2706 set_domain_offline(domain);
2708 if (!domain->internal &&
2711 NTSTATUS cache_status;
2712 cache_status = wcache_lookup_groupmem(domain, mem_ctx, group_sid,
2713 num_names, sid_mem, names,
2715 return cache_status;
2719 refresh_sequence_number(domain);
2720 if (!NT_STATUS_IS_OK(status)) {
2723 centry = centry_start(domain, status);
2726 centry_put_uint32(centry, *num_names);
2727 for (i=0; i<(*num_names); i++) {
2728 centry_put_sid(centry, &(*sid_mem)[i]);
2729 centry_put_string(centry, (*names)[i]);
2730 centry_put_uint32(centry, (*name_types)[i]);
2732 centry_end(centry, "GM/%s", sid_to_fstring(sid_string, group_sid));
2733 centry_free(centry);
2739 /* find the sequence number for a domain */
2740 NTSTATUS wb_cache_sequence_number(struct winbindd_domain *domain,
2743 refresh_sequence_number(domain);
2745 *seq = domain->sequence_number;
2747 return NT_STATUS_OK;
2750 /* enumerate trusted domains
2751 * (we need to have the list of trustdoms in the cache when we go offline) -
2753 NTSTATUS wb_cache_trusted_domains(struct winbindd_domain *domain,
2754 TALLOC_CTX *mem_ctx,
2755 struct netr_DomainTrustList *trusts)
2758 struct winbind_cache *cache;
2759 struct winbindd_tdc_domain *dom_list = NULL;
2760 size_t num_domains = 0;
2761 bool retval = false;
2765 old_status = domain->online;
2767 trusts->array = NULL;
2769 cache = get_cache(domain);
2770 if (!cache || !cache->tdb) {
2774 if (domain->online) {
2778 retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2779 if (!retval || !num_domains || !dom_list) {
2780 TALLOC_FREE(dom_list);
2785 trusts->array = talloc_zero_array(mem_ctx, struct netr_DomainTrust, num_domains);
2786 if (!trusts->array) {
2787 TALLOC_FREE(dom_list);
2788 return NT_STATUS_NO_MEMORY;
2791 for (i = 0; i < num_domains; i++) {
2792 struct netr_DomainTrust *trust;
2793 struct dom_sid *sid;
2794 struct winbindd_domain *dom;
2796 dom = find_domain_from_name_noinit(dom_list[i].domain_name);
2797 if (dom && dom->internal) {
2801 trust = &trusts->array[trusts->count];
2802 trust->netbios_name = talloc_strdup(trusts->array, dom_list[i].domain_name);
2803 trust->dns_name = talloc_strdup(trusts->array, dom_list[i].dns_name);
2804 sid = talloc(trusts->array, struct dom_sid);
2805 if (!trust->netbios_name || !trust->dns_name ||
2807 TALLOC_FREE(dom_list);
2808 TALLOC_FREE(trusts->array);
2809 return NT_STATUS_NO_MEMORY;
2812 trust->trust_flags = dom_list[i].trust_flags;
2813 trust->trust_attributes = dom_list[i].trust_attribs;
2814 trust->trust_type = dom_list[i].trust_type;
2815 sid_copy(sid, &dom_list[i].sid);
2820 TALLOC_FREE(dom_list);
2821 return NT_STATUS_OK;
2824 /* Return status value returned by seq number check */
2826 if (!NT_STATUS_IS_OK(domain->last_status))
2827 return domain->last_status;
2829 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2832 status = domain->backend->trusted_domains(domain, mem_ctx, trusts);
2834 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2835 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2836 if (!domain->internal && old_status) {
2837 set_domain_offline(domain);
2839 if (!domain->internal &&
2842 retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2843 if (retval && num_domains && dom_list) {
2844 TALLOC_FREE(trusts->array);
2846 goto do_fetch_cache;
2850 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2851 * so that the generic centry handling still applies correctly -
2854 if (!NT_STATUS_IS_ERR(status)) {
2855 status = NT_STATUS_OK;
2860 /* get lockout policy */
2861 NTSTATUS wb_cache_lockout_policy(struct winbindd_domain *domain,
2862 TALLOC_CTX *mem_ctx,
2863 struct samr_DomInfo12 *policy)
2865 struct winbind_cache *cache = get_cache(domain);
2866 struct cache_entry *centry = NULL;
2870 old_status = domain->online;
2874 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2880 policy->lockout_duration = centry_nttime(centry);
2881 policy->lockout_window = centry_nttime(centry);
2882 policy->lockout_threshold = centry_uint16(centry);
2884 status = centry->status;
2886 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2887 domain->name, nt_errstr(status) ));
2889 centry_free(centry);
2893 ZERO_STRUCTP(policy);
2895 /* Return status value returned by seq number check */
2897 if (!NT_STATUS_IS_OK(domain->last_status))
2898 return domain->last_status;
2900 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2903 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2905 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2906 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2907 if (!domain->internal && old_status) {
2908 set_domain_offline(domain);
2911 !domain->internal &&
2914 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2916 goto do_fetch_cache;
2921 refresh_sequence_number(domain);
2922 if (!NT_STATUS_IS_OK(status)) {
2925 wcache_save_lockout_policy(domain, status, policy);
2930 /* get password policy */
2931 NTSTATUS wb_cache_password_policy(struct winbindd_domain *domain,
2932 TALLOC_CTX *mem_ctx,
2933 struct samr_DomInfo1 *policy)
2935 struct winbind_cache *cache = get_cache(domain);
2936 struct cache_entry *centry = NULL;
2940 old_status = domain->online;
2944 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2950 policy->min_password_length = centry_uint16(centry);
2951 policy->password_history_length = centry_uint16(centry);
2952 policy->password_properties = centry_uint32(centry);
2953 policy->max_password_age = centry_nttime(centry);
2954 policy->min_password_age = centry_nttime(centry);
2956 status = centry->status;
2958 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2959 domain->name, nt_errstr(status) ));
2961 centry_free(centry);
2965 ZERO_STRUCTP(policy);
2967 /* Return status value returned by seq number check */
2969 if (!NT_STATUS_IS_OK(domain->last_status))
2970 return domain->last_status;
2972 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2975 status = domain->backend->password_policy(domain, mem_ctx, policy);
2977 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2978 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2979 if (!domain->internal && old_status) {
2980 set_domain_offline(domain);
2983 !domain->internal &&
2986 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2988 goto do_fetch_cache;
2993 refresh_sequence_number(domain);
2994 if (!NT_STATUS_IS_OK(status)) {
2997 wcache_save_password_policy(domain, status, policy);
3003 /* Invalidate cached user and group lists coherently */
3005 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3008 if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
3009 strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
3010 tdb_delete(the_tdb, kbuf);
3015 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3017 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
3018 const struct dom_sid *sid)
3020 fstring key_str, sid_string;
3021 struct winbind_cache *cache;
3023 /* don't clear cached U/SID and UG/SID entries when we want to logon
3026 if (lp_winbind_offline_logon()) {
3033 cache = get_cache(domain);
3039 /* Clear U/SID cache entry */
3040 fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, sid));
3041 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
3042 tdb_delete(cache->tdb, string_tdb_data(key_str));
3044 /* Clear UG/SID cache entry */
3045 fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, sid));
3046 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
3047 tdb_delete(cache->tdb, string_tdb_data(key_str));
3049 /* Samba/winbindd never needs this. */
3050 netsamlogon_clear_cached_user(sid);
3053 bool wcache_invalidate_cache(void)
3055 struct winbindd_domain *domain;
3057 for (domain = domain_list(); domain; domain = domain->next) {
3058 struct winbind_cache *cache = get_cache(domain);
3060 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3061 "entries for %s\n", domain->name));
3064 tdb_traverse(cache->tdb, traverse_fn, NULL);
3073 bool wcache_invalidate_cache_noinit(void)
3075 struct winbindd_domain *domain;
3077 for (domain = domain_list(); domain; domain = domain->next) {
3078 struct winbind_cache *cache;
3080 /* Skip uninitialized domains. */
3081 if (!domain->initialized && !domain->internal) {
3085 cache = get_cache(domain);
3087 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3088 "entries for %s\n", domain->name));
3091 tdb_traverse(cache->tdb, traverse_fn, NULL);
3093 * Flushing cache has nothing to with domains.
3094 * return here if we successfully flushed once.
3095 * To avoid unnecessary traversing the cache.
3106 bool init_wcache(void)
3110 if (wcache == NULL) {
3111 wcache = SMB_XMALLOC_P(struct winbind_cache);
3112 ZERO_STRUCTP(wcache);
3115 if (wcache->tdb != NULL)
3118 db_path = wcache_path();
3119 if (db_path == NULL) {
3123 /* when working offline we must not clear the cache on restart */
3124 wcache->tdb = tdb_open_log(db_path,
3125 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3126 TDB_INCOMPATIBLE_HASH |
3127 (lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
3128 O_RDWR|O_CREAT, 0600);
3129 TALLOC_FREE(db_path);
3130 if (wcache->tdb == NULL) {
3131 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3138 /************************************************************************
3139 This is called by the parent to initialize the cache file.
3140 We don't need sophisticated locking here as we know we're the
3142 ************************************************************************/
3144 bool initialize_winbindd_cache(void)
3146 bool cache_bad = true;
3149 if (!init_wcache()) {
3150 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3154 /* Check version number. */
3155 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
3156 vers == WINBINDD_CACHE_VERSION) {
3163 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3164 "and re-creating with version number %d\n",
3165 WINBINDD_CACHE_VERSION ));
3167 tdb_close(wcache->tdb);
3170 db_path = wcache_path();
3171 if (db_path == NULL) {
3175 if (unlink(db_path) == -1) {
3176 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3179 TALLOC_FREE(db_path);
3182 TALLOC_FREE(db_path);
3183 if (!init_wcache()) {
3184 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3185 "init_wcache failed.\n"));
3189 /* Write the version. */
3190 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
3191 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3192 tdb_errorstr(wcache->tdb) ));
3197 tdb_close(wcache->tdb);
3202 void close_winbindd_cache(void)
3208 tdb_close(wcache->tdb);
3213 bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
3214 char **domain_name, char **name,
3215 enum lsa_SidType *type)
3217 struct winbindd_domain *domain;
3220 domain = find_lookup_domain_from_sid(sid);
3221 if (domain == NULL) {
3224 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
3226 return NT_STATUS_IS_OK(status);
3229 bool lookup_cached_name(const char *domain_name,
3231 struct dom_sid *sid,
3232 enum lsa_SidType *type)
3234 struct winbindd_domain *domain;
3236 bool original_online_state;
3238 domain = find_lookup_domain_from_name(domain_name);
3239 if (domain == NULL) {
3243 /* If we are doing a cached logon, temporarily set the domain
3244 offline so the cache won't expire the entry */
3246 original_online_state = domain->online;
3247 domain->online = false;
3248 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
3249 domain->online = original_online_state;
3251 return NT_STATUS_IS_OK(status);
3255 * Cache a name to sid without checking the sequence number.
3256 * Used when caching from a trusted PAC.
3259 void cache_name2sid_trusted(struct winbindd_domain *domain,
3260 const char *domain_name,
3262 enum lsa_SidType type,
3263 const struct dom_sid *sid)
3266 * Ensure we store the mapping with the
3267 * existing sequence number from the cache.
3270 (void)fetch_cache_seqnum(domain, time(NULL));
3271 wcache_save_name_to_sid(domain,
3279 void cache_name2sid(struct winbindd_domain *domain,
3280 const char *domain_name, const char *name,
3281 enum lsa_SidType type, const struct dom_sid *sid)
3283 refresh_sequence_number(domain);
3284 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
3289 * The original idea that this cache only contains centries has
3290 * been blurred - now other stuff gets put in here. Ensure we
3291 * ignore these things on cleanup.
3294 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
3295 TDB_DATA dbuf, void *state)
3297 struct cache_entry *centry;
3299 if (is_non_centry_key(kbuf)) {
3303 centry = wcache_fetch_raw((char *)kbuf.dptr);
3308 if (!NT_STATUS_IS_OK(centry->status)) {
3309 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
3310 tdb_delete(the_tdb, kbuf);
3313 centry_free(centry);
3317 /* flush the cache */
3318 void wcache_flush_cache(void)
3325 tdb_close(wcache->tdb);
3328 if (!winbindd_use_cache()) {
3332 db_path = wcache_path();
3333 if (db_path == NULL) {
3337 /* when working offline we must not clear the cache on restart */
3338 wcache->tdb = tdb_open_log(db_path,
3339 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3340 TDB_INCOMPATIBLE_HASH |
3341 (lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
3342 O_RDWR|O_CREAT, 0600);
3343 TALLOC_FREE(db_path);
3345 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3349 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
3351 DEBUG(10,("wcache_flush_cache success\n"));
3354 /* Count cached creds */
3356 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3359 int *cred_count = (int*)state;
3361 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3367 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
3369 struct winbind_cache *cache = get_cache(domain);
3374 return NT_STATUS_INTERNAL_DB_ERROR;
3377 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
3379 return NT_STATUS_OK;
3383 struct cred_list *prev, *next;
3388 static struct cred_list *wcache_cred_list;
3390 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3393 struct cred_list *cred;
3395 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3397 cred = SMB_MALLOC_P(struct cred_list);
3399 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3405 /* save a copy of the key */
3407 fstrcpy(cred->name, (const char *)kbuf.dptr);
3408 DLIST_ADD(wcache_cred_list, cred);
3414 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const struct dom_sid *sid)
3416 struct winbind_cache *cache = get_cache(domain);
3419 struct cred_list *cred, *next, *oldest = NULL;
3422 return NT_STATUS_INTERNAL_DB_ERROR;
3425 /* we possibly already have an entry */
3426 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
3428 fstring key_str, tmp;
3430 DEBUG(11,("we already have an entry, deleting that\n"));
3432 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
3434 tdb_delete(cache->tdb, string_tdb_data(key_str));
3436 return NT_STATUS_OK;
3439 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
3441 return NT_STATUS_OK;
3442 } else if ((ret < 0) || (wcache_cred_list == NULL)) {
3443 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3446 ZERO_STRUCTP(oldest);
3448 for (cred = wcache_cred_list; cred; cred = cred->next) {
3453 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
3455 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3457 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
3461 t = IVAL(data.dptr, 0);
3462 SAFE_FREE(data.dptr);
3465 oldest = SMB_MALLOC_P(struct cred_list);
3466 if (oldest == NULL) {
3467 status = NT_STATUS_NO_MEMORY;
3471 fstrcpy(oldest->name, cred->name);
3472 oldest->created = t;
3476 if (t < oldest->created) {
3477 fstrcpy(oldest->name, cred->name);
3478 oldest->created = t;
3482 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
3483 status = NT_STATUS_OK;
3485 status = NT_STATUS_UNSUCCESSFUL;
3488 for (cred = wcache_cred_list; cred; cred = next) {
3490 DLIST_REMOVE(wcache_cred_list, cred);
3498 /* Change the global online/offline state. */
3499 bool set_global_winbindd_state_offline(void)
3503 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3505 /* Only go offline if someone has created
3506 the key "WINBINDD_OFFLINE" in the cache tdb. */
3508 if (wcache == NULL || wcache->tdb == NULL) {
3509 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3513 if (!lp_winbind_offline_logon()) {
3514 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3518 if (global_winbindd_offline_state) {
3519 /* Already offline. */
3523 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
3525 if (!data.dptr || data.dsize != 4) {
3526 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3527 SAFE_FREE(data.dptr);
3530 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3531 global_winbindd_offline_state = true;
3532 SAFE_FREE(data.dptr);
3537 void set_global_winbindd_state_online(void)
3539 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3541 if (!lp_winbind_offline_logon()) {
3542 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3546 if (!global_winbindd_offline_state) {
3547 /* Already online. */
3550 global_winbindd_offline_state = false;
3556 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3557 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
3560 bool get_global_winbindd_state_offline(void)
3562 return global_winbindd_offline_state;
3565 /***********************************************************************
3566 Validate functions for all possible cache tdb keys.
3567 ***********************************************************************/
3569 static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
3570 struct tdb_validation_status *state)
3572 struct cache_entry *centry;
3574 centry = SMB_XMALLOC_P(struct cache_entry);
3575 centry->data = (unsigned char *)smb_memdup(data.dptr, data.dsize);
3576 if (!centry->data) {
3580 centry->len = data.dsize;
3583 if (centry->len < 16) {
3584 /* huh? corrupt cache? */
3585 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3586 "(len < 16) ?\n", kstr));
3587 centry_free(centry);
3588 state->bad_entry = true;
3589 state->success = false;
3593 centry->status = NT_STATUS(centry_uint32(centry));
3594 centry->sequence_number = centry_uint32(centry);
3595 centry->timeout = centry_uint64_t(centry);
3599 static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3600 struct tdb_validation_status *state)
3602 if (dbuf.dsize != 8) {
3603 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3604 keystr, (unsigned int)dbuf.dsize ));
3605 state->bad_entry = true;
3611 static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3612 struct tdb_validation_status *state)
3614 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3619 (void)centry_uint32(centry);
3620 if (NT_STATUS_IS_OK(centry->status)) {
3622 (void)centry_sid(centry, &sid);
3625 centry_free(centry);
3627 if (!(state->success)) {
3630 DEBUG(10,("validate_ns: %s ok\n", keystr));
3634 static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3635 struct tdb_validation_status *state)
3637 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3642 if (NT_STATUS_IS_OK(centry->status)) {
3643 (void)centry_uint32(centry);
3644 (void)centry_string(centry, mem_ctx);
3645 (void)centry_string(centry, mem_ctx);
3648 centry_free(centry);
3650 if (!(state->success)) {
3653 DEBUG(10,("validate_sn: %s ok\n", keystr));
3657 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3658 struct tdb_validation_status *state)
3660 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3667 (void)centry_string(centry, mem_ctx);
3668 (void)centry_string(centry, mem_ctx);
3669 (void)centry_string(centry, mem_ctx);
3670 (void)centry_string(centry, mem_ctx);
3671 (void)centry_string(centry, mem_ctx);
3672 (void)centry_uint32(centry);
3673 (void)centry_uint32(centry);
3674 (void)centry_string(centry, mem_ctx);
3675 (void)centry_sid(centry, &sid);
3676 (void)centry_sid(centry, &sid);
3678 centry_free(centry);
3680 if (!(state->success)) {
3683 DEBUG(10,("validate_u: %s ok\n", keystr));
3687 static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3688 struct tdb_validation_status *state)
3690 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3696 (void)centry_nttime(centry);
3697 (void)centry_nttime(centry);
3698 (void)centry_uint16(centry);
3700 centry_free(centry);
3702 if (!(state->success)) {
3705 DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
3709 static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3710 struct tdb_validation_status *state)
3712 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3718 (void)centry_uint16(centry);
3719 (void)centry_uint16(centry);
3720 (void)centry_uint32(centry);
3721 (void)centry_nttime(centry);
3722 (void)centry_nttime(centry);
3724 centry_free(centry);
3726 if (!(state->success)) {
3729 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
3733 static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3734 struct tdb_validation_status *state)
3736 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3742 (void)centry_time(centry);
3743 (void)centry_hash16(centry, mem_ctx);
3745 /* We only have 17 bytes more data in the salted cred case. */
3746 if (centry->len - centry->ofs == 17) {
3747 (void)centry_hash16(centry, mem_ctx);
3750 centry_free(centry);
3752 if (!(state->success)) {
3755 DEBUG(10,("validate_cred: %s ok\n", keystr));
3759 static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3760 struct tdb_validation_status *state)
3762 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3763 int32_t num_entries, i;
3769 num_entries = (int32_t)centry_uint32(centry);
3771 for (i=0; i< num_entries; i++) {
3772 (void)centry_uint32(centry);
3775 centry_free(centry);
3777 if (!(state->success)) {
3780 DEBUG(10,("validate_ul: %s ok\n", keystr));
3784 static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3785 struct tdb_validation_status *state)
3787 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3788 int32_t num_entries, i;
3794 num_entries = centry_uint32(centry);
3796 for (i=0; i< num_entries; i++) {
3797 (void)centry_string(centry, mem_ctx);
3798 (void)centry_string(centry, mem_ctx);
3799 (void)centry_uint32(centry);
3802 centry_free(centry);
3804 if (!(state->success)) {
3807 DEBUG(10,("validate_gl: %s ok\n", keystr));
3811 static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3812 struct tdb_validation_status *state)
3814 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3815 int32_t num_groups, i;
3821 num_groups = centry_uint32(centry);
3823 for (i=0; i< num_groups; i++) {
3825 centry_sid(centry, &sid);
3828 centry_free(centry);
3830 if (!(state->success)) {
3833 DEBUG(10,("validate_ug: %s ok\n", keystr));
3837 static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3838 struct tdb_validation_status *state)
3840 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3841 int32_t num_aliases, i;
3847 num_aliases = centry_uint32(centry);
3849 for (i=0; i < num_aliases; i++) {
3850 (void)centry_uint32(centry);
3853 centry_free(centry);
3855 if (!(state->success)) {
3858 DEBUG(10,("validate_ua: %s ok\n", keystr));
3862 static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3863 struct tdb_validation_status *state)
3865 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3866 int32_t num_names, i;
3872 num_names = centry_uint32(centry);
3874 for (i=0; i< num_names; i++) {
3876 centry_sid(centry, &sid);
3877 (void)centry_string(centry, mem_ctx);
3878 (void)centry_uint32(centry);
3881 centry_free(centry);
3883 if (!(state->success)) {
3886 DEBUG(10,("validate_gm: %s ok\n", keystr));
3890 static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3891 struct tdb_validation_status *state)
3893 /* Can't say anything about this other than must be nonzero. */
3894 if (dbuf.dsize == 0) {
3895 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3897 state->bad_entry = true;
3898 state->success = false;
3902 DEBUG(10,("validate_dr: %s ok\n", keystr));
3906 static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3907 struct tdb_validation_status *state)
3909 /* Can't say anything about this other than must be nonzero. */
3910 if (dbuf.dsize == 0) {
3911 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3913 state->bad_entry = true;
3914 state->success = false;
3918 DEBUG(10,("validate_de: %s ok\n", keystr));
3922 static int validate_nss_an(TALLOC_CTX *mem_ctx, const char *keystr,
3924 struct tdb_validation_status *state)
3926 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3932 (void)centry_string( centry, mem_ctx );
3934 centry_free(centry);
3936 if (!(state->success)) {
3939 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3943 static int validate_nss_na(TALLOC_CTX *mem_ctx, const char *keystr,
3945 struct tdb_validation_status *state)
3947 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3953 (void)centry_string( centry, mem_ctx );
3955 centry_free(centry);
3957 if (!(state->success)) {
3960 DBG_DEBUG("%s ok\n", keystr);
3964 static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
3966 struct tdb_validation_status *state)
3968 if (dbuf.dsize == 0) {
3969 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3970 "key %s (len ==0) ?\n", keystr));
3971 state->bad_entry = true;
3972 state->success = false;
3976 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
3977 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3981 static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3982 struct tdb_validation_status *state)
3984 if (dbuf.dsize != 4) {
3985 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3986 keystr, (unsigned int)dbuf.dsize ));
3987 state->bad_entry = true;
3988 state->success = false;
3991 DEBUG(10,("validate_offline: %s ok\n", keystr));
3995 static int validate_ndr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3996 struct tdb_validation_status *state)
3999 * Ignore validation for now. The proper way to do this is with a
4000 * checksum. Just pure parsing does not really catch much.
4005 static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
4006 struct tdb_validation_status *state)
4008 if (dbuf.dsize != 4) {
4009 DEBUG(0, ("validate_cache_version: Corrupt cache for "
4010 "key %s (len %u != 4) ?\n",
4011 keystr, (unsigned int)dbuf.dsize));
4012 state->bad_entry = true;
4013 state->success = false;
4017 DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
4021 /***********************************************************************
4022 A list of all possible cache tdb keys with associated validation
4024 ***********************************************************************/
4026 struct key_val_struct {
4027 const char *keyname;
4028 int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
4030 {"SEQNUM/", validate_seqnum},
4031 {"NS/", validate_ns},
4032 {"SN/", validate_sn},
4034 {"LOC_POL/", validate_loc_pol},
4035 {"PWD_POL/", validate_pwd_pol},
4036 {"CRED/", validate_cred},
4037 {"UL/", validate_ul},
4038 {"GL/", validate_gl},
4039 {"UG/", validate_ug},
4040 {"UA", validate_ua},
4041 {"GM/", validate_gm},
4042 {"DR/", validate_dr},
4043 {"DE/", validate_de},
4044 {"TRUSTDOMCACHE/", validate_trustdomcache},
4045 {"NSS/NA/", validate_nss_na},
4046 {"NSS/AN/", validate_nss_an},
4047 {"WINBINDD_OFFLINE", validate_offline},
4048 {"NDR/", validate_ndr},
4049 {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
4053 /***********************************************************************
4054 Function to look at every entry in the tdb and validate it as far as
4056 ***********************************************************************/
4058 static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
4061 unsigned int max_key_len = 1024;
4062 struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
4064 /* Paranoia check. */
4065 if (strncmp("UA/", (const char *)kbuf.dptr, 3) == 0 ||
4066 strncmp("NDR/", (const char *)kbuf.dptr, 4) == 0) {
4067 max_key_len = 1024 * 1024;
4069 if (kbuf.dsize > max_key_len) {
4070 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4072 (unsigned int)kbuf.dsize, (unsigned int)max_key_len));
4076 for (i = 0; key_val[i].keyname; i++) {
4077 size_t namelen = strlen(key_val[i].keyname);
4078 if (kbuf.dsize >= namelen && (
4079 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
4080 TALLOC_CTX *mem_ctx;
4084 keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
4088 memcpy(keystr, kbuf.dptr, kbuf.dsize);
4089 keystr[kbuf.dsize] = '\0';
4091 mem_ctx = talloc_init("validate_ctx");
4097 ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
4101 talloc_destroy(mem_ctx);
4106 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4107 dump_data(0, (uint8_t *)kbuf.dptr, kbuf.dsize);
4108 DEBUG(0,("data :\n"));
4109 dump_data(0, (uint8_t *)dbuf.dptr, dbuf.dsize);
4110 v_state->unknown_key = true;
4111 v_state->success = false;
4112 return 1; /* terminate. */
4115 static void validate_panic(const char *const why)
4117 DEBUG(0,("validating cache: would panic %s\n", why ));
4118 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4122 static int wbcache_update_centry_fn(TDB_CONTEXT *tdb,
4130 if (is_non_centry_key(key)) {
4134 if (data.dptr == NULL || data.dsize == 0) {
4135 if (tdb_delete(tdb, key) < 0) {
4136 DEBUG(0, ("tdb_delete for [%s] failed!\n",
4142 /* add timeout to blob (uint64_t) */
4143 blob.dsize = data.dsize + 8;
4145 blob.dptr = SMB_XMALLOC_ARRAY(uint8_t, blob.dsize);
4146 if (blob.dptr == NULL) {
4149 memset(blob.dptr, 0, blob.dsize);
4151 /* copy status and seqnum */
4152 memcpy(blob.dptr, data.dptr, 8);
4155 ctimeout = lp_winbind_cache_time() + time(NULL);
4156 SBVAL(blob.dptr, 8, ctimeout);
4159 memcpy(blob.dptr + 16, data.dptr + 8, data.dsize - 8);
4161 if (tdb_store(tdb, key, blob, TDB_REPLACE) < 0) {
4162 DEBUG(0, ("tdb_store to update [%s] failed!\n",
4164 SAFE_FREE(blob.dptr);
4168 SAFE_FREE(blob.dptr);
4172 static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT *tdb)
4176 DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
4178 rc = tdb_traverse(tdb, wbcache_update_centry_fn, NULL);
4186 /***********************************************************************
4187 Try and validate every entry in the winbindd cache. If we fail here,
4188 delete the cache tdb and return non-zero.
4189 ***********************************************************************/
4191 int winbindd_validate_cache(void)
4194 char *tdb_path = NULL;
4195 TDB_CONTEXT *tdb = NULL;
4199 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4200 smb_panic_fn = validate_panic;
4202 tdb_path = wcache_path();
4203 if (tdb_path == NULL) {
4207 tdb = tdb_open_log(tdb_path,
4208 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
4209 TDB_INCOMPATIBLE_HASH |
4210 ( lp_winbind_offline_logon()
4212 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
4216 DEBUG(0, ("winbindd_validate_cache: "
4217 "error opening/initializing tdb\n"));
4221 /* Version check and upgrade code. */
4222 if (!tdb_fetch_uint32(tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers_id)) {
4223 DEBUG(10, ("Fresh database\n"));
4224 tdb_store_uint32(tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION);
4225 vers_id = WINBINDD_CACHE_VERSION;
4228 if (vers_id != WINBINDD_CACHE_VERSION) {
4229 if (vers_id == WINBINDD_CACHE_VER1) {
4230 ok = wbcache_upgrade_v1_to_v2(tdb);
4232 DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
4237 tdb_store_uint32(tdb,
4238 WINBINDD_CACHE_VERSION_KEYSTR,
4239 WINBINDD_CACHE_VERSION);
4240 vers_id = WINBINDD_CACHE_VER2;
4246 ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
4249 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4250 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
4255 TALLOC_FREE(tdb_path);
4256 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4257 smb_panic_fn = smb_panic;
4261 /***********************************************************************
4262 Try and validate every entry in the winbindd cache.
4263 ***********************************************************************/
4265 int winbindd_validate_cache_nobackup(void)
4270 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4271 smb_panic_fn = validate_panic;
4273 tdb_path = wcache_path();
4274 if (tdb_path == NULL) {
4275 goto err_panic_restore;
4278 if (wcache == NULL || wcache->tdb == NULL) {
4279 ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
4281 ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
4285 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4289 TALLOC_FREE(tdb_path);
4291 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4293 smb_panic_fn = smb_panic;
4297 bool winbindd_cache_validate_and_initialize(void)
4299 close_winbindd_cache();
4301 if (lp_winbind_offline_logon()) {
4302 if (winbindd_validate_cache() < 0) {
4303 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4304 "could be restored.\n"));
4308 return initialize_winbindd_cache();
4311 /*********************************************************************
4312 ********************************************************************/
4314 static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
4315 struct winbindd_tdc_domain **domains,
4316 size_t *num_domains )
4318 struct winbindd_tdc_domain *list = NULL;
4321 bool set_only = false;
4323 /* don't allow duplicates */
4328 for ( i=0; i< (*num_domains); i++ ) {
4329 if ( strequal( new_dom->name, list[i].domain_name ) ) {
4330 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4341 list = talloc_array( NULL, struct winbindd_tdc_domain, 1 );
4344 list = talloc_realloc( *domains, *domains,
4345 struct winbindd_tdc_domain,
4350 ZERO_STRUCT( list[idx] );
4356 list[idx].domain_name = talloc_strdup(list, new_dom->name);
4357 if (list[idx].domain_name == NULL) {
4360 if (new_dom->alt_name != NULL) {
4361 list[idx].dns_name = talloc_strdup(list, new_dom->alt_name);
4362 if (list[idx].dns_name == NULL) {
4367 if ( !is_null_sid( &new_dom->sid ) ) {
4368 sid_copy( &list[idx].sid, &new_dom->sid );
4370 sid_copy(&list[idx].sid, &global_sid_NULL);
4373 if ( new_dom->domain_flags != 0x0 )
4374 list[idx].trust_flags = new_dom->domain_flags;
4376 if ( new_dom->domain_type != 0x0 )
4377 list[idx].trust_type = new_dom->domain_type;
4379 if ( new_dom->domain_trust_attribs != 0x0 )
4380 list[idx].trust_attribs = new_dom->domain_trust_attribs;
4384 *num_domains = idx + 1;
4390 /*********************************************************************
4391 ********************************************************************/
4393 static TDB_DATA make_tdc_key( const char *domain_name )
4395 char *keystr = NULL;
4396 TDB_DATA key = { NULL, 0 };
4398 if ( !domain_name ) {
4399 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4403 if (asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name ) == -1) {
4406 key = string_term_tdb_data(keystr);
4411 /*********************************************************************
4412 ********************************************************************/
4414 static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
4416 unsigned char **buf )
4418 unsigned char *buffer = NULL;
4423 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4431 /* Store the number of array items first */
4432 len += tdb_pack( buffer+len, buflen-len, "d",
4435 /* now pack each domain trust record */
4436 for ( i=0; i<num_domains; i++ ) {
4441 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4442 domains[i].domain_name,
4443 domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
4446 len += tdb_pack( buffer+len, buflen-len, "fffddd",
4447 domains[i].domain_name,
4448 domains[i].dns_name ? domains[i].dns_name : "",
4449 sid_to_fstring(tmp, &domains[i].sid),
4450 domains[i].trust_flags,
4451 domains[i].trust_attribs,
4452 domains[i].trust_type );
4455 if ( buflen < len ) {
4457 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
4458 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4472 /*********************************************************************
4473 ********************************************************************/
4475 static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
4476 struct winbindd_tdc_domain **domains )
4478 fstring domain_name, dns_name, sid_string;
4479 uint32_t type, attribs, flags;
4483 struct winbindd_tdc_domain *list = NULL;
4485 /* get the number of domains */
4486 len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
4488 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4492 list = talloc_array( NULL, struct winbindd_tdc_domain, num_domains );
4494 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4498 for ( i=0; i<num_domains; i++ ) {
4501 this_len = tdb_unpack( buf+len, buflen-len, "fffddd",
4509 if ( this_len == -1 ) {
4510 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4511 TALLOC_FREE( list );
4516 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4517 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4518 domain_name, dns_name, sid_string,
4519 flags, attribs, type));
4521 list[i].domain_name = talloc_strdup( list, domain_name );
4522 list[i].dns_name = NULL;
4523 if (dns_name[0] != '\0') {
4524 list[i].dns_name = talloc_strdup(list, dns_name);
4526 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
4527 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4530 list[i].trust_flags = flags;
4531 list[i].trust_attribs = attribs;
4532 list[i].trust_type = type;
4540 /*********************************************************************
4541 ********************************************************************/
4543 static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
4545 TDB_DATA key = make_tdc_key( lp_workgroup() );
4546 TDB_DATA data = { NULL, 0 };
4552 /* See if we were asked to delete the cache entry */
4555 ret = tdb_delete( wcache->tdb, key );
4559 data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
4566 ret = tdb_store( wcache->tdb, key, data, 0 );
4569 SAFE_FREE( data.dptr );
4570 SAFE_FREE( key.dptr );
4572 return ( ret == 0 );
4575 /*********************************************************************
4576 ********************************************************************/
4578 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
4580 TDB_DATA key = make_tdc_key( lp_workgroup() );
4581 TDB_DATA data = { NULL, 0 };
4589 data = tdb_fetch( wcache->tdb, key );
4591 SAFE_FREE( key.dptr );
4596 *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
4598 SAFE_FREE( data.dptr );
4606 /*********************************************************************
4607 ********************************************************************/
4609 bool wcache_tdc_add_domain( struct winbindd_domain *domain )
4611 struct winbindd_tdc_domain *dom_list = NULL;
4612 size_t num_domains = 0;
4615 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4616 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4617 domain->name, domain->alt_name,
4618 sid_string_dbg(&domain->sid),
4619 domain->domain_flags,
4620 domain->domain_trust_attribs,
4621 domain->domain_type));
4623 if ( !init_wcache() ) {
4627 /* fetch the list */
4629 wcache_tdc_fetch_list( &dom_list, &num_domains );
4631 /* add the new domain */
4633 if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
4637 /* pack the domain */
4639 if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
4647 TALLOC_FREE( dom_list );
4652 static struct winbindd_tdc_domain *wcache_tdc_dup_domain(
4653 TALLOC_CTX *mem_ctx, const struct winbindd_tdc_domain *src)
4655 struct winbindd_tdc_domain *dst;
4657 dst = talloc(mem_ctx, struct winbindd_tdc_domain);
4661 dst->domain_name = talloc_strdup(dst, src->domain_name);
4662 if (dst->domain_name == NULL) {
4666 dst->dns_name = NULL;
4667 if (src->dns_name != NULL) {
4668 dst->dns_name = talloc_strdup(dst, src->dns_name);
4669 if (dst->dns_name == NULL) {
4674 sid_copy(&dst->sid, &src->sid);
4675 dst->trust_flags = src->trust_flags;
4676 dst->trust_type = src->trust_type;
4677 dst->trust_attribs = src->trust_attribs;
4684 /*********************************************************************
4685 ********************************************************************/
4687 struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
4689 struct winbindd_tdc_domain *dom_list = NULL;
4690 size_t num_domains = 0;
4692 struct winbindd_tdc_domain *d = NULL;
4694 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
4696 if ( !init_wcache() ) {
4700 /* fetch the list */
4702 wcache_tdc_fetch_list( &dom_list, &num_domains );
4704 for ( i=0; i<num_domains; i++ ) {
4705 if ( strequal(name, dom_list[i].domain_name) ||
4706 strequal(name, dom_list[i].dns_name) )
4708 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4711 d = wcache_tdc_dup_domain(ctx, &dom_list[i]);
4716 TALLOC_FREE( dom_list );
4721 /*********************************************************************
4722 ********************************************************************/
4724 void wcache_tdc_clear( void )
4726 if ( !init_wcache() )
4729 wcache_tdc_store_list( NULL, 0 );
4734 static bool wcache_ndr_key(TALLOC_CTX *mem_ctx, const char *domain_name,
4735 uint32_t opnum, const DATA_BLOB *req,
4741 key = talloc_asprintf(mem_ctx, "NDR/%s/%d/", domain_name, (int)opnum);
4745 keylen = talloc_get_size(key) - 1;
4747 key = talloc_realloc(mem_ctx, key, char, keylen + req->length);
4751 memcpy(key + keylen, req->data, req->length);
4753 pkey->dptr = (uint8_t *)key;
4754 pkey->dsize = talloc_get_size(key);
4758 static bool wcache_opnum_cacheable(uint32_t opnum)
4761 case NDR_WBINT_PING:
4762 case NDR_WBINT_QUERYSEQUENCENUMBER:
4763 case NDR_WBINT_ALLOCATEUID:
4764 case NDR_WBINT_ALLOCATEGID:
4765 case NDR_WBINT_CHECKMACHINEACCOUNT:
4766 case NDR_WBINT_CHANGEMACHINEACCOUNT:
4767 case NDR_WBINT_PINGDC:
4773 bool wcache_fetch_ndr(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
4774 uint32_t opnum, const DATA_BLOB *req, DATA_BLOB *resp)
4779 if (!wcache_opnum_cacheable(opnum) ||
4780 is_my_own_sam_domain(domain) ||
4781 is_builtin_domain(domain)) {
4785 if (wcache->tdb == NULL) {
4789 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4792 data = tdb_fetch(wcache->tdb, key);
4793 TALLOC_FREE(key.dptr);
4795 if (data.dptr == NULL) {
4798 if (data.dsize < 12) {
4802 if (!is_domain_offline(domain)) {
4803 uint32_t entry_seqnum, dom_seqnum, last_check;
4804 uint64_t entry_timeout;
4806 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum,
4810 entry_seqnum = IVAL(data.dptr, 0);
4811 if (entry_seqnum != dom_seqnum) {
4812 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4813 (int)entry_seqnum));
4816 entry_timeout = BVAL(data.dptr, 4);
4817 if (time(NULL) > entry_timeout) {
4818 DEBUG(10, ("Entry has timed out\n"));
4823 resp->data = (uint8_t *)talloc_memdup(mem_ctx, data.dptr + 12,
4825 if (resp->data == NULL) {
4826 DEBUG(10, ("talloc failed\n"));
4829 resp->length = data.dsize - 12;
4833 SAFE_FREE(data.dptr);
4837 void wcache_store_ndr(struct winbindd_domain *domain, uint32_t opnum,
4838 const DATA_BLOB *req, const DATA_BLOB *resp)
4841 uint32_t dom_seqnum, last_check;
4844 if (!wcache_opnum_cacheable(opnum) ||
4845 is_my_own_sam_domain(domain) ||
4846 is_builtin_domain(domain)) {
4850 if (wcache->tdb == NULL) {
4854 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum, &last_check)) {
4855 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4860 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4864 timeout = time(NULL) + lp_winbind_cache_time();
4866 data.dsize = resp->length + 12;
4867 data.dptr = talloc_array(key.dptr, uint8_t, data.dsize);
4868 if (data.dptr == NULL) {
4872 SIVAL(data.dptr, 0, dom_seqnum);
4873 SBVAL(data.dptr, 4, timeout);
4874 memcpy(data.dptr + 12, resp->data, resp->length);
4876 tdb_store(wcache->tdb, key, data, 0);
4879 TALLOC_FREE(key.dptr);