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))
140 domain->backend = &sam_passdb_methods;
143 if (!domain->initialized) {
144 /* We do not need a connection to an RW DC for cache operation */
145 init_dc_connection(domain, false);
149 OK. Listen up because I'm only going to say this once.
150 We have the following scenarios to consider
151 (a) trusted AD domains on a Samba DC,
152 (b) trusted AD domains and we are joined to a non-kerberos domain
153 (c) trusted AD domains and we are joined to a kerberos (AD) domain
155 For (a) we can always contact the trusted domain using krb5
156 since we have the domain trust account password
158 For (b) we can only use RPC since we have no way of
159 getting a krb5 ticket in our own domain
161 For (c) we can always use krb5 since we have a kerberos trust
167 if (domain->backend == NULL) {
168 struct winbindd_domain *our_domain = domain;
170 /* find our domain first so we can figure out if we
171 are joined to a kerberized domain */
173 if (!domain->primary) {
174 our_domain = find_our_domain();
177 if ((our_domain->active_directory || IS_DC)
178 && domain->active_directory
179 && !lp_winbind_rpc_only())
181 DBG_INFO("Setting ADS methods for domain %s\n",
183 domain->backend = &reconnect_ads_methods;
186 #endif /* HAVE_ADS */
188 if (domain->backend == NULL) {
189 DBG_INFO("Setting MS-RPC methods for domain %s\n", domain->name);
190 domain->backend = &reconnect_methods;
197 ret = SMB_XMALLOC_P(struct winbind_cache);
201 wcache_flush_cache();
207 free a centry structure
209 static void centry_free(struct cache_entry *centry)
213 SAFE_FREE(centry->data);
217 static bool centry_check_bytes(struct cache_entry *centry, size_t nbytes)
219 if (centry->len - centry->ofs < nbytes) {
220 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
221 (unsigned int)nbytes,
222 centry->len - centry->ofs));
229 pull a uint64_t from a cache entry
231 static uint64_t centry_uint64_t(struct cache_entry *centry)
235 if (!centry_check_bytes(centry, 8)) {
236 smb_panic_fn("centry_uint64_t");
238 ret = BVAL(centry->data, centry->ofs);
244 pull a uint32_t from a cache entry
246 static uint32_t centry_uint32(struct cache_entry *centry)
250 if (!centry_check_bytes(centry, 4)) {
251 smb_panic_fn("centry_uint32");
253 ret = IVAL(centry->data, centry->ofs);
259 pull a uint16_t from a cache entry
261 static uint16_t centry_uint16(struct cache_entry *centry)
264 if (!centry_check_bytes(centry, 2)) {
265 smb_panic_fn("centry_uint16");
267 ret = SVAL(centry->data, centry->ofs);
273 pull a uint8_t from a cache entry
275 static uint8_t centry_uint8(struct cache_entry *centry)
278 if (!centry_check_bytes(centry, 1)) {
279 smb_panic_fn("centry_uint8");
281 ret = CVAL(centry->data, centry->ofs);
287 pull a NTTIME from a cache entry
289 static NTTIME centry_nttime(struct cache_entry *centry)
292 if (!centry_check_bytes(centry, 8)) {
293 smb_panic_fn("centry_nttime");
295 ret = IVAL(centry->data, centry->ofs);
297 ret += (uint64_t)IVAL(centry->data, centry->ofs) << 32;
303 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
305 static time_t centry_time(struct cache_entry *centry)
307 return (time_t)centry_nttime(centry);
310 /* pull a string from a cache entry, using the supplied
313 static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
318 len = centry_uint8(centry);
321 /* a deliberate NULL string */
325 if (!centry_check_bytes(centry, (size_t)len)) {
326 smb_panic_fn("centry_string");
329 ret = talloc_array(mem_ctx, char, len+1);
331 smb_panic_fn("centry_string out of memory\n");
333 memcpy(ret,centry->data + centry->ofs, len);
339 /* pull a hash16 from a cache entry, using the supplied
342 static char *centry_hash16(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
347 len = centry_uint8(centry);
350 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
355 if (!centry_check_bytes(centry, 16)) {
359 ret = talloc_array(mem_ctx, char, 16);
361 smb_panic_fn("centry_hash out of memory\n");
363 memcpy(ret,centry->data + centry->ofs, 16);
368 /* pull a sid from a cache entry, using the supplied
371 static bool centry_sid(struct cache_entry *centry, struct dom_sid *sid)
376 sid_string = centry_string(centry, talloc_tos());
377 if (sid_string == NULL) {
380 ret = string_to_sid(sid, sid_string);
381 TALLOC_FREE(sid_string);
387 pull a NTSTATUS from a cache entry
389 static NTSTATUS centry_ntstatus(struct cache_entry *centry)
393 status = NT_STATUS(centry_uint32(centry));
398 /* the server is considered down if it can't give us a sequence number */
399 static bool wcache_server_down(struct winbindd_domain *domain)
406 ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
409 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
414 struct wcache_seqnum_state {
416 uint32_t *last_seq_check;
419 static int wcache_seqnum_parser(TDB_DATA key, TDB_DATA data,
422 struct wcache_seqnum_state *state = private_data;
424 if (data.dsize != 8) {
425 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
430 *state->seqnum = IVAL(data.dptr, 0);
431 *state->last_seq_check = IVAL(data.dptr, 4);
435 static bool wcache_fetch_seqnum(const char *domain_name, uint32_t *seqnum,
436 uint32_t *last_seq_check)
438 struct wcache_seqnum_state state = {
439 .seqnum = seqnum, .last_seq_check = last_seq_check
441 size_t len = strlen(domain_name);
443 TDB_DATA key = { .dptr = (uint8_t *)keystr, .dsize = sizeof(keystr) };
446 if (wcache->tdb == NULL) {
447 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
451 snprintf(keystr, sizeof(keystr), "SEQNUM/%s", domain_name);
453 ret = tdb_parse_record(wcache->tdb, key, wcache_seqnum_parser,
458 static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
460 uint32_t last_check, time_diff;
462 if (!wcache_fetch_seqnum(domain->name, &domain->sequence_number,
464 return NT_STATUS_UNSUCCESSFUL;
466 domain->last_seq_check = last_check;
468 /* have we expired? */
470 time_diff = now - domain->last_seq_check;
471 if ( time_diff > lp_winbind_cache_time() ) {
472 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
473 domain->name, domain->sequence_number,
474 (uint32_t)domain->last_seq_check));
475 return NT_STATUS_UNSUCCESSFUL;
478 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
479 domain->name, domain->sequence_number,
480 (uint32_t)domain->last_seq_check));
485 bool wcache_store_seqnum(const char *domain_name, uint32_t seqnum,
486 time_t last_seq_check)
488 size_t len = strlen(domain_name);
490 TDB_DATA key = { .dptr = (uint8_t *)keystr, .dsize = sizeof(keystr) };
494 if (wcache->tdb == NULL) {
495 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
499 snprintf(keystr, sizeof(keystr), "SEQNUM/%s", domain_name);
501 SIVAL(buf, 0, seqnum);
502 SIVAL(buf, 4, last_seq_check);
504 ret = tdb_store(wcache->tdb, key, make_tdb_data(buf, sizeof(buf)),
507 DEBUG(10, ("tdb_store_bystring failed: %s\n",
508 tdb_errorstr(wcache->tdb)));
512 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
513 domain_name, seqnum, (unsigned)last_seq_check));
518 static bool store_cache_seqnum( struct winbindd_domain *domain )
520 return wcache_store_seqnum(domain->name, domain->sequence_number,
521 domain->last_seq_check);
525 refresh the domain sequence number on timeout.
528 static void refresh_sequence_number(struct winbindd_domain *domain)
532 time_t t = time(NULL);
533 unsigned cache_time = lp_winbind_cache_time();
535 if (is_domain_offline(domain)) {
541 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
542 /* trying to reconnect is expensive, don't do it too often */
543 if (domain->sequence_number == DOM_SEQUENCE_NONE) {
548 time_diff = t - domain->last_seq_check;
550 /* see if we have to refetch the domain sequence number */
551 if ((time_diff < cache_time) &&
552 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
553 NT_STATUS_IS_OK(domain->last_status)) {
554 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
558 /* try to get the sequence number from the tdb cache first */
559 /* this will update the timestamp as well */
561 status = fetch_cache_seqnum( domain, t );
562 if (NT_STATUS_IS_OK(status) &&
563 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
564 NT_STATUS_IS_OK(domain->last_status)) {
568 /* important! make sure that we know if this is a native
569 mode domain or not. And that we can contact it. */
571 if ( winbindd_can_contact_domain( domain ) ) {
572 status = domain->backend->sequence_number(domain,
573 &domain->sequence_number);
575 /* just use the current time */
576 status = NT_STATUS_OK;
577 domain->sequence_number = time(NULL);
581 /* the above call could have set our domain->backend to NULL when
582 * coming from offline to online mode, make sure to reinitialize the
583 * backend - Guenther */
586 if (!NT_STATUS_IS_OK(status)) {
587 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status)));
588 domain->sequence_number = DOM_SEQUENCE_NONE;
591 domain->last_status = status;
592 domain->last_seq_check = time(NULL);
594 /* save the new sequence number in the cache */
595 store_cache_seqnum( domain );
598 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
599 domain->name, domain->sequence_number));
605 decide if a cache entry has expired
607 static bool centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
609 /* If we've been told to be offline - stay in that state... */
610 if (lp_winbind_offline_logon() && global_winbindd_offline_state) {
611 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
612 keystr, domain->name ));
616 /* when the domain is offline return the cached entry.
617 * This deals with transient offline states... */
619 if (!domain->online) {
620 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
621 keystr, domain->name ));
625 /* if the server is OK and our cache entry came from when it was down then
626 the entry is invalid */
627 if ((domain->sequence_number != DOM_SEQUENCE_NONE) &&
628 (centry->sequence_number == DOM_SEQUENCE_NONE)) {
629 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
630 keystr, domain->name ));
634 /* if the server is down or the cache entry is not older than the
635 current sequence number or it did not timeout then it is OK */
636 if (wcache_server_down(domain)
637 || ((centry->sequence_number == domain->sequence_number)
638 && (centry->timeout > time(NULL)))) {
639 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
640 keystr, domain->name ));
644 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
645 keystr, domain->name ));
651 static struct cache_entry *wcache_fetch_raw(char *kstr)
654 struct cache_entry *centry;
657 key = string_tdb_data(kstr);
658 data = tdb_fetch(wcache->tdb, key);
664 centry = SMB_XMALLOC_P(struct cache_entry);
665 centry->data = (unsigned char *)data.dptr;
666 centry->len = data.dsize;
669 if (centry->len < 16) {
670 /* huh? corrupt cache? */
671 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s "
672 "(len < 16)?\n", kstr));
677 centry->status = centry_ntstatus(centry);
678 centry->sequence_number = centry_uint32(centry);
679 centry->timeout = centry_uint64_t(centry);
684 static bool is_my_own_sam_domain(struct winbindd_domain *domain)
686 if (strequal(domain->name, get_global_sam_name()) &&
687 sid_check_is_our_sam(&domain->sid)) {
694 static bool is_builtin_domain(struct winbindd_domain *domain)
696 if (strequal(domain->name, "BUILTIN") &&
697 sid_check_is_builtin(&domain->sid)) {
705 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
706 number and return status
708 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
709 struct winbindd_domain *domain,
710 const char *format, ...) PRINTF_ATTRIBUTE(3,4);
711 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
712 struct winbindd_domain *domain,
713 const char *format, ...)
717 struct cache_entry *centry;
719 if (!winbindd_use_cache() ||
720 is_my_own_sam_domain(domain) ||
721 is_builtin_domain(domain)) {
725 refresh_sequence_number(domain);
727 va_start(ap, format);
728 smb_xvasprintf(&kstr, format, ap);
731 centry = wcache_fetch_raw(kstr);
732 if (centry == NULL) {
737 if (centry_expired(domain, kstr, centry)) {
739 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
740 kstr, domain->name ));
747 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
748 kstr, domain->name ));
754 static void wcache_delete(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
755 static void wcache_delete(const char *format, ...)
761 va_start(ap, format);
762 smb_xvasprintf(&kstr, format, ap);
765 key = string_tdb_data(kstr);
767 tdb_delete(wcache->tdb, key);
772 make sure we have at least len bytes available in a centry
774 static void centry_expand(struct cache_entry *centry, uint32_t len)
776 if (centry->len - centry->ofs >= len)
779 centry->data = SMB_REALLOC_ARRAY(centry->data, unsigned char,
782 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
783 smb_panic_fn("out of memory in centry_expand");
788 push a uint64_t into a centry
790 static void centry_put_uint64_t(struct cache_entry *centry, uint64_t v)
792 centry_expand(centry, 8);
793 SBVAL(centry->data, centry->ofs, v);
798 push a uint32_t into a centry
800 static void centry_put_uint32(struct cache_entry *centry, uint32_t v)
802 centry_expand(centry, 4);
803 SIVAL(centry->data, centry->ofs, v);
808 push a uint16_t into a centry
810 static void centry_put_uint16(struct cache_entry *centry, uint16_t v)
812 centry_expand(centry, 2);
813 SSVAL(centry->data, centry->ofs, v);
818 push a uint8_t into a centry
820 static void centry_put_uint8(struct cache_entry *centry, uint8_t v)
822 centry_expand(centry, 1);
823 SCVAL(centry->data, centry->ofs, v);
828 push a string into a centry
830 static void centry_put_string(struct cache_entry *centry, const char *s)
835 /* null strings are marked as len 0xFFFF */
836 centry_put_uint8(centry, 0xFF);
841 /* can't handle more than 254 char strings. Truncating is probably best */
843 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len));
846 centry_put_uint8(centry, len);
847 centry_expand(centry, len);
848 memcpy(centry->data + centry->ofs, s, len);
853 push a 16 byte hash into a centry - treat as 16 byte string.
855 static void centry_put_hash16(struct cache_entry *centry, const uint8_t val[16])
857 centry_put_uint8(centry, 16);
858 centry_expand(centry, 16);
859 memcpy(centry->data + centry->ofs, val, 16);
863 static void centry_put_sid(struct cache_entry *centry, const struct dom_sid *sid)
866 centry_put_string(centry, sid_to_fstring(sid_string, sid));
871 put NTSTATUS into a centry
873 static void centry_put_ntstatus(struct cache_entry *centry, NTSTATUS status)
875 uint32_t status_value = NT_STATUS_V(status);
876 centry_put_uint32(centry, status_value);
881 push a NTTIME into a centry
883 static void centry_put_nttime(struct cache_entry *centry, NTTIME nt)
885 centry_expand(centry, 8);
886 SIVAL(centry->data, centry->ofs, nt & 0xFFFFFFFF);
888 SIVAL(centry->data, centry->ofs, nt >> 32);
893 push a time_t into a centry - use a 64 bit size.
894 NTTIME here is being used as a convenient 64-bit size.
896 static void centry_put_time(struct cache_entry *centry, time_t t)
898 NTTIME nt = (NTTIME)t;
899 centry_put_nttime(centry, nt);
903 start a centry for output. When finished, call centry_end()
905 static struct cache_entry *centry_start(struct winbindd_domain *domain,
908 struct cache_entry *centry;
913 centry = SMB_XMALLOC_P(struct cache_entry);
915 centry->len = 8192; /* reasonable default */
916 centry->data = SMB_XMALLOC_ARRAY(uint8_t, centry->len);
918 centry->sequence_number = domain->sequence_number;
919 centry->timeout = lp_winbind_cache_time() + time(NULL);
920 centry_put_ntstatus(centry, status);
921 centry_put_uint32(centry, centry->sequence_number);
922 centry_put_uint64_t(centry, centry->timeout);
927 finish a centry and write it to the tdb
929 static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
930 static void centry_end(struct cache_entry *centry, const char *format, ...)
936 if (!winbindd_use_cache()) {
940 va_start(ap, format);
941 smb_xvasprintf(&kstr, format, ap);
944 key = string_tdb_data(kstr);
945 data.dptr = centry->data;
946 data.dsize = centry->ofs;
948 tdb_store(wcache->tdb, key, data, TDB_REPLACE);
952 static void wcache_save_name_to_sid(struct winbindd_domain *domain,
953 NTSTATUS status, const char *domain_name,
954 const char *name, const struct dom_sid *sid,
955 enum lsa_SidType type)
957 struct cache_entry *centry;
960 centry = centry_start(domain, status);
964 if ((domain_name == NULL) || (domain_name[0] == '\0')) {
965 struct winbindd_domain *mydomain =
966 find_domain_from_sid_noinit(sid);
967 if (mydomain != NULL) {
968 domain_name = mydomain->name;
972 centry_put_uint32(centry, type);
973 centry_put_sid(centry, sid);
974 fstrcpy(uname, name);
975 (void)strupper_m(uname);
976 centry_end(centry, "NS/%s/%s", domain_name, uname);
977 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name,
978 uname, sid_string_dbg(sid), nt_errstr(status)));
982 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
983 const struct dom_sid *sid, const char *domain_name, const char *name, enum lsa_SidType type)
985 struct cache_entry *centry;
988 centry = centry_start(domain, status);
992 if ((domain_name == NULL) || (domain_name[0] == '\0')) {
993 struct winbindd_domain *mydomain =
994 find_domain_from_sid_noinit(sid);
995 if (mydomain != NULL) {
996 domain_name = mydomain->name;
1000 if (NT_STATUS_IS_OK(status)) {
1001 centry_put_uint32(centry, type);
1002 centry_put_string(centry, domain_name);
1003 centry_put_string(centry, name);
1006 centry_end(centry, "SN/%s", sid_to_fstring(sid_string, sid));
1007 DEBUG(10,("wcache_save_sid_to_name: %s -> %s\\%s (%s)\n", sid_string,
1008 domain_name, name, nt_errstr(status)));
1009 centry_free(centry);
1012 static void wcache_save_lockout_policy(struct winbindd_domain *domain,
1014 struct samr_DomInfo12 *lockout_policy)
1016 struct cache_entry *centry;
1018 centry = centry_start(domain, status);
1022 centry_put_nttime(centry, lockout_policy->lockout_duration);
1023 centry_put_nttime(centry, lockout_policy->lockout_window);
1024 centry_put_uint16(centry, lockout_policy->lockout_threshold);
1026 centry_end(centry, "LOC_POL/%s", domain->name);
1028 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
1030 centry_free(centry);
1035 static void wcache_save_password_policy(struct winbindd_domain *domain,
1037 struct samr_DomInfo1 *policy)
1039 struct cache_entry *centry;
1041 centry = centry_start(domain, status);
1045 centry_put_uint16(centry, policy->min_password_length);
1046 centry_put_uint16(centry, policy->password_history_length);
1047 centry_put_uint32(centry, policy->password_properties);
1048 centry_put_nttime(centry, policy->max_password_age);
1049 centry_put_nttime(centry, policy->min_password_age);
1051 centry_end(centry, "PWD_POL/%s", domain->name);
1053 DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
1055 centry_free(centry);
1058 /***************************************************************************
1059 ***************************************************************************/
1061 static void wcache_save_username_alias(struct winbindd_domain *domain,
1063 const char *name, const char *alias)
1065 struct cache_entry *centry;
1068 if ( (centry = centry_start(domain, status)) == NULL )
1071 centry_put_string( centry, alias );
1073 fstrcpy(uname, name);
1074 (void)strupper_m(uname);
1075 centry_end(centry, "NSS/NA/%s", uname);
1077 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name, alias ));
1079 centry_free(centry);
1082 static void wcache_save_alias_username(struct winbindd_domain *domain,
1084 const char *alias, const char *name)
1086 struct cache_entry *centry;
1089 if ( (centry = centry_start(domain, status)) == NULL )
1092 centry_put_string( centry, name );
1094 fstrcpy(uname, alias);
1095 (void)strupper_m(uname);
1096 centry_end(centry, "NSS/AN/%s", uname);
1098 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias, name ));
1100 centry_free(centry);
1103 /***************************************************************************
1104 ***************************************************************************/
1106 NTSTATUS resolve_username_to_alias( TALLOC_CTX *mem_ctx,
1107 struct winbindd_domain *domain,
1108 const char *name, char **alias )
1110 struct winbind_cache *cache = get_cache(domain);
1111 struct cache_entry *centry = NULL;
1115 if ( domain->internal )
1116 return NT_STATUS_NOT_SUPPORTED;
1121 upper_name = talloc_strdup_upper(mem_ctx, name);
1122 if (upper_name == NULL) {
1123 return NT_STATUS_NO_MEMORY;
1126 centry = wcache_fetch(cache, domain, "NSS/NA/%s", upper_name);
1128 talloc_free(upper_name);
1133 status = centry->status;
1135 if (!NT_STATUS_IS_OK(status)) {
1136 centry_free(centry);
1140 *alias = centry_string( centry, mem_ctx );
1142 centry_free(centry);
1144 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1145 name, *alias ? *alias : "(none)"));
1147 return (*alias) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1151 /* If its not in cache and we are offline, then fail */
1153 if ( get_global_winbindd_state_offline() || !domain->online ) {
1154 DEBUG(8,("resolve_username_to_alias: rejecting query "
1155 "in offline mode\n"));
1156 return NT_STATUS_NOT_FOUND;
1159 status = nss_map_to_alias( mem_ctx, domain->name, name, alias );
1161 if ( NT_STATUS_IS_OK( status ) ) {
1162 wcache_save_username_alias(domain, status, name, *alias);
1165 if ( NT_STATUS_EQUAL( status, NT_STATUS_NONE_MAPPED ) ) {
1166 wcache_save_username_alias(domain, status, name, "(NULL)");
1169 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1170 nt_errstr(status)));
1172 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1173 set_domain_offline( domain );
1179 /***************************************************************************
1180 ***************************************************************************/
1182 NTSTATUS resolve_alias_to_username( TALLOC_CTX *mem_ctx,
1183 struct winbindd_domain *domain,
1184 const char *alias, char **name )
1186 struct winbind_cache *cache = get_cache(domain);
1187 struct cache_entry *centry = NULL;
1191 if ( domain->internal )
1192 return NT_STATUS_NOT_SUPPORTED;
1197 upper_name = talloc_strdup(mem_ctx, alias);
1198 if (upper_name == NULL) {
1199 return NT_STATUS_NO_MEMORY;
1201 if (!strupper_m(upper_name)) {
1202 talloc_free(upper_name);
1203 return NT_STATUS_INVALID_PARAMETER;
1206 centry = wcache_fetch(cache, domain, "NSS/AN/%s", upper_name);
1208 talloc_free(upper_name);
1213 status = centry->status;
1215 if (!NT_STATUS_IS_OK(status)) {
1216 centry_free(centry);
1220 *name = centry_string( centry, mem_ctx );
1222 centry_free(centry);
1224 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1225 alias, *name ? *name : "(none)"));
1227 return (*name) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1231 /* If its not in cache and we are offline, then fail */
1233 if ( get_global_winbindd_state_offline() || !domain->online ) {
1234 DEBUG(8,("resolve_alias_to_username: rejecting query "
1235 "in offline mode\n"));
1236 return NT_STATUS_NOT_FOUND;
1239 /* an alias cannot contain a domain prefix or '@' */
1241 if (strchr(alias, '\\') || strchr(alias, '@')) {
1242 DEBUG(10,("resolve_alias_to_username: skipping fully "
1243 "qualified name %s\n", alias));
1244 return NT_STATUS_OBJECT_NAME_INVALID;
1247 status = nss_map_from_alias( mem_ctx, domain->name, alias, name );
1249 if ( NT_STATUS_IS_OK( status ) ) {
1250 wcache_save_alias_username( domain, status, alias, *name );
1253 if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1254 wcache_save_alias_username(domain, status, alias, "(NULL)");
1257 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1258 nt_errstr(status)));
1260 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1261 set_domain_offline( domain );
1267 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const struct dom_sid *sid)
1269 struct winbind_cache *cache = get_cache(domain);
1271 fstring key_str, tmp;
1275 return NT_STATUS_INTERNAL_DB_ERROR;
1278 if (is_null_sid(sid)) {
1279 return NT_STATUS_INVALID_SID;
1282 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1283 return NT_STATUS_INVALID_SID;
1286 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
1288 data = tdb_fetch(cache->tdb, string_tdb_data(key_str));
1290 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1293 SAFE_FREE(data.dptr);
1294 return NT_STATUS_OK;
1297 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1298 as new salted ones. */
1300 NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
1301 TALLOC_CTX *mem_ctx,
1302 const struct dom_sid *sid,
1303 const uint8_t **cached_nt_pass,
1304 const uint8_t **cached_salt)
1306 struct winbind_cache *cache = get_cache(domain);
1307 struct cache_entry *centry = NULL;
1313 return NT_STATUS_INTERNAL_DB_ERROR;
1316 if (is_null_sid(sid)) {
1317 return NT_STATUS_INVALID_SID;
1320 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1321 return NT_STATUS_INVALID_SID;
1324 /* Try and get a salted cred first. If we can't
1325 fall back to an unsalted cred. */
1327 centry = wcache_fetch(cache, domain, "CRED/%s",
1328 sid_to_fstring(tmp, sid));
1330 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1331 sid_string_dbg(sid)));
1332 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1336 * We don't use the time element at this moment,
1337 * but we have to consume it, so that we don't
1338 * neet to change the disk format of the cache.
1340 (void)centry_time(centry);
1342 /* In the salted case this isn't actually the nt_hash itself,
1343 but the MD5 of the salt + nt_hash. Let the caller
1344 sort this out. It can tell as we only return the cached_salt
1345 if we are returning a salted cred. */
1347 *cached_nt_pass = (const uint8_t *)centry_hash16(centry, mem_ctx);
1348 if (*cached_nt_pass == NULL) {
1351 sid_to_fstring(sidstr, sid);
1353 /* Bad (old) cred cache. Delete and pretend we
1355 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1357 wcache_delete("CRED/%s", sidstr);
1358 centry_free(centry);
1359 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1362 /* We only have 17 bytes more data in the salted cred case. */
1363 if (centry->len - centry->ofs == 17) {
1364 *cached_salt = (const uint8_t *)centry_hash16(centry, mem_ctx);
1366 *cached_salt = NULL;
1369 dump_data_pw("cached_nt_pass", *cached_nt_pass, NT_HASH_LEN);
1371 dump_data_pw("cached_salt", *cached_salt, NT_HASH_LEN);
1374 status = centry->status;
1376 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1377 sid_string_dbg(sid), nt_errstr(status) ));
1379 centry_free(centry);
1383 /* Store creds for a SID - only writes out new salted ones. */
1385 NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
1386 const struct dom_sid *sid,
1387 const uint8_t nt_pass[NT_HASH_LEN])
1389 struct cache_entry *centry;
1392 uint8_t cred_salt[NT_HASH_LEN];
1393 uint8_t salted_hash[NT_HASH_LEN];
1395 if (is_null_sid(sid)) {
1396 return NT_STATUS_INVALID_SID;
1399 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1400 return NT_STATUS_INVALID_SID;
1403 centry = centry_start(domain, NT_STATUS_OK);
1405 return NT_STATUS_INTERNAL_DB_ERROR;
1408 dump_data_pw("nt_pass", nt_pass, NT_HASH_LEN);
1410 centry_put_time(centry, time(NULL));
1412 /* Create a salt and then salt the hash. */
1413 generate_random_buffer(cred_salt, NT_HASH_LEN);
1414 E_md5hash(cred_salt, nt_pass, salted_hash);
1416 centry_put_hash16(centry, salted_hash);
1417 centry_put_hash16(centry, cred_salt);
1418 centry_end(centry, "CRED/%s", sid_to_fstring(sid_string, sid));
1420 DEBUG(10,("wcache_save_creds: %s\n", sid_string));
1422 centry_free(centry);
1424 return NT_STATUS_OK;
1428 /* Query display info. This is the basic user list fn */
1429 NTSTATUS wb_cache_query_user_list(struct winbindd_domain *domain,
1430 TALLOC_CTX *mem_ctx,
1433 struct winbind_cache *cache = get_cache(domain);
1434 struct cache_entry *centry = NULL;
1435 uint32_t num_rids = 0;
1436 uint32_t *rids = NULL;
1438 unsigned int i, retry;
1439 bool old_status = domain->online;
1446 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1451 num_rids = centry_uint32(centry);
1453 if (num_rids == 0) {
1457 rids = talloc_array(mem_ctx, uint32_t, num_rids);
1459 centry_free(centry);
1460 return NT_STATUS_NO_MEMORY;
1463 for (i=0; i<num_rids; i++) {
1464 rids[i] = centry_uint32(centry);
1468 status = centry->status;
1470 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1471 domain->name, nt_errstr(status) ));
1473 centry_free(centry);
1478 /* Return status value returned by seq number check */
1480 if (!NT_STATUS_IS_OK(domain->last_status))
1481 return domain->last_status;
1483 /* Put the query_user_list() in a retry loop. There appears to be
1484 * some bug either with Windows 2000 or Samba's handling of large
1485 * rpc replies. This manifests itself as sudden disconnection
1486 * at a random point in the enumeration of a large (60k) user list.
1487 * The retry loop simply tries the operation again. )-: It's not
1488 * pretty but an acceptable workaround until we work out what the
1489 * real problem is. */
1494 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1498 status = domain->backend->query_user_list(domain, mem_ctx,
1500 num_rids = talloc_array_length(rids);
1502 if (!NT_STATUS_IS_OK(status)) {
1503 DEBUG(3, ("query_user_list: returned 0x%08x, "
1504 "retrying\n", NT_STATUS_V(status)));
1506 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1507 DEBUG(3, ("query_user_list: flushing "
1508 "connection cache\n"));
1509 invalidate_cm_connection(domain);
1511 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1512 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1513 if (!domain->internal && old_status) {
1514 set_domain_offline(domain);
1516 /* store partial response. */
1519 * humm, what about the status used for cache?
1520 * Should it be NT_STATUS_OK?
1525 * domain is offline now, and there is no user entries,
1526 * try to fetch from cache again.
1528 if (cache->tdb && !domain->online && !domain->internal && old_status) {
1529 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1530 /* partial response... */
1534 goto do_fetch_cache;
1541 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
1545 refresh_sequence_number(domain);
1546 if (!NT_STATUS_IS_OK(status)) {
1549 centry = centry_start(domain, status);
1552 centry_put_uint32(centry, num_rids);
1553 for (i=0; i<num_rids; i++) {
1554 centry_put_uint32(centry, rids[i]);
1556 centry_end(centry, "UL/%s", domain->name);
1557 centry_free(centry);
1565 /* list all domain groups */
1566 NTSTATUS wb_cache_enum_dom_groups(struct winbindd_domain *domain,
1567 TALLOC_CTX *mem_ctx,
1568 uint32_t *num_entries,
1569 struct wb_acct_info **info)
1571 struct winbind_cache *cache = get_cache(domain);
1572 struct cache_entry *centry = NULL;
1577 old_status = domain->online;
1581 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1586 *num_entries = centry_uint32(centry);
1588 if (*num_entries == 0)
1591 (*info) = talloc_array(mem_ctx, struct wb_acct_info, *num_entries);
1593 smb_panic_fn("enum_dom_groups out of memory");
1595 for (i=0; i<(*num_entries); i++) {
1596 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1597 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1598 (*info)[i].rid = centry_uint32(centry);
1602 status = centry->status;
1604 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1605 domain->name, nt_errstr(status) ));
1607 centry_free(centry);
1614 /* Return status value returned by seq number check */
1616 if (!NT_STATUS_IS_OK(domain->last_status))
1617 return domain->last_status;
1619 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1622 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1624 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1625 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1626 if (!domain->internal && old_status) {
1627 set_domain_offline(domain);
1631 !domain->internal &&
1633 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1635 goto do_fetch_cache;
1640 refresh_sequence_number(domain);
1641 if (!NT_STATUS_IS_OK(status)) {
1644 centry = centry_start(domain, status);
1647 centry_put_uint32(centry, *num_entries);
1648 for (i=0; i<(*num_entries); i++) {
1649 centry_put_string(centry, (*info)[i].acct_name);
1650 centry_put_string(centry, (*info)[i].acct_desc);
1651 centry_put_uint32(centry, (*info)[i].rid);
1653 centry_end(centry, "GL/%s/domain", domain->name);
1654 centry_free(centry);
1660 /* list all domain groups */
1661 NTSTATUS wb_cache_enum_local_groups(struct winbindd_domain *domain,
1662 TALLOC_CTX *mem_ctx,
1663 uint32_t *num_entries,
1664 struct wb_acct_info **info)
1666 struct winbind_cache *cache = get_cache(domain);
1667 struct cache_entry *centry = NULL;
1672 old_status = domain->online;
1676 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1681 *num_entries = centry_uint32(centry);
1683 if (*num_entries == 0)
1686 (*info) = talloc_array(mem_ctx, struct wb_acct_info, *num_entries);
1688 smb_panic_fn("enum_dom_groups out of memory");
1690 for (i=0; i<(*num_entries); i++) {
1691 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1692 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1693 (*info)[i].rid = centry_uint32(centry);
1698 /* If we are returning cached data and the domain controller
1699 is down then we don't know whether the data is up to date
1700 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1703 if (wcache_server_down(domain)) {
1704 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1705 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1707 status = centry->status;
1709 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1710 domain->name, nt_errstr(status) ));
1712 centry_free(centry);
1719 /* Return status value returned by seq number check */
1721 if (!NT_STATUS_IS_OK(domain->last_status))
1722 return domain->last_status;
1724 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1727 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1729 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1730 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1731 if (!domain->internal && old_status) {
1732 set_domain_offline(domain);
1735 !domain->internal &&
1738 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1740 goto do_fetch_cache;
1745 refresh_sequence_number(domain);
1746 if (!NT_STATUS_IS_OK(status)) {
1749 centry = centry_start(domain, status);
1752 centry_put_uint32(centry, *num_entries);
1753 for (i=0; i<(*num_entries); i++) {
1754 centry_put_string(centry, (*info)[i].acct_name);
1755 centry_put_string(centry, (*info)[i].acct_desc);
1756 centry_put_uint32(centry, (*info)[i].rid);
1758 centry_end(centry, "GL/%s/local", domain->name);
1759 centry_free(centry);
1765 NTSTATUS wcache_name_to_sid(struct winbindd_domain *domain,
1766 const char *domain_name,
1768 struct dom_sid *sid,
1769 enum lsa_SidType *type)
1771 struct winbind_cache *cache = get_cache(domain);
1772 struct cache_entry *centry;
1776 if (cache->tdb == NULL) {
1777 return NT_STATUS_NOT_FOUND;
1780 uname = talloc_strdup_upper(talloc_tos(), name);
1781 if (uname == NULL) {
1782 return NT_STATUS_NO_MEMORY;
1785 if ((domain_name == NULL) || (domain_name[0] == '\0')) {
1786 domain_name = domain->name;
1789 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1791 if (centry == NULL) {
1792 return NT_STATUS_NOT_FOUND;
1795 status = centry->status;
1796 if (NT_STATUS_IS_OK(status)) {
1797 *type = (enum lsa_SidType)centry_uint32(centry);
1798 centry_sid(centry, sid);
1801 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1802 "%s\n", domain->name, nt_errstr(status) ));
1804 centry_free(centry);
1808 /* convert a single name to a sid in a domain */
1809 NTSTATUS wb_cache_name_to_sid(struct winbindd_domain *domain,
1810 TALLOC_CTX *mem_ctx,
1811 const char *domain_name,
1814 struct dom_sid *sid,
1815 enum lsa_SidType *type)
1820 old_status = domain->online;
1822 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1823 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1829 /* If the seq number check indicated that there is a problem
1830 * with this DC, then return that status... except for
1831 * access_denied. This is special because the dc may be in
1832 * "restrict anonymous = 1" mode, in which case it will deny
1833 * most unauthenticated operations, but *will* allow the LSA
1834 * name-to-sid that we try as a fallback. */
1836 if (!(NT_STATUS_IS_OK(domain->last_status)
1837 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1838 return domain->last_status;
1840 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1843 status = domain->backend->name_to_sid(domain, mem_ctx, domain_name,
1844 name, flags, sid, type);
1846 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1847 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1848 if (!domain->internal && old_status) {
1849 set_domain_offline(domain);
1851 if (!domain->internal &&
1854 NTSTATUS cache_status;
1855 cache_status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1856 return cache_status;
1860 refresh_sequence_number(domain);
1862 if (domain->online &&
1863 (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
1864 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1866 /* Only save the reverse mapping if this was not a UPN */
1867 if (!strchr(name, '@')) {
1868 if (!strupper_m(discard_const_p(char, domain_name))) {
1869 return NT_STATUS_INVALID_PARAMETER;
1871 (void)strlower_m(discard_const_p(char, name));
1872 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1879 static NTSTATUS wcache_sid_to_name(struct winbindd_domain *domain,
1880 const struct dom_sid *sid,
1881 TALLOC_CTX *mem_ctx,
1884 enum lsa_SidType *type)
1886 struct winbind_cache *cache = get_cache(domain);
1887 struct cache_entry *centry;
1891 if (cache->tdb == NULL) {
1892 return NT_STATUS_NOT_FOUND;
1895 sid_string = sid_string_tos(sid);
1896 if (sid_string == NULL) {
1897 return NT_STATUS_NO_MEMORY;
1900 centry = wcache_fetch(cache, domain, "SN/%s", sid_string);
1901 TALLOC_FREE(sid_string);
1902 if (centry == NULL) {
1903 return NT_STATUS_NOT_FOUND;
1906 if (NT_STATUS_IS_OK(centry->status)) {
1907 *type = (enum lsa_SidType)centry_uint32(centry);
1908 *domain_name = centry_string(centry, mem_ctx);
1909 *name = centry_string(centry, mem_ctx);
1912 status = centry->status;
1913 centry_free(centry);
1915 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1916 "%s\n", domain->name, nt_errstr(status) ));
1921 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1923 NTSTATUS wb_cache_sid_to_name(struct winbindd_domain *domain,
1924 TALLOC_CTX *mem_ctx,
1925 const struct dom_sid *sid,
1928 enum lsa_SidType *type)
1933 old_status = domain->online;
1934 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
1936 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1941 *domain_name = NULL;
1943 /* If the seq number check indicated that there is a problem
1944 * with this DC, then return that status... except for
1945 * access_denied. This is special because the dc may be in
1946 * "restrict anonymous = 1" mode, in which case it will deny
1947 * most unauthenticated operations, but *will* allow the LSA
1948 * sid-to-name that we try as a fallback. */
1950 if (!(NT_STATUS_IS_OK(domain->last_status)
1951 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1952 return domain->last_status;
1954 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1957 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1959 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1960 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1961 if (!domain->internal && old_status) {
1962 set_domain_offline(domain);
1964 if (!domain->internal &&
1967 NTSTATUS cache_status;
1968 cache_status = wcache_sid_to_name(domain, sid, mem_ctx,
1969 domain_name, name, type);
1970 return cache_status;
1974 refresh_sequence_number(domain);
1975 if (!NT_STATUS_IS_OK(status)) {
1978 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1980 /* We can't save the name to sid mapping here, as with sid history a
1981 * later name2sid would give the wrong sid. */
1986 NTSTATUS wb_cache_rids_to_names(struct winbindd_domain *domain,
1987 TALLOC_CTX *mem_ctx,
1988 const struct dom_sid *domain_sid,
1993 enum lsa_SidType **types)
1995 struct winbind_cache *cache = get_cache(domain);
1997 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
2002 old_status = domain->online;
2003 *domain_name = NULL;
2011 if (num_rids == 0) {
2012 return NT_STATUS_OK;
2015 *names = talloc_array(mem_ctx, char *, num_rids);
2016 *types = talloc_array(mem_ctx, enum lsa_SidType, num_rids);
2018 if ((*names == NULL) || (*types == NULL)) {
2019 result = NT_STATUS_NO_MEMORY;
2023 have_mapped = have_unmapped = false;
2025 for (i=0; i<num_rids; i++) {
2027 struct cache_entry *centry;
2030 if (!sid_compose(&sid, domain_sid, rids[i])) {
2031 result = NT_STATUS_INTERNAL_ERROR;
2035 centry = wcache_fetch(cache, domain, "SN/%s",
2036 sid_to_fstring(tmp, &sid));
2041 (*types)[i] = SID_NAME_UNKNOWN;
2042 (*names)[i] = talloc_strdup(*names, "");
2044 if (NT_STATUS_IS_OK(centry->status)) {
2047 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
2049 dom = centry_string(centry, mem_ctx);
2050 if (*domain_name == NULL) {
2056 (*names)[i] = centry_string(centry, *names);
2058 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)
2059 || NT_STATUS_EQUAL(centry->status, STATUS_SOME_UNMAPPED)) {
2060 have_unmapped = true;
2063 /* something's definitely wrong */
2064 result = centry->status;
2065 centry_free(centry);
2069 centry_free(centry);
2073 return NT_STATUS_NONE_MAPPED;
2075 if (!have_unmapped) {
2076 return NT_STATUS_OK;
2078 return STATUS_SOME_UNMAPPED;
2082 TALLOC_FREE(*names);
2083 TALLOC_FREE(*types);
2085 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
2086 rids, num_rids, domain_name,
2089 if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
2090 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2091 if (!domain->internal && old_status) {
2092 set_domain_offline(domain);
2095 !domain->internal &&
2098 have_mapped = have_unmapped = false;
2100 *names = talloc_array(mem_ctx, char *, num_rids);
2101 if (*names == NULL) {
2102 result = NT_STATUS_NO_MEMORY;
2106 *types = talloc_array(mem_ctx, enum lsa_SidType,
2108 if (*types == NULL) {
2109 result = NT_STATUS_NO_MEMORY;
2113 for (i=0; i<num_rids; i++) {
2115 struct cache_entry *centry;
2118 if (!sid_compose(&sid, domain_sid, rids[i])) {
2119 result = NT_STATUS_INTERNAL_ERROR;
2123 centry = wcache_fetch(cache, domain, "SN/%s",
2124 sid_to_fstring(tmp, &sid));
2126 (*types)[i] = SID_NAME_UNKNOWN;
2127 (*names)[i] = talloc_strdup(*names, "");
2131 (*types)[i] = SID_NAME_UNKNOWN;
2132 (*names)[i] = talloc_strdup(*names, "");
2134 if (NT_STATUS_IS_OK(centry->status)) {
2137 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
2139 dom = centry_string(centry, mem_ctx);
2140 if (*domain_name == NULL) {
2146 (*names)[i] = centry_string(centry, *names);
2148 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
2149 have_unmapped = true;
2152 /* something's definitely wrong */
2153 result = centry->status;
2154 centry_free(centry);
2158 centry_free(centry);
2162 return NT_STATUS_NONE_MAPPED;
2164 if (!have_unmapped) {
2165 return NT_STATUS_OK;
2167 return STATUS_SOME_UNMAPPED;
2171 None of the queried rids has been found so save all negative entries
2173 if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
2174 for (i = 0; i < num_rids; i++) {
2176 const char *name = "";
2177 const enum lsa_SidType type = SID_NAME_UNKNOWN;
2178 NTSTATUS status = NT_STATUS_NONE_MAPPED;
2180 if (!sid_compose(&sid, domain_sid, rids[i])) {
2181 return NT_STATUS_INTERNAL_ERROR;
2184 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2192 Some or all of the queried rids have been found.
2194 if (!NT_STATUS_IS_OK(result) &&
2195 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
2199 refresh_sequence_number(domain);
2201 for (i=0; i<num_rids; i++) {
2205 if (!sid_compose(&sid, domain_sid, rids[i])) {
2206 result = NT_STATUS_INTERNAL_ERROR;
2210 status = (*types)[i] == SID_NAME_UNKNOWN ?
2211 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
2213 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2214 (*names)[i], (*types)[i]);
2220 TALLOC_FREE(*names);
2221 TALLOC_FREE(*types);
2225 NTSTATUS wcache_query_user(struct winbindd_domain *domain,
2226 TALLOC_CTX *mem_ctx,
2227 const struct dom_sid *user_sid,
2228 struct wbint_userinfo *info)
2230 struct winbind_cache *cache = get_cache(domain);
2231 struct cache_entry *centry = NULL;
2235 if (cache->tdb == NULL) {
2236 return NT_STATUS_NOT_FOUND;
2239 sid_string = sid_string_tos(user_sid);
2240 if (sid_string == NULL) {
2241 return NT_STATUS_NO_MEMORY;
2244 centry = wcache_fetch(cache, domain, "U/%s", sid_string);
2245 TALLOC_FREE(sid_string);
2246 if (centry == NULL) {
2247 return NT_STATUS_NOT_FOUND;
2251 * If we have an access denied cache entry and a cached info3
2252 * in the samlogon cache then do a query. This will force the
2253 * rpc back end to return the info3 data.
2256 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED) &&
2257 netsamlogon_cache_have(user_sid)) {
2258 DEBUG(10, ("query_user: cached access denied and have cached "
2260 domain->last_status = NT_STATUS_OK;
2261 centry_free(centry);
2262 return NT_STATUS_NOT_FOUND;
2265 /* if status is not ok then this is a negative hit
2266 and the rest of the data doesn't matter */
2267 status = centry->status;
2268 if (NT_STATUS_IS_OK(status)) {
2269 info->domain_name = centry_string(centry, mem_ctx);
2270 info->acct_name = centry_string(centry, mem_ctx);
2271 info->full_name = centry_string(centry, mem_ctx);
2272 info->homedir = centry_string(centry, mem_ctx);
2273 info->shell = centry_string(centry, mem_ctx);
2274 info->uid = centry_uint32(centry);
2275 info->primary_gid = centry_uint32(centry);
2276 info->primary_group_name = centry_string(centry, mem_ctx);
2277 centry_sid(centry, &info->user_sid);
2278 centry_sid(centry, &info->group_sid);
2281 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2282 "%s\n", domain->name, nt_errstr(status) ));
2284 centry_free(centry);
2290 * @brief Query a fullname from the username cache (for further gecos processing)
2292 * @param domain A pointer to the winbindd_domain struct.
2293 * @param mem_ctx The talloc context.
2294 * @param user_sid The user sid.
2295 * @param full_name A pointer to the full_name string.
2297 * @return NTSTATUS code
2299 NTSTATUS wcache_query_user_fullname(struct winbindd_domain *domain,
2300 TALLOC_CTX *mem_ctx,
2301 const struct dom_sid *user_sid,
2302 const char **full_name)
2305 struct wbint_userinfo info;
2307 status = wcache_query_user(domain, mem_ctx, user_sid, &info);
2308 if (!NT_STATUS_IS_OK(status)) {
2312 if (info.full_name != NULL) {
2313 *full_name = talloc_strdup(mem_ctx, info.full_name);
2314 if (*full_name == NULL) {
2315 return NT_STATUS_NO_MEMORY;
2319 return NT_STATUS_OK;
2322 NTSTATUS wcache_lookup_usergroups(struct winbindd_domain *domain,
2323 TALLOC_CTX *mem_ctx,
2324 const struct dom_sid *user_sid,
2325 uint32_t *pnum_sids,
2326 struct dom_sid **psids)
2328 struct winbind_cache *cache = get_cache(domain);
2329 struct cache_entry *centry = NULL;
2331 uint32_t i, num_sids;
2332 struct dom_sid *sids;
2335 if (cache->tdb == NULL) {
2336 return NT_STATUS_NOT_FOUND;
2339 centry = wcache_fetch(cache, domain, "UG/%s",
2340 sid_to_fstring(sid_string, user_sid));
2341 if (centry == NULL) {
2342 return NT_STATUS_NOT_FOUND;
2345 /* If we have an access denied cache entry and a cached info3 in the
2346 samlogon cache then do a query. This will force the rpc back end
2347 to return the info3 data. */
2349 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)
2350 && netsamlogon_cache_have(user_sid)) {
2351 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2353 domain->last_status = NT_STATUS_OK;
2354 centry_free(centry);
2355 return NT_STATUS_NOT_FOUND;
2358 num_sids = centry_uint32(centry);
2359 sids = talloc_array(mem_ctx, struct dom_sid, num_sids);
2361 centry_free(centry);
2362 return NT_STATUS_NO_MEMORY;
2365 for (i=0; i<num_sids; i++) {
2366 centry_sid(centry, &sids[i]);
2369 status = centry->status;
2371 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2372 "status: %s\n", domain->name, nt_errstr(status)));
2374 centry_free(centry);
2376 *pnum_sids = num_sids;
2381 /* Lookup groups a user is a member of. */
2382 NTSTATUS wb_cache_lookup_usergroups(struct winbindd_domain *domain,
2383 TALLOC_CTX *mem_ctx,
2384 const struct dom_sid *user_sid,
2385 uint32_t *num_groups,
2386 struct dom_sid **user_gids)
2388 struct cache_entry *centry = NULL;
2394 old_status = domain->online;
2395 status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2396 num_groups, user_gids);
2397 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2402 (*user_gids) = NULL;
2404 /* Return status value returned by seq number check */
2406 if (!NT_STATUS_IS_OK(domain->last_status))
2407 return domain->last_status;
2409 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2412 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
2414 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2415 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2416 if (!domain->internal && old_status) {
2417 set_domain_offline(domain);
2419 if (!domain->internal &&
2422 NTSTATUS cache_status;
2423 cache_status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2424 num_groups, user_gids);
2425 return cache_status;
2428 if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
2432 refresh_sequence_number(domain);
2433 if (!NT_STATUS_IS_OK(status)) {
2436 centry = centry_start(domain, status);
2440 centry_put_uint32(centry, *num_groups);
2441 for (i=0; i<(*num_groups); i++) {
2442 centry_put_sid(centry, &(*user_gids)[i]);
2445 centry_end(centry, "UG/%s", sid_to_fstring(sid_string, user_sid));
2446 centry_free(centry);
2452 static char *wcache_make_sidlist(TALLOC_CTX *mem_ctx, uint32_t num_sids,
2453 const struct dom_sid *sids)
2458 sidlist = talloc_strdup(mem_ctx, "");
2459 if (sidlist == NULL) {
2462 for (i=0; i<num_sids; i++) {
2464 sidlist = talloc_asprintf_append_buffer(
2465 sidlist, "/%s", sid_to_fstring(tmp, &sids[i]));
2466 if (sidlist == NULL) {
2473 NTSTATUS wcache_lookup_useraliases(struct winbindd_domain *domain,
2474 TALLOC_CTX *mem_ctx, uint32_t num_sids,
2475 const struct dom_sid *sids,
2476 uint32_t *pnum_aliases, uint32_t **paliases)
2478 struct winbind_cache *cache = get_cache(domain);
2479 struct cache_entry *centry = NULL;
2480 uint32_t i, num_aliases;
2485 if (cache->tdb == NULL) {
2486 return NT_STATUS_NOT_FOUND;
2489 if (num_sids == 0) {
2492 return NT_STATUS_OK;
2495 /* We need to cache indexed by the whole list of SIDs, the aliases
2496 * resulting might come from any of the SIDs. */
2498 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2499 if (sidlist == NULL) {
2500 return NT_STATUS_NO_MEMORY;
2503 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
2504 TALLOC_FREE(sidlist);
2505 if (centry == NULL) {
2506 return NT_STATUS_NOT_FOUND;
2509 num_aliases = centry_uint32(centry);
2510 aliases = talloc_array(mem_ctx, uint32_t, num_aliases);
2511 if (aliases == NULL) {
2512 centry_free(centry);
2513 return NT_STATUS_NO_MEMORY;
2516 for (i=0; i<num_aliases; i++) {
2517 aliases[i] = centry_uint32(centry);
2520 status = centry->status;
2522 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2523 "status %s\n", domain->name, nt_errstr(status)));
2525 centry_free(centry);
2527 *pnum_aliases = num_aliases;
2528 *paliases = aliases;
2533 NTSTATUS wb_cache_lookup_useraliases(struct winbindd_domain *domain,
2534 TALLOC_CTX *mem_ctx,
2536 const struct dom_sid *sids,
2537 uint32_t *num_aliases,
2538 uint32_t **alias_rids)
2540 struct cache_entry *centry = NULL;
2546 old_status = domain->online;
2547 status = wcache_lookup_useraliases(domain, mem_ctx, num_sids, sids,
2548 num_aliases, alias_rids);
2549 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2554 (*alias_rids) = NULL;
2556 if (!NT_STATUS_IS_OK(domain->last_status))
2557 return domain->last_status;
2559 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2560 "for domain %s\n", domain->name ));
2562 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2563 if (sidlist == NULL) {
2564 return NT_STATUS_NO_MEMORY;
2567 status = domain->backend->lookup_useraliases(domain, mem_ctx,
2569 num_aliases, alias_rids);
2571 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2572 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2573 if (!domain->internal && old_status) {
2574 set_domain_offline(domain);
2576 if (!domain->internal &&
2579 NTSTATUS cache_status;
2580 cache_status = wcache_lookup_useraliases(domain, mem_ctx, num_sids,
2581 sids, num_aliases, alias_rids);
2582 return cache_status;
2586 refresh_sequence_number(domain);
2587 if (!NT_STATUS_IS_OK(status)) {
2590 centry = centry_start(domain, status);
2593 centry_put_uint32(centry, *num_aliases);
2594 for (i=0; i<(*num_aliases); i++)
2595 centry_put_uint32(centry, (*alias_rids)[i]);
2596 centry_end(centry, "UA%s", sidlist);
2597 centry_free(centry);
2603 NTSTATUS wcache_lookup_groupmem(struct winbindd_domain *domain,
2604 TALLOC_CTX *mem_ctx,
2605 const struct dom_sid *group_sid,
2606 uint32_t *num_names,
2607 struct dom_sid **sid_mem, char ***names,
2608 uint32_t **name_types)
2610 struct winbind_cache *cache = get_cache(domain);
2611 struct cache_entry *centry = NULL;
2616 if (cache->tdb == NULL) {
2617 return NT_STATUS_NOT_FOUND;
2620 sid_string = sid_string_tos(group_sid);
2621 if (sid_string == NULL) {
2622 return NT_STATUS_NO_MEMORY;
2625 centry = wcache_fetch(cache, domain, "GM/%s", sid_string);
2626 TALLOC_FREE(sid_string);
2627 if (centry == NULL) {
2628 return NT_STATUS_NOT_FOUND;
2635 *num_names = centry_uint32(centry);
2636 if (*num_names == 0) {
2637 centry_free(centry);
2638 return NT_STATUS_OK;
2641 *sid_mem = talloc_array(mem_ctx, struct dom_sid, *num_names);
2642 *names = talloc_array(mem_ctx, char *, *num_names);
2643 *name_types = talloc_array(mem_ctx, uint32_t, *num_names);
2645 if ((*sid_mem == NULL) || (*names == NULL) || (*name_types == NULL)) {
2646 TALLOC_FREE(*sid_mem);
2647 TALLOC_FREE(*names);
2648 TALLOC_FREE(*name_types);
2649 centry_free(centry);
2650 return NT_STATUS_NO_MEMORY;
2653 for (i=0; i<(*num_names); i++) {
2654 centry_sid(centry, &(*sid_mem)[i]);
2655 (*names)[i] = centry_string(centry, mem_ctx);
2656 (*name_types)[i] = centry_uint32(centry);
2659 status = centry->status;
2661 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2662 "status: %s\n", domain->name, nt_errstr(status)));
2664 centry_free(centry);
2668 NTSTATUS wb_cache_lookup_groupmem(struct winbindd_domain *domain,
2669 TALLOC_CTX *mem_ctx,
2670 const struct dom_sid *group_sid,
2671 enum lsa_SidType type,
2672 uint32_t *num_names,
2673 struct dom_sid **sid_mem,
2675 uint32_t **name_types)
2677 struct cache_entry *centry = NULL;
2683 old_status = domain->online;
2684 status = wcache_lookup_groupmem(domain, mem_ctx, group_sid, num_names,
2685 sid_mem, names, name_types);
2686 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2693 (*name_types) = NULL;
2695 /* Return status value returned by seq number check */
2697 if (!NT_STATUS_IS_OK(domain->last_status))
2698 return domain->last_status;
2700 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2703 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid,
2705 sid_mem, names, name_types);
2707 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2708 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2709 if (!domain->internal && old_status) {
2710 set_domain_offline(domain);
2712 if (!domain->internal &&
2715 NTSTATUS cache_status;
2716 cache_status = wcache_lookup_groupmem(domain, mem_ctx, group_sid,
2717 num_names, sid_mem, names,
2719 return cache_status;
2723 refresh_sequence_number(domain);
2724 if (!NT_STATUS_IS_OK(status)) {
2727 centry = centry_start(domain, status);
2730 centry_put_uint32(centry, *num_names);
2731 for (i=0; i<(*num_names); i++) {
2732 centry_put_sid(centry, &(*sid_mem)[i]);
2733 centry_put_string(centry, (*names)[i]);
2734 centry_put_uint32(centry, (*name_types)[i]);
2736 centry_end(centry, "GM/%s", sid_to_fstring(sid_string, group_sid));
2737 centry_free(centry);
2743 /* find the sequence number for a domain */
2744 NTSTATUS wb_cache_sequence_number(struct winbindd_domain *domain,
2747 refresh_sequence_number(domain);
2749 *seq = domain->sequence_number;
2751 return NT_STATUS_OK;
2754 /* enumerate trusted domains
2755 * (we need to have the list of trustdoms in the cache when we go offline) -
2757 NTSTATUS wb_cache_trusted_domains(struct winbindd_domain *domain,
2758 TALLOC_CTX *mem_ctx,
2759 struct netr_DomainTrustList *trusts)
2762 struct winbind_cache *cache;
2763 struct winbindd_tdc_domain *dom_list = NULL;
2764 size_t num_domains = 0;
2765 bool retval = false;
2769 old_status = domain->online;
2771 trusts->array = NULL;
2773 cache = get_cache(domain);
2774 if (!cache || !cache->tdb) {
2778 if (domain->online) {
2782 retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2783 if (!retval || !num_domains || !dom_list) {
2784 TALLOC_FREE(dom_list);
2789 trusts->array = talloc_zero_array(mem_ctx, struct netr_DomainTrust, num_domains);
2790 if (!trusts->array) {
2791 TALLOC_FREE(dom_list);
2792 return NT_STATUS_NO_MEMORY;
2795 for (i = 0; i < num_domains; i++) {
2796 struct netr_DomainTrust *trust;
2797 struct dom_sid *sid;
2798 struct winbindd_domain *dom;
2800 dom = find_domain_from_name_noinit(dom_list[i].domain_name);
2801 if (dom && dom->internal) {
2805 trust = &trusts->array[trusts->count];
2806 trust->netbios_name = talloc_strdup(trusts->array, dom_list[i].domain_name);
2807 trust->dns_name = talloc_strdup(trusts->array, dom_list[i].dns_name);
2808 sid = talloc(trusts->array, struct dom_sid);
2809 if (!trust->netbios_name || !trust->dns_name ||
2811 TALLOC_FREE(dom_list);
2812 TALLOC_FREE(trusts->array);
2813 return NT_STATUS_NO_MEMORY;
2816 trust->trust_flags = dom_list[i].trust_flags;
2817 trust->trust_attributes = dom_list[i].trust_attribs;
2818 trust->trust_type = dom_list[i].trust_type;
2819 sid_copy(sid, &dom_list[i].sid);
2824 TALLOC_FREE(dom_list);
2825 return NT_STATUS_OK;
2828 /* Return status value returned by seq number check */
2830 if (!NT_STATUS_IS_OK(domain->last_status))
2831 return domain->last_status;
2833 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2836 status = domain->backend->trusted_domains(domain, mem_ctx, trusts);
2838 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2839 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2840 if (!domain->internal && old_status) {
2841 set_domain_offline(domain);
2843 if (!domain->internal &&
2846 retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2847 if (retval && num_domains && dom_list) {
2848 TALLOC_FREE(trusts->array);
2850 goto do_fetch_cache;
2854 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2855 * so that the generic centry handling still applies correctly -
2858 if (!NT_STATUS_IS_ERR(status)) {
2859 status = NT_STATUS_OK;
2864 /* get lockout policy */
2865 NTSTATUS wb_cache_lockout_policy(struct winbindd_domain *domain,
2866 TALLOC_CTX *mem_ctx,
2867 struct samr_DomInfo12 *policy)
2869 struct winbind_cache *cache = get_cache(domain);
2870 struct cache_entry *centry = NULL;
2874 old_status = domain->online;
2878 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2884 policy->lockout_duration = centry_nttime(centry);
2885 policy->lockout_window = centry_nttime(centry);
2886 policy->lockout_threshold = centry_uint16(centry);
2888 status = centry->status;
2890 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2891 domain->name, nt_errstr(status) ));
2893 centry_free(centry);
2897 ZERO_STRUCTP(policy);
2899 /* Return status value returned by seq number check */
2901 if (!NT_STATUS_IS_OK(domain->last_status))
2902 return domain->last_status;
2904 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2907 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2909 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2910 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2911 if (!domain->internal && old_status) {
2912 set_domain_offline(domain);
2915 !domain->internal &&
2918 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2920 goto do_fetch_cache;
2925 refresh_sequence_number(domain);
2926 if (!NT_STATUS_IS_OK(status)) {
2929 wcache_save_lockout_policy(domain, status, policy);
2934 /* get password policy */
2935 NTSTATUS wb_cache_password_policy(struct winbindd_domain *domain,
2936 TALLOC_CTX *mem_ctx,
2937 struct samr_DomInfo1 *policy)
2939 struct winbind_cache *cache = get_cache(domain);
2940 struct cache_entry *centry = NULL;
2944 old_status = domain->online;
2948 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2954 policy->min_password_length = centry_uint16(centry);
2955 policy->password_history_length = centry_uint16(centry);
2956 policy->password_properties = centry_uint32(centry);
2957 policy->max_password_age = centry_nttime(centry);
2958 policy->min_password_age = centry_nttime(centry);
2960 status = centry->status;
2962 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2963 domain->name, nt_errstr(status) ));
2965 centry_free(centry);
2969 ZERO_STRUCTP(policy);
2971 /* Return status value returned by seq number check */
2973 if (!NT_STATUS_IS_OK(domain->last_status))
2974 return domain->last_status;
2976 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2979 status = domain->backend->password_policy(domain, mem_ctx, policy);
2981 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2982 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2983 if (!domain->internal && old_status) {
2984 set_domain_offline(domain);
2987 !domain->internal &&
2990 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2992 goto do_fetch_cache;
2997 refresh_sequence_number(domain);
2998 if (!NT_STATUS_IS_OK(status)) {
3001 wcache_save_password_policy(domain, status, policy);
3007 /* Invalidate cached user and group lists coherently */
3009 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3012 if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
3013 strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
3014 tdb_delete(the_tdb, kbuf);
3019 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3021 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
3022 const struct dom_sid *sid)
3024 fstring key_str, sid_string;
3025 struct winbind_cache *cache;
3027 /* don't clear cached U/SID and UG/SID entries when we want to logon
3030 if (lp_winbind_offline_logon()) {
3037 cache = get_cache(domain);
3043 /* Clear U/SID cache entry */
3044 fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, sid));
3045 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
3046 tdb_delete(cache->tdb, string_tdb_data(key_str));
3048 /* Clear UG/SID cache entry */
3049 fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, sid));
3050 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
3051 tdb_delete(cache->tdb, string_tdb_data(key_str));
3053 /* Samba/winbindd never needs this. */
3054 netsamlogon_clear_cached_user(sid);
3057 bool wcache_invalidate_cache(void)
3059 struct winbindd_domain *domain;
3061 for (domain = domain_list(); domain; domain = domain->next) {
3062 struct winbind_cache *cache = get_cache(domain);
3064 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3065 "entries for %s\n", domain->name));
3068 tdb_traverse(cache->tdb, traverse_fn, NULL);
3077 bool wcache_invalidate_cache_noinit(void)
3079 struct winbindd_domain *domain;
3081 for (domain = domain_list(); domain; domain = domain->next) {
3082 struct winbind_cache *cache;
3084 /* Skip uninitialized domains. */
3085 if (!domain->initialized && !domain->internal) {
3089 cache = get_cache(domain);
3091 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3092 "entries for %s\n", domain->name));
3095 tdb_traverse(cache->tdb, traverse_fn, NULL);
3097 * Flushing cache has nothing to with domains.
3098 * return here if we successfully flushed once.
3099 * To avoid unnecessary traversing the cache.
3110 bool init_wcache(void)
3114 if (wcache == NULL) {
3115 wcache = SMB_XMALLOC_P(struct winbind_cache);
3116 ZERO_STRUCTP(wcache);
3119 if (wcache->tdb != NULL)
3122 db_path = wcache_path();
3123 if (db_path == NULL) {
3127 /* when working offline we must not clear the cache on restart */
3128 wcache->tdb = tdb_open_log(db_path,
3129 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3130 TDB_INCOMPATIBLE_HASH |
3131 (lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
3132 O_RDWR|O_CREAT, 0600);
3133 TALLOC_FREE(db_path);
3134 if (wcache->tdb == NULL) {
3135 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3142 /************************************************************************
3143 This is called by the parent to initialize the cache file.
3144 We don't need sophisticated locking here as we know we're the
3146 ************************************************************************/
3148 bool initialize_winbindd_cache(void)
3150 bool cache_bad = true;
3153 if (!init_wcache()) {
3154 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3158 /* Check version number. */
3159 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
3160 vers == WINBINDD_CACHE_VERSION) {
3167 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3168 "and re-creating with version number %d\n",
3169 WINBINDD_CACHE_VERSION ));
3171 tdb_close(wcache->tdb);
3174 db_path = wcache_path();
3175 if (db_path == NULL) {
3179 if (unlink(db_path) == -1) {
3180 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3183 TALLOC_FREE(db_path);
3186 TALLOC_FREE(db_path);
3187 if (!init_wcache()) {
3188 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3189 "init_wcache failed.\n"));
3193 /* Write the version. */
3194 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
3195 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3196 tdb_errorstr(wcache->tdb) ));
3201 tdb_close(wcache->tdb);
3206 void close_winbindd_cache(void)
3212 tdb_close(wcache->tdb);
3217 bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
3218 char **domain_name, char **name,
3219 enum lsa_SidType *type)
3221 struct winbindd_domain *domain;
3224 domain = find_lookup_domain_from_sid(sid);
3225 if (domain == NULL) {
3228 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
3230 return NT_STATUS_IS_OK(status);
3233 bool lookup_cached_name(const char *domain_name,
3235 struct dom_sid *sid,
3236 enum lsa_SidType *type)
3238 struct winbindd_domain *domain;
3240 bool original_online_state;
3242 domain = find_lookup_domain_from_name(domain_name);
3243 if (domain == NULL) {
3247 /* If we are doing a cached logon, temporarily set the domain
3248 offline so the cache won't expire the entry */
3250 original_online_state = domain->online;
3251 domain->online = false;
3252 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
3253 domain->online = original_online_state;
3255 return NT_STATUS_IS_OK(status);
3259 * Cache a name to sid without checking the sequence number.
3260 * Used when caching from a trusted PAC.
3263 void cache_name2sid_trusted(struct winbindd_domain *domain,
3264 const char *domain_name,
3266 enum lsa_SidType type,
3267 const struct dom_sid *sid)
3270 * Ensure we store the mapping with the
3271 * existing sequence number from the cache.
3274 (void)fetch_cache_seqnum(domain, time(NULL));
3275 wcache_save_name_to_sid(domain,
3283 void cache_name2sid(struct winbindd_domain *domain,
3284 const char *domain_name, const char *name,
3285 enum lsa_SidType type, const struct dom_sid *sid)
3287 refresh_sequence_number(domain);
3288 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
3293 * The original idea that this cache only contains centries has
3294 * been blurred - now other stuff gets put in here. Ensure we
3295 * ignore these things on cleanup.
3298 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
3299 TDB_DATA dbuf, void *state)
3301 struct cache_entry *centry;
3303 if (is_non_centry_key(kbuf)) {
3307 centry = wcache_fetch_raw((char *)kbuf.dptr);
3312 if (!NT_STATUS_IS_OK(centry->status)) {
3313 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
3314 tdb_delete(the_tdb, kbuf);
3317 centry_free(centry);
3321 /* flush the cache */
3322 void wcache_flush_cache(void)
3329 tdb_close(wcache->tdb);
3332 if (!winbindd_use_cache()) {
3336 db_path = wcache_path();
3337 if (db_path == NULL) {
3341 /* when working offline we must not clear the cache on restart */
3342 wcache->tdb = tdb_open_log(db_path,
3343 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3344 TDB_INCOMPATIBLE_HASH |
3345 (lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
3346 O_RDWR|O_CREAT, 0600);
3347 TALLOC_FREE(db_path);
3349 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3353 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
3355 DEBUG(10,("wcache_flush_cache success\n"));
3358 /* Count cached creds */
3360 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3363 int *cred_count = (int*)state;
3365 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3371 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
3373 struct winbind_cache *cache = get_cache(domain);
3378 return NT_STATUS_INTERNAL_DB_ERROR;
3381 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
3383 return NT_STATUS_OK;
3387 struct cred_list *prev, *next;
3392 static struct cred_list *wcache_cred_list;
3394 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3397 struct cred_list *cred;
3399 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3401 cred = SMB_MALLOC_P(struct cred_list);
3403 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3409 /* save a copy of the key */
3411 fstrcpy(cred->name, (const char *)kbuf.dptr);
3412 DLIST_ADD(wcache_cred_list, cred);
3418 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const struct dom_sid *sid)
3420 struct winbind_cache *cache = get_cache(domain);
3423 struct cred_list *cred, *next, *oldest = NULL;
3426 return NT_STATUS_INTERNAL_DB_ERROR;
3429 /* we possibly already have an entry */
3430 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
3432 fstring key_str, tmp;
3434 DEBUG(11,("we already have an entry, deleting that\n"));
3436 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
3438 tdb_delete(cache->tdb, string_tdb_data(key_str));
3440 return NT_STATUS_OK;
3443 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
3445 return NT_STATUS_OK;
3446 } else if ((ret < 0) || (wcache_cred_list == NULL)) {
3447 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3450 ZERO_STRUCTP(oldest);
3452 for (cred = wcache_cred_list; cred; cred = cred->next) {
3457 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
3459 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3461 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
3465 t = IVAL(data.dptr, 0);
3466 SAFE_FREE(data.dptr);
3469 oldest = SMB_MALLOC_P(struct cred_list);
3470 if (oldest == NULL) {
3471 status = NT_STATUS_NO_MEMORY;
3475 fstrcpy(oldest->name, cred->name);
3476 oldest->created = t;
3480 if (t < oldest->created) {
3481 fstrcpy(oldest->name, cred->name);
3482 oldest->created = t;
3486 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
3487 status = NT_STATUS_OK;
3489 status = NT_STATUS_UNSUCCESSFUL;
3492 for (cred = wcache_cred_list; cred; cred = next) {
3494 DLIST_REMOVE(wcache_cred_list, cred);
3502 /* Change the global online/offline state. */
3503 bool set_global_winbindd_state_offline(void)
3507 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3509 /* Only go offline if someone has created
3510 the key "WINBINDD_OFFLINE" in the cache tdb. */
3512 if (wcache == NULL || wcache->tdb == NULL) {
3513 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3517 if (!lp_winbind_offline_logon()) {
3518 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3522 if (global_winbindd_offline_state) {
3523 /* Already offline. */
3527 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
3529 if (!data.dptr || data.dsize != 4) {
3530 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3531 SAFE_FREE(data.dptr);
3534 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3535 global_winbindd_offline_state = true;
3536 SAFE_FREE(data.dptr);
3541 void set_global_winbindd_state_online(void)
3543 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3545 if (!lp_winbind_offline_logon()) {
3546 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3550 if (!global_winbindd_offline_state) {
3551 /* Already online. */
3554 global_winbindd_offline_state = false;
3560 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3561 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
3564 bool get_global_winbindd_state_offline(void)
3566 return global_winbindd_offline_state;
3569 /***********************************************************************
3570 Validate functions for all possible cache tdb keys.
3571 ***********************************************************************/
3573 static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
3574 struct tdb_validation_status *state)
3576 struct cache_entry *centry;
3578 centry = SMB_XMALLOC_P(struct cache_entry);
3579 centry->data = (unsigned char *)smb_memdup(data.dptr, data.dsize);
3580 if (!centry->data) {
3584 centry->len = data.dsize;
3587 if (centry->len < 16) {
3588 /* huh? corrupt cache? */
3589 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3590 "(len < 16) ?\n", kstr));
3591 centry_free(centry);
3592 state->bad_entry = true;
3593 state->success = false;
3597 centry->status = NT_STATUS(centry_uint32(centry));
3598 centry->sequence_number = centry_uint32(centry);
3599 centry->timeout = centry_uint64_t(centry);
3603 static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3604 struct tdb_validation_status *state)
3606 if (dbuf.dsize != 8) {
3607 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3608 keystr, (unsigned int)dbuf.dsize ));
3609 state->bad_entry = true;
3615 static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3616 struct tdb_validation_status *state)
3618 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3623 (void)centry_uint32(centry);
3624 if (NT_STATUS_IS_OK(centry->status)) {
3626 (void)centry_sid(centry, &sid);
3629 centry_free(centry);
3631 if (!(state->success)) {
3634 DEBUG(10,("validate_ns: %s ok\n", keystr));
3638 static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3639 struct tdb_validation_status *state)
3641 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3646 if (NT_STATUS_IS_OK(centry->status)) {
3647 (void)centry_uint32(centry);
3648 (void)centry_string(centry, mem_ctx);
3649 (void)centry_string(centry, mem_ctx);
3652 centry_free(centry);
3654 if (!(state->success)) {
3657 DEBUG(10,("validate_sn: %s ok\n", keystr));
3661 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3662 struct tdb_validation_status *state)
3664 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3671 (void)centry_string(centry, mem_ctx);
3672 (void)centry_string(centry, mem_ctx);
3673 (void)centry_string(centry, mem_ctx);
3674 (void)centry_string(centry, mem_ctx);
3675 (void)centry_string(centry, mem_ctx);
3676 (void)centry_uint32(centry);
3677 (void)centry_uint32(centry);
3678 (void)centry_string(centry, mem_ctx);
3679 (void)centry_sid(centry, &sid);
3680 (void)centry_sid(centry, &sid);
3682 centry_free(centry);
3684 if (!(state->success)) {
3687 DEBUG(10,("validate_u: %s ok\n", keystr));
3691 static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3692 struct tdb_validation_status *state)
3694 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3700 (void)centry_nttime(centry);
3701 (void)centry_nttime(centry);
3702 (void)centry_uint16(centry);
3704 centry_free(centry);
3706 if (!(state->success)) {
3709 DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
3713 static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3714 struct tdb_validation_status *state)
3716 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3722 (void)centry_uint16(centry);
3723 (void)centry_uint16(centry);
3724 (void)centry_uint32(centry);
3725 (void)centry_nttime(centry);
3726 (void)centry_nttime(centry);
3728 centry_free(centry);
3730 if (!(state->success)) {
3733 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
3737 static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3738 struct tdb_validation_status *state)
3740 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3746 (void)centry_time(centry);
3747 (void)centry_hash16(centry, mem_ctx);
3749 /* We only have 17 bytes more data in the salted cred case. */
3750 if (centry->len - centry->ofs == 17) {
3751 (void)centry_hash16(centry, mem_ctx);
3754 centry_free(centry);
3756 if (!(state->success)) {
3759 DEBUG(10,("validate_cred: %s ok\n", keystr));
3763 static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3764 struct tdb_validation_status *state)
3766 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3767 int32_t num_entries, i;
3773 num_entries = (int32_t)centry_uint32(centry);
3775 for (i=0; i< num_entries; i++) {
3776 (void)centry_uint32(centry);
3779 centry_free(centry);
3781 if (!(state->success)) {
3784 DEBUG(10,("validate_ul: %s ok\n", keystr));
3788 static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3789 struct tdb_validation_status *state)
3791 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3792 int32_t num_entries, i;
3798 num_entries = centry_uint32(centry);
3800 for (i=0; i< num_entries; i++) {
3801 (void)centry_string(centry, mem_ctx);
3802 (void)centry_string(centry, mem_ctx);
3803 (void)centry_uint32(centry);
3806 centry_free(centry);
3808 if (!(state->success)) {
3811 DEBUG(10,("validate_gl: %s ok\n", keystr));
3815 static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3816 struct tdb_validation_status *state)
3818 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3819 int32_t num_groups, i;
3825 num_groups = centry_uint32(centry);
3827 for (i=0; i< num_groups; i++) {
3829 centry_sid(centry, &sid);
3832 centry_free(centry);
3834 if (!(state->success)) {
3837 DEBUG(10,("validate_ug: %s ok\n", keystr));
3841 static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3842 struct tdb_validation_status *state)
3844 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3845 int32_t num_aliases, i;
3851 num_aliases = centry_uint32(centry);
3853 for (i=0; i < num_aliases; i++) {
3854 (void)centry_uint32(centry);
3857 centry_free(centry);
3859 if (!(state->success)) {
3862 DEBUG(10,("validate_ua: %s ok\n", keystr));
3866 static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3867 struct tdb_validation_status *state)
3869 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3870 int32_t num_names, i;
3876 num_names = centry_uint32(centry);
3878 for (i=0; i< num_names; i++) {
3880 centry_sid(centry, &sid);
3881 (void)centry_string(centry, mem_ctx);
3882 (void)centry_uint32(centry);
3885 centry_free(centry);
3887 if (!(state->success)) {
3890 DEBUG(10,("validate_gm: %s ok\n", keystr));
3894 static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3895 struct tdb_validation_status *state)
3897 /* Can't say anything about this other than must be nonzero. */
3898 if (dbuf.dsize == 0) {
3899 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3901 state->bad_entry = true;
3902 state->success = false;
3906 DEBUG(10,("validate_dr: %s ok\n", keystr));
3910 static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3911 struct tdb_validation_status *state)
3913 /* Can't say anything about this other than must be nonzero. */
3914 if (dbuf.dsize == 0) {
3915 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3917 state->bad_entry = true;
3918 state->success = false;
3922 DEBUG(10,("validate_de: %s ok\n", keystr));
3926 static int validate_nss_an(TALLOC_CTX *mem_ctx, const char *keystr,
3928 struct tdb_validation_status *state)
3930 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3936 (void)centry_string( centry, mem_ctx );
3938 centry_free(centry);
3940 if (!(state->success)) {
3943 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3947 static int validate_nss_na(TALLOC_CTX *mem_ctx, const char *keystr,
3949 struct tdb_validation_status *state)
3951 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3957 (void)centry_string( centry, mem_ctx );
3959 centry_free(centry);
3961 if (!(state->success)) {
3964 DBG_DEBUG("%s ok\n", keystr);
3968 static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
3970 struct tdb_validation_status *state)
3972 if (dbuf.dsize == 0) {
3973 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3974 "key %s (len ==0) ?\n", keystr));
3975 state->bad_entry = true;
3976 state->success = false;
3980 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
3981 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3985 static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3986 struct tdb_validation_status *state)
3988 if (dbuf.dsize != 4) {
3989 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3990 keystr, (unsigned int)dbuf.dsize ));
3991 state->bad_entry = true;
3992 state->success = false;
3995 DEBUG(10,("validate_offline: %s ok\n", keystr));
3999 static int validate_ndr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
4000 struct tdb_validation_status *state)
4003 * Ignore validation for now. The proper way to do this is with a
4004 * checksum. Just pure parsing does not really catch much.
4009 static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
4010 struct tdb_validation_status *state)
4012 if (dbuf.dsize != 4) {
4013 DEBUG(0, ("validate_cache_version: Corrupt cache for "
4014 "key %s (len %u != 4) ?\n",
4015 keystr, (unsigned int)dbuf.dsize));
4016 state->bad_entry = true;
4017 state->success = false;
4021 DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
4025 /***********************************************************************
4026 A list of all possible cache tdb keys with associated validation
4028 ***********************************************************************/
4030 struct key_val_struct {
4031 const char *keyname;
4032 int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
4034 {"SEQNUM/", validate_seqnum},
4035 {"NS/", validate_ns},
4036 {"SN/", validate_sn},
4038 {"LOC_POL/", validate_loc_pol},
4039 {"PWD_POL/", validate_pwd_pol},
4040 {"CRED/", validate_cred},
4041 {"UL/", validate_ul},
4042 {"GL/", validate_gl},
4043 {"UG/", validate_ug},
4044 {"UA", validate_ua},
4045 {"GM/", validate_gm},
4046 {"DR/", validate_dr},
4047 {"DE/", validate_de},
4048 {"TRUSTDOMCACHE/", validate_trustdomcache},
4049 {"NSS/NA/", validate_nss_na},
4050 {"NSS/AN/", validate_nss_an},
4051 {"WINBINDD_OFFLINE", validate_offline},
4052 {"NDR/", validate_ndr},
4053 {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
4057 /***********************************************************************
4058 Function to look at every entry in the tdb and validate it as far as
4060 ***********************************************************************/
4062 static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
4065 unsigned int max_key_len = 1024;
4066 struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
4068 /* Paranoia check. */
4069 if (strncmp("UA/", (const char *)kbuf.dptr, 3) == 0 ||
4070 strncmp("NDR/", (const char *)kbuf.dptr, 4) == 0) {
4071 max_key_len = 1024 * 1024;
4073 if (kbuf.dsize > max_key_len) {
4074 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4076 (unsigned int)kbuf.dsize, (unsigned int)max_key_len));
4080 for (i = 0; key_val[i].keyname; i++) {
4081 size_t namelen = strlen(key_val[i].keyname);
4082 if (kbuf.dsize >= namelen && (
4083 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
4084 TALLOC_CTX *mem_ctx;
4088 keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
4092 memcpy(keystr, kbuf.dptr, kbuf.dsize);
4093 keystr[kbuf.dsize] = '\0';
4095 mem_ctx = talloc_init("validate_ctx");
4101 ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
4105 talloc_destroy(mem_ctx);
4110 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4111 dump_data(0, (uint8_t *)kbuf.dptr, kbuf.dsize);
4112 DEBUG(0,("data :\n"));
4113 dump_data(0, (uint8_t *)dbuf.dptr, dbuf.dsize);
4114 v_state->unknown_key = true;
4115 v_state->success = false;
4116 return 1; /* terminate. */
4119 static void validate_panic(const char *const why)
4121 DEBUG(0,("validating cache: would panic %s\n", why ));
4122 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4126 static int wbcache_update_centry_fn(TDB_CONTEXT *tdb,
4134 if (is_non_centry_key(key)) {
4138 if (data.dptr == NULL || data.dsize == 0) {
4139 if (tdb_delete(tdb, key) < 0) {
4140 DEBUG(0, ("tdb_delete for [%s] failed!\n",
4146 /* add timeout to blob (uint64_t) */
4147 blob.dsize = data.dsize + 8;
4149 blob.dptr = SMB_XMALLOC_ARRAY(uint8_t, blob.dsize);
4150 if (blob.dptr == NULL) {
4153 memset(blob.dptr, 0, blob.dsize);
4155 /* copy status and seqnum */
4156 memcpy(blob.dptr, data.dptr, 8);
4159 ctimeout = lp_winbind_cache_time() + time(NULL);
4160 SBVAL(blob.dptr, 8, ctimeout);
4163 memcpy(blob.dptr + 16, data.dptr + 8, data.dsize - 8);
4165 if (tdb_store(tdb, key, blob, TDB_REPLACE) < 0) {
4166 DEBUG(0, ("tdb_store to update [%s] failed!\n",
4168 SAFE_FREE(blob.dptr);
4172 SAFE_FREE(blob.dptr);
4176 static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT *tdb)
4180 DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
4182 rc = tdb_traverse(tdb, wbcache_update_centry_fn, NULL);
4190 /***********************************************************************
4191 Try and validate every entry in the winbindd cache. If we fail here,
4192 delete the cache tdb and return non-zero.
4193 ***********************************************************************/
4195 int winbindd_validate_cache(void)
4198 char *tdb_path = NULL;
4199 TDB_CONTEXT *tdb = NULL;
4203 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4204 smb_panic_fn = validate_panic;
4206 tdb_path = wcache_path();
4207 if (tdb_path == NULL) {
4211 tdb = tdb_open_log(tdb_path,
4212 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
4213 TDB_INCOMPATIBLE_HASH |
4214 ( lp_winbind_offline_logon()
4216 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
4220 DEBUG(0, ("winbindd_validate_cache: "
4221 "error opening/initializing tdb\n"));
4225 /* Version check and upgrade code. */
4226 if (!tdb_fetch_uint32(tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers_id)) {
4227 DEBUG(10, ("Fresh database\n"));
4228 tdb_store_uint32(tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION);
4229 vers_id = WINBINDD_CACHE_VERSION;
4232 if (vers_id != WINBINDD_CACHE_VERSION) {
4233 if (vers_id == WINBINDD_CACHE_VER1) {
4234 ok = wbcache_upgrade_v1_to_v2(tdb);
4236 DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
4241 tdb_store_uint32(tdb,
4242 WINBINDD_CACHE_VERSION_KEYSTR,
4243 WINBINDD_CACHE_VERSION);
4244 vers_id = WINBINDD_CACHE_VER2;
4250 ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
4253 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4254 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
4259 TALLOC_FREE(tdb_path);
4260 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4261 smb_panic_fn = smb_panic;
4265 /***********************************************************************
4266 Try and validate every entry in the winbindd cache.
4267 ***********************************************************************/
4269 int winbindd_validate_cache_nobackup(void)
4274 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4275 smb_panic_fn = validate_panic;
4277 tdb_path = wcache_path();
4278 if (tdb_path == NULL) {
4279 goto err_panic_restore;
4282 if (wcache == NULL || wcache->tdb == NULL) {
4283 ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
4285 ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
4289 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4293 TALLOC_FREE(tdb_path);
4295 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4297 smb_panic_fn = smb_panic;
4301 bool winbindd_cache_validate_and_initialize(void)
4303 close_winbindd_cache();
4305 if (lp_winbind_offline_logon()) {
4306 if (winbindd_validate_cache() < 0) {
4307 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4308 "could be restored.\n"));
4312 return initialize_winbindd_cache();
4315 /*********************************************************************
4316 ********************************************************************/
4318 static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
4319 struct winbindd_tdc_domain **domains,
4320 size_t *num_domains )
4322 struct winbindd_tdc_domain *list = NULL;
4324 bool set_only = false;
4326 /* don't allow duplicates */
4331 for ( i=0; i< (*num_domains); i++ ) {
4332 if ( strequal( new_dom->name, list[i].domain_name ) ) {
4333 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4344 list = talloc_array( NULL, struct winbindd_tdc_domain, 1 );
4347 list = talloc_realloc( *domains, *domains,
4348 struct winbindd_tdc_domain,
4353 ZERO_STRUCT( list[idx] );
4359 list[idx].domain_name = talloc_strdup(list, new_dom->name);
4360 if (list[idx].domain_name == NULL) {
4363 if (new_dom->alt_name != NULL) {
4364 list[idx].dns_name = talloc_strdup(list, new_dom->alt_name);
4365 if (list[idx].dns_name == NULL) {
4370 if ( !is_null_sid( &new_dom->sid ) ) {
4371 sid_copy( &list[idx].sid, &new_dom->sid );
4373 sid_copy(&list[idx].sid, &global_sid_NULL);
4376 if ( new_dom->domain_flags != 0x0 )
4377 list[idx].trust_flags = new_dom->domain_flags;
4379 if ( new_dom->domain_type != 0x0 )
4380 list[idx].trust_type = new_dom->domain_type;
4382 if ( new_dom->domain_trust_attribs != 0x0 )
4383 list[idx].trust_attribs = new_dom->domain_trust_attribs;
4387 *num_domains = idx + 1;
4393 /*********************************************************************
4394 ********************************************************************/
4396 static TDB_DATA make_tdc_key( const char *domain_name )
4398 char *keystr = NULL;
4399 TDB_DATA key = { NULL, 0 };
4401 if ( !domain_name ) {
4402 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4406 if (asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name ) == -1) {
4409 key = string_term_tdb_data(keystr);
4414 /*********************************************************************
4415 ********************************************************************/
4417 static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
4419 unsigned char **buf )
4421 unsigned char *buffer = NULL;
4426 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4434 /* Store the number of array items first */
4435 len += tdb_pack( buffer+len, buflen-len, "d",
4438 /* now pack each domain trust record */
4439 for ( i=0; i<num_domains; i++ ) {
4444 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4445 domains[i].domain_name,
4446 domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
4449 len += tdb_pack( buffer+len, buflen-len, "fffddd",
4450 domains[i].domain_name,
4451 domains[i].dns_name ? domains[i].dns_name : "",
4452 sid_to_fstring(tmp, &domains[i].sid),
4453 domains[i].trust_flags,
4454 domains[i].trust_attribs,
4455 domains[i].trust_type );
4458 if ( buflen < len ) {
4460 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
4461 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4475 /*********************************************************************
4476 ********************************************************************/
4478 static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
4479 struct winbindd_tdc_domain **domains )
4481 fstring domain_name, dns_name, sid_string;
4482 uint32_t type, attribs, flags;
4486 struct winbindd_tdc_domain *list = NULL;
4488 /* get the number of domains */
4489 len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
4491 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4495 list = talloc_array( NULL, struct winbindd_tdc_domain, num_domains );
4497 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4501 for ( i=0; i<num_domains; i++ ) {
4504 this_len = tdb_unpack( buf+len, buflen-len, "fffddd",
4512 if ( this_len == -1 ) {
4513 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4514 TALLOC_FREE( list );
4519 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4520 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4521 domain_name, dns_name, sid_string,
4522 flags, attribs, type));
4524 list[i].domain_name = talloc_strdup( list, domain_name );
4525 list[i].dns_name = NULL;
4526 if (dns_name[0] != '\0') {
4527 list[i].dns_name = talloc_strdup(list, dns_name);
4529 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
4530 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4533 list[i].trust_flags = flags;
4534 list[i].trust_attribs = attribs;
4535 list[i].trust_type = type;
4543 /*********************************************************************
4544 ********************************************************************/
4546 static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
4548 TDB_DATA key = make_tdc_key( lp_workgroup() );
4549 TDB_DATA data = { NULL, 0 };
4555 /* See if we were asked to delete the cache entry */
4558 ret = tdb_delete( wcache->tdb, key );
4562 data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
4569 ret = tdb_store( wcache->tdb, key, data, 0 );
4572 SAFE_FREE( data.dptr );
4573 SAFE_FREE( key.dptr );
4575 return ( ret == 0 );
4578 /*********************************************************************
4579 ********************************************************************/
4581 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
4583 TDB_DATA key = make_tdc_key( lp_workgroup() );
4584 TDB_DATA data = { NULL, 0 };
4592 data = tdb_fetch( wcache->tdb, key );
4594 SAFE_FREE( key.dptr );
4599 *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
4601 SAFE_FREE( data.dptr );
4609 /*********************************************************************
4610 ********************************************************************/
4612 bool wcache_tdc_add_domain( struct winbindd_domain *domain )
4614 struct winbindd_tdc_domain *dom_list = NULL;
4615 size_t num_domains = 0;
4618 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4619 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4620 domain->name, domain->alt_name,
4621 sid_string_dbg(&domain->sid),
4622 domain->domain_flags,
4623 domain->domain_trust_attribs,
4624 domain->domain_type));
4626 if ( !init_wcache() ) {
4630 /* fetch the list */
4632 wcache_tdc_fetch_list( &dom_list, &num_domains );
4634 /* add the new domain */
4636 if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
4640 /* pack the domain */
4642 if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
4650 TALLOC_FREE( dom_list );
4655 static struct winbindd_tdc_domain *wcache_tdc_dup_domain(
4656 TALLOC_CTX *mem_ctx, const struct winbindd_tdc_domain *src)
4658 struct winbindd_tdc_domain *dst;
4660 dst = talloc(mem_ctx, struct winbindd_tdc_domain);
4664 dst->domain_name = talloc_strdup(dst, src->domain_name);
4665 if (dst->domain_name == NULL) {
4669 dst->dns_name = NULL;
4670 if (src->dns_name != NULL) {
4671 dst->dns_name = talloc_strdup(dst, src->dns_name);
4672 if (dst->dns_name == NULL) {
4677 sid_copy(&dst->sid, &src->sid);
4678 dst->trust_flags = src->trust_flags;
4679 dst->trust_type = src->trust_type;
4680 dst->trust_attribs = src->trust_attribs;
4687 /*********************************************************************
4688 ********************************************************************/
4690 struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
4692 struct winbindd_tdc_domain *dom_list = NULL;
4693 size_t num_domains = 0;
4695 struct winbindd_tdc_domain *d = NULL;
4697 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
4699 if ( !init_wcache() ) {
4703 /* fetch the list */
4705 wcache_tdc_fetch_list( &dom_list, &num_domains );
4707 for ( i=0; i<num_domains; i++ ) {
4708 if ( strequal(name, dom_list[i].domain_name) ||
4709 strequal(name, dom_list[i].dns_name) )
4711 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4714 d = wcache_tdc_dup_domain(ctx, &dom_list[i]);
4719 TALLOC_FREE( dom_list );
4724 /*********************************************************************
4725 ********************************************************************/
4727 void wcache_tdc_clear( void )
4729 if ( !init_wcache() )
4732 wcache_tdc_store_list( NULL, 0 );
4737 static bool wcache_ndr_key(TALLOC_CTX *mem_ctx, const char *domain_name,
4738 uint32_t opnum, const DATA_BLOB *req,
4744 key = talloc_asprintf(mem_ctx, "NDR/%s/%d/", domain_name, (int)opnum);
4748 keylen = talloc_get_size(key) - 1;
4750 key = talloc_realloc(mem_ctx, key, char, keylen + req->length);
4754 memcpy(key + keylen, req->data, req->length);
4756 pkey->dptr = (uint8_t *)key;
4757 pkey->dsize = talloc_get_size(key);
4761 static bool wcache_opnum_cacheable(uint32_t opnum)
4764 case NDR_WBINT_PING:
4765 case NDR_WBINT_QUERYSEQUENCENUMBER:
4766 case NDR_WBINT_ALLOCATEUID:
4767 case NDR_WBINT_ALLOCATEGID:
4768 case NDR_WBINT_CHECKMACHINEACCOUNT:
4769 case NDR_WBINT_CHANGEMACHINEACCOUNT:
4770 case NDR_WBINT_PINGDC:
4776 bool wcache_fetch_ndr(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
4777 uint32_t opnum, const DATA_BLOB *req, DATA_BLOB *resp)
4782 if (!wcache_opnum_cacheable(opnum) ||
4783 is_my_own_sam_domain(domain) ||
4784 is_builtin_domain(domain)) {
4788 if (wcache->tdb == NULL) {
4792 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4795 data = tdb_fetch(wcache->tdb, key);
4796 TALLOC_FREE(key.dptr);
4798 if (data.dptr == NULL) {
4801 if (data.dsize < 12) {
4805 if (!is_domain_offline(domain)) {
4806 uint32_t entry_seqnum, dom_seqnum, last_check;
4807 uint64_t entry_timeout;
4809 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum,
4813 entry_seqnum = IVAL(data.dptr, 0);
4814 if (entry_seqnum != dom_seqnum) {
4815 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4816 (int)entry_seqnum));
4819 entry_timeout = BVAL(data.dptr, 4);
4820 if (time(NULL) > entry_timeout) {
4821 DEBUG(10, ("Entry has timed out\n"));
4826 resp->data = (uint8_t *)talloc_memdup(mem_ctx, data.dptr + 12,
4828 if (resp->data == NULL) {
4829 DEBUG(10, ("talloc failed\n"));
4832 resp->length = data.dsize - 12;
4836 SAFE_FREE(data.dptr);
4840 void wcache_store_ndr(struct winbindd_domain *domain, uint32_t opnum,
4841 const DATA_BLOB *req, const DATA_BLOB *resp)
4844 uint32_t dom_seqnum, last_check;
4847 if (!wcache_opnum_cacheable(opnum) ||
4848 is_my_own_sam_domain(domain) ||
4849 is_builtin_domain(domain)) {
4853 if (wcache->tdb == NULL) {
4857 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum, &last_check)) {
4858 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4863 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4867 timeout = time(NULL) + lp_winbind_cache_time();
4869 data.dsize = resp->length + 12;
4870 data.dptr = talloc_array(key.dptr, uint8_t, data.dsize);
4871 if (data.dptr == NULL) {
4875 SIVAL(data.dptr, 0, dom_seqnum);
4876 SBVAL(data.dptr, 4, timeout);
4877 memcpy(data.dptr + 12, resp->data, resp->length);
4879 tdb_store(wcache->tdb, key, data, 0);
4882 TALLOC_FREE(key.dptr);