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;
55 static void wcache_flush_cache(void);
58 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
59 * Here are the list of entry types that are *not* stored
60 * as form struct cache_entry in the cache.
63 static const char *non_centry_keys[] = {
66 WINBINDD_CACHE_VERSION_KEYSTR,
70 /************************************************************************
71 Is this key a non-centry type ?
72 ************************************************************************/
74 static bool is_non_centry_key(TDB_DATA kbuf)
78 if (kbuf.dptr == NULL || kbuf.dsize == 0) {
81 for (i = 0; non_centry_keys[i] != NULL; i++) {
82 size_t namelen = strlen(non_centry_keys[i]);
83 if (kbuf.dsize < namelen) {
86 if (strncmp(non_centry_keys[i], (const char *)kbuf.dptr, namelen) == 0) {
93 /* Global online/offline state - False when online. winbindd starts up online
94 and sets this to true if the first query fails and there's an entry in
95 the cache tdb telling us to stay offline. */
97 static bool global_winbindd_offline_state;
99 struct winbind_cache {
105 uint32_t sequence_number;
111 void (*smb_panic_fn)(const char *const why) = smb_panic;
113 static struct winbind_cache *wcache;
115 static char *wcache_path(void)
118 * Data needs to be kept persistent in state directory for
119 * running with "winbindd offline logon".
121 return state_path("winbindd_cache.tdb");
124 /* get the winbind_cache structure */
125 static struct winbind_cache *get_cache(struct winbindd_domain *domain)
127 struct winbind_cache *ret = wcache;
129 /* We have to know what type of domain we are dealing with first. */
131 if (domain->internal) {
132 domain->backend = &builtin_passdb_methods;
135 if (dom_sid_equal(&domain->sid, &global_sid_Builtin)) {
136 domain->initialized = true;
139 if (strequal(domain->name, get_global_sam_name()) &&
140 sid_check_is_our_sam(&domain->sid))
142 domain->backend = &sam_passdb_methods;
145 if (!domain->initialized) {
146 /* We do not need a connection to an RW DC for cache operation */
147 init_dc_connection(domain, false);
151 OK. Listen up because I'm only going to say this once.
152 We have the following scenarios to consider
153 (a) trusted AD domains on a Samba DC,
154 (b) trusted AD domains and we are joined to a non-kerberos domain
155 (c) trusted AD domains and we are joined to a kerberos (AD) domain
157 For (a) we can always contact the trusted domain using krb5
158 since we have the domain trust account password
160 For (b) we can only use RPC since we have no way of
161 getting a krb5 ticket in our own domain
163 For (c) we can always use krb5 since we have a kerberos trust
169 if (domain->backend == NULL) {
170 struct winbindd_domain *our_domain = domain;
172 /* find our domain first so we can figure out if we
173 are joined to a kerberized domain */
175 if (!domain->primary) {
176 our_domain = find_our_domain();
179 if ((our_domain->active_directory || IS_DC)
180 && domain->active_directory
181 && !lp_winbind_rpc_only())
183 DBG_INFO("Setting ADS methods for domain %s\n",
185 domain->backend = &reconnect_ads_methods;
188 #endif /* HAVE_ADS */
190 if (domain->backend == NULL) {
191 DBG_INFO("Setting MS-RPC methods for domain %s\n", domain->name);
192 domain->backend = &reconnect_methods;
199 ret = SMB_XMALLOC_P(struct winbind_cache);
203 wcache_flush_cache();
209 free a centry structure
211 static void centry_free(struct cache_entry *centry)
215 SAFE_FREE(centry->data);
219 static bool centry_check_bytes(struct cache_entry *centry, size_t nbytes)
221 if (centry->len - centry->ofs < nbytes) {
222 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
223 (unsigned int)nbytes,
224 centry->len - centry->ofs));
231 pull a uint64_t from a cache entry
233 static uint64_t centry_uint64_t(struct cache_entry *centry)
237 if (!centry_check_bytes(centry, 8)) {
238 smb_panic_fn("centry_uint64_t");
240 ret = BVAL(centry->data, centry->ofs);
246 pull a uint32_t from a cache entry
248 static uint32_t centry_uint32(struct cache_entry *centry)
252 if (!centry_check_bytes(centry, 4)) {
253 smb_panic_fn("centry_uint32");
255 ret = IVAL(centry->data, centry->ofs);
261 pull a uint16_t from a cache entry
263 static uint16_t centry_uint16(struct cache_entry *centry)
266 if (!centry_check_bytes(centry, 2)) {
267 smb_panic_fn("centry_uint16");
269 ret = SVAL(centry->data, centry->ofs);
275 pull a uint8_t from a cache entry
277 static uint8_t centry_uint8(struct cache_entry *centry)
280 if (!centry_check_bytes(centry, 1)) {
281 smb_panic_fn("centry_uint8");
283 ret = CVAL(centry->data, centry->ofs);
289 pull a NTTIME from a cache entry
291 static NTTIME centry_nttime(struct cache_entry *centry)
294 if (!centry_check_bytes(centry, 8)) {
295 smb_panic_fn("centry_nttime");
297 ret = IVAL(centry->data, centry->ofs);
299 ret += (uint64_t)IVAL(centry->data, centry->ofs) << 32;
305 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
307 static time_t centry_time(struct cache_entry *centry)
309 return (time_t)centry_nttime(centry);
312 /* pull a string from a cache entry, using the supplied
315 static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
320 len = centry_uint8(centry);
323 /* a deliberate NULL string */
327 if (!centry_check_bytes(centry, (size_t)len)) {
328 smb_panic_fn("centry_string");
331 ret = talloc_array(mem_ctx, char, len+1);
333 smb_panic_fn("centry_string out of memory\n");
335 memcpy(ret,centry->data + centry->ofs, len);
341 /* pull a hash16 from a cache entry, using the supplied
344 static char *centry_hash16(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
349 len = centry_uint8(centry);
352 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
357 if (!centry_check_bytes(centry, 16)) {
361 ret = talloc_array(mem_ctx, char, 16);
363 smb_panic_fn("centry_hash out of memory\n");
365 memcpy(ret,centry->data + centry->ofs, 16);
370 /* pull a sid from a cache entry, using the supplied
373 static bool centry_sid(struct cache_entry *centry, struct dom_sid *sid)
378 sid_string = centry_string(centry, talloc_tos());
379 if (sid_string == NULL) {
382 ret = string_to_sid(sid, sid_string);
383 TALLOC_FREE(sid_string);
389 pull a NTSTATUS from a cache entry
391 static NTSTATUS centry_ntstatus(struct cache_entry *centry)
395 status = NT_STATUS(centry_uint32(centry));
400 /* the server is considered down if it can't give us a sequence number */
401 static bool wcache_server_down(struct winbindd_domain *domain)
408 ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
411 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
416 struct wcache_seqnum_state {
418 uint32_t *last_seq_check;
421 static int wcache_seqnum_parser(TDB_DATA key, TDB_DATA data,
424 struct wcache_seqnum_state *state = private_data;
426 if (data.dsize != 8) {
427 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
432 *state->seqnum = IVAL(data.dptr, 0);
433 *state->last_seq_check = IVAL(data.dptr, 4);
437 static bool wcache_fetch_seqnum(const char *domain_name, uint32_t *seqnum,
438 uint32_t *last_seq_check)
440 struct wcache_seqnum_state state = {
441 .seqnum = seqnum, .last_seq_check = last_seq_check
443 size_t len = strlen(domain_name);
445 TDB_DATA key = { .dptr = (uint8_t *)keystr, .dsize = sizeof(keystr) };
448 if (wcache->tdb == NULL) {
449 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
453 snprintf(keystr, sizeof(keystr), "SEQNUM/%s", domain_name);
455 ret = tdb_parse_record(wcache->tdb, key, wcache_seqnum_parser,
460 static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
462 uint32_t last_check, time_diff;
464 if (!wcache_fetch_seqnum(domain->name, &domain->sequence_number,
466 return NT_STATUS_UNSUCCESSFUL;
468 domain->last_seq_check = last_check;
470 /* have we expired? */
472 time_diff = now - domain->last_seq_check;
473 if ( time_diff > lp_winbind_cache_time() ) {
474 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
475 domain->name, domain->sequence_number,
476 (uint32_t)domain->last_seq_check));
477 return NT_STATUS_UNSUCCESSFUL;
480 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
481 domain->name, domain->sequence_number,
482 (uint32_t)domain->last_seq_check));
487 bool wcache_store_seqnum(const char *domain_name, uint32_t seqnum,
488 time_t last_seq_check)
490 size_t len = strlen(domain_name);
492 TDB_DATA key = { .dptr = (uint8_t *)keystr, .dsize = sizeof(keystr) };
496 if (wcache->tdb == NULL) {
497 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
501 snprintf(keystr, sizeof(keystr), "SEQNUM/%s", domain_name);
503 SIVAL(buf, 0, seqnum);
504 SIVAL(buf, 4, last_seq_check);
506 ret = tdb_store(wcache->tdb, key, make_tdb_data(buf, sizeof(buf)),
509 DEBUG(10, ("tdb_store_bystring failed: %s\n",
510 tdb_errorstr(wcache->tdb)));
514 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
515 domain_name, seqnum, (unsigned)last_seq_check));
520 static bool store_cache_seqnum( struct winbindd_domain *domain )
522 return wcache_store_seqnum(domain->name, domain->sequence_number,
523 domain->last_seq_check);
527 refresh the domain sequence number on timeout.
530 static void refresh_sequence_number(struct winbindd_domain *domain)
534 time_t t = time(NULL);
535 unsigned cache_time = lp_winbind_cache_time();
537 if (is_domain_offline(domain)) {
543 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
544 /* trying to reconnect is expensive, don't do it too often */
545 if (domain->sequence_number == DOM_SEQUENCE_NONE) {
550 time_diff = t - domain->last_seq_check;
552 /* see if we have to refetch the domain sequence number */
553 if ((time_diff < cache_time) &&
554 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
555 NT_STATUS_IS_OK(domain->last_status)) {
556 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
560 /* try to get the sequence number from the tdb cache first */
561 /* this will update the timestamp as well */
563 status = fetch_cache_seqnum( domain, t );
564 if (NT_STATUS_IS_OK(status) &&
565 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
566 NT_STATUS_IS_OK(domain->last_status)) {
570 /* important! make sure that we know if this is a native
571 mode domain or not. And that we can contact it. */
573 if ( winbindd_can_contact_domain( domain ) ) {
574 status = domain->backend->sequence_number(domain,
575 &domain->sequence_number);
577 /* just use the current time */
578 status = NT_STATUS_OK;
579 domain->sequence_number = time(NULL);
583 /* the above call could have set our domain->backend to NULL when
584 * coming from offline to online mode, make sure to reinitialize the
585 * backend - Guenther */
588 if (!NT_STATUS_IS_OK(status)) {
589 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status)));
590 domain->sequence_number = DOM_SEQUENCE_NONE;
593 domain->last_status = status;
594 domain->last_seq_check = time(NULL);
596 /* save the new sequence number in the cache */
597 store_cache_seqnum( domain );
600 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
601 domain->name, domain->sequence_number));
607 decide if a cache entry has expired
609 static bool centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
611 /* If we've been told to be offline - stay in that state... */
612 if (lp_winbind_offline_logon() && global_winbindd_offline_state) {
613 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
614 keystr, domain->name ));
618 /* when the domain is offline return the cached entry.
619 * This deals with transient offline states... */
621 if (!domain->online) {
622 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
623 keystr, domain->name ));
627 /* if the server is OK and our cache entry came from when it was down then
628 the entry is invalid */
629 if ((domain->sequence_number != DOM_SEQUENCE_NONE) &&
630 (centry->sequence_number == DOM_SEQUENCE_NONE)) {
631 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
632 keystr, domain->name ));
636 /* if the server is down or the cache entry is not older than the
637 current sequence number or it did not timeout then it is OK */
638 if (wcache_server_down(domain)
639 || ((centry->sequence_number == domain->sequence_number)
640 && (centry->timeout > time(NULL)))) {
641 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
642 keystr, domain->name ));
646 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
647 keystr, domain->name ));
653 static struct cache_entry *wcache_fetch_raw(char *kstr)
656 struct cache_entry *centry;
659 key = string_tdb_data(kstr);
660 data = tdb_fetch(wcache->tdb, key);
666 centry = SMB_XMALLOC_P(struct cache_entry);
667 centry->data = (unsigned char *)data.dptr;
668 centry->len = data.dsize;
671 if (centry->len < 16) {
672 /* huh? corrupt cache? */
673 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s "
674 "(len < 16)?\n", kstr));
679 centry->status = centry_ntstatus(centry);
680 centry->sequence_number = centry_uint32(centry);
681 centry->timeout = centry_uint64_t(centry);
686 static bool is_my_own_sam_domain(struct winbindd_domain *domain)
688 if (strequal(domain->name, get_global_sam_name()) &&
689 sid_check_is_our_sam(&domain->sid)) {
696 static bool is_builtin_domain(struct winbindd_domain *domain)
698 if (strequal(domain->name, "BUILTIN") &&
699 sid_check_is_builtin(&domain->sid)) {
707 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
708 number and return status
710 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
711 struct winbindd_domain *domain,
712 const char *format, ...) PRINTF_ATTRIBUTE(3,4);
713 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
714 struct winbindd_domain *domain,
715 const char *format, ...)
719 struct cache_entry *centry;
721 if (!winbindd_use_cache() ||
722 is_my_own_sam_domain(domain) ||
723 is_builtin_domain(domain)) {
727 refresh_sequence_number(domain);
729 va_start(ap, format);
730 smb_xvasprintf(&kstr, format, ap);
733 centry = wcache_fetch_raw(kstr);
734 if (centry == NULL) {
739 if (centry_expired(domain, kstr, centry)) {
741 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
742 kstr, domain->name ));
749 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
750 kstr, domain->name ));
756 static void wcache_delete(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
757 static void wcache_delete(const char *format, ...)
763 va_start(ap, format);
764 smb_xvasprintf(&kstr, format, ap);
767 key = string_tdb_data(kstr);
769 tdb_delete(wcache->tdb, key);
774 make sure we have at least len bytes available in a centry
776 static void centry_expand(struct cache_entry *centry, uint32_t len)
778 if (centry->len - centry->ofs >= len)
781 centry->data = SMB_REALLOC_ARRAY(centry->data, unsigned char,
784 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
785 smb_panic_fn("out of memory in centry_expand");
790 push a uint64_t into a centry
792 static void centry_put_uint64_t(struct cache_entry *centry, uint64_t v)
794 centry_expand(centry, 8);
795 SBVAL(centry->data, centry->ofs, v);
800 push a uint32_t into a centry
802 static void centry_put_uint32(struct cache_entry *centry, uint32_t v)
804 centry_expand(centry, 4);
805 SIVAL(centry->data, centry->ofs, v);
810 push a uint16_t into a centry
812 static void centry_put_uint16(struct cache_entry *centry, uint16_t v)
814 centry_expand(centry, 2);
815 SSVAL(centry->data, centry->ofs, v);
820 push a uint8_t into a centry
822 static void centry_put_uint8(struct cache_entry *centry, uint8_t v)
824 centry_expand(centry, 1);
825 SCVAL(centry->data, centry->ofs, v);
830 push a string into a centry
832 static void centry_put_string(struct cache_entry *centry, const char *s)
837 /* null strings are marked as len 0xFFFF */
838 centry_put_uint8(centry, 0xFF);
843 /* can't handle more than 254 char strings. Truncating is probably best */
845 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len));
848 centry_put_uint8(centry, len);
849 centry_expand(centry, len);
850 memcpy(centry->data + centry->ofs, s, len);
855 push a 16 byte hash into a centry - treat as 16 byte string.
857 static void centry_put_hash16(struct cache_entry *centry, const uint8_t val[16])
859 centry_put_uint8(centry, 16);
860 centry_expand(centry, 16);
861 memcpy(centry->data + centry->ofs, val, 16);
865 static void centry_put_sid(struct cache_entry *centry, const struct dom_sid *sid)
868 centry_put_string(centry, sid_to_fstring(sid_string, sid));
873 put NTSTATUS into a centry
875 static void centry_put_ntstatus(struct cache_entry *centry, NTSTATUS status)
877 uint32_t status_value = NT_STATUS_V(status);
878 centry_put_uint32(centry, status_value);
883 push a NTTIME into a centry
885 static void centry_put_nttime(struct cache_entry *centry, NTTIME nt)
887 centry_expand(centry, 8);
888 SIVAL(centry->data, centry->ofs, nt & 0xFFFFFFFF);
890 SIVAL(centry->data, centry->ofs, nt >> 32);
895 push a time_t into a centry - use a 64 bit size.
896 NTTIME here is being used as a convenient 64-bit size.
898 static void centry_put_time(struct cache_entry *centry, time_t t)
900 NTTIME nt = (NTTIME)t;
901 centry_put_nttime(centry, nt);
905 start a centry for output. When finished, call centry_end()
907 static struct cache_entry *centry_start(struct winbindd_domain *domain,
910 struct cache_entry *centry;
915 centry = SMB_XMALLOC_P(struct cache_entry);
917 centry->len = 8192; /* reasonable default */
918 centry->data = SMB_XMALLOC_ARRAY(uint8_t, centry->len);
920 centry->sequence_number = domain->sequence_number;
921 centry->timeout = lp_winbind_cache_time() + time(NULL);
922 centry_put_ntstatus(centry, status);
923 centry_put_uint32(centry, centry->sequence_number);
924 centry_put_uint64_t(centry, centry->timeout);
929 finish a centry and write it to the tdb
931 static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
932 static void centry_end(struct cache_entry *centry, const char *format, ...)
938 if (!winbindd_use_cache()) {
942 va_start(ap, format);
943 smb_xvasprintf(&kstr, format, ap);
946 key = string_tdb_data(kstr);
947 data.dptr = centry->data;
948 data.dsize = centry->ofs;
950 tdb_store(wcache->tdb, key, data, TDB_REPLACE);
954 static void wcache_save_name_to_sid(struct winbindd_domain *domain,
955 NTSTATUS status, const char *domain_name,
956 const char *name, const struct dom_sid *sid,
957 enum lsa_SidType type)
959 struct cache_entry *centry;
962 centry = centry_start(domain, status);
966 if ((domain_name == NULL) || (domain_name[0] == '\0')) {
967 struct winbindd_domain *mydomain =
968 find_domain_from_sid_noinit(sid);
969 if (mydomain != NULL) {
970 domain_name = mydomain->name;
974 centry_put_uint32(centry, type);
975 centry_put_sid(centry, sid);
976 fstrcpy(uname, name);
977 (void)strupper_m(uname);
978 centry_end(centry, "NS/%s/%s", domain_name, uname);
979 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name,
980 uname, sid_string_dbg(sid), nt_errstr(status)));
984 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
985 const struct dom_sid *sid, const char *domain_name, const char *name, enum lsa_SidType type)
987 struct cache_entry *centry;
990 centry = centry_start(domain, status);
994 if ((domain_name == NULL) || (domain_name[0] == '\0')) {
995 struct winbindd_domain *mydomain =
996 find_domain_from_sid_noinit(sid);
997 if (mydomain != NULL) {
998 domain_name = mydomain->name;
1002 if (NT_STATUS_IS_OK(status)) {
1003 centry_put_uint32(centry, type);
1004 centry_put_string(centry, domain_name);
1005 centry_put_string(centry, name);
1008 centry_end(centry, "SN/%s", sid_to_fstring(sid_string, sid));
1009 DEBUG(10,("wcache_save_sid_to_name: %s -> %s\\%s (%s)\n", sid_string,
1010 domain_name, name, nt_errstr(status)));
1011 centry_free(centry);
1014 static void wcache_save_lockout_policy(struct winbindd_domain *domain,
1016 struct samr_DomInfo12 *lockout_policy)
1018 struct cache_entry *centry;
1020 centry = centry_start(domain, status);
1024 centry_put_nttime(centry, lockout_policy->lockout_duration);
1025 centry_put_nttime(centry, lockout_policy->lockout_window);
1026 centry_put_uint16(centry, lockout_policy->lockout_threshold);
1028 centry_end(centry, "LOC_POL/%s", domain->name);
1030 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
1032 centry_free(centry);
1037 static void wcache_save_password_policy(struct winbindd_domain *domain,
1039 struct samr_DomInfo1 *policy)
1041 struct cache_entry *centry;
1043 centry = centry_start(domain, status);
1047 centry_put_uint16(centry, policy->min_password_length);
1048 centry_put_uint16(centry, policy->password_history_length);
1049 centry_put_uint32(centry, policy->password_properties);
1050 centry_put_nttime(centry, policy->max_password_age);
1051 centry_put_nttime(centry, policy->min_password_age);
1053 centry_end(centry, "PWD_POL/%s", domain->name);
1055 DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
1057 centry_free(centry);
1060 /***************************************************************************
1061 ***************************************************************************/
1063 static void wcache_save_username_alias(struct winbindd_domain *domain,
1065 const char *name, const char *alias)
1067 struct cache_entry *centry;
1070 if ( (centry = centry_start(domain, status)) == NULL )
1073 centry_put_string( centry, alias );
1075 fstrcpy(uname, name);
1076 (void)strupper_m(uname);
1077 centry_end(centry, "NSS/NA/%s", uname);
1079 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name, alias ));
1081 centry_free(centry);
1084 static void wcache_save_alias_username(struct winbindd_domain *domain,
1086 const char *alias, const char *name)
1088 struct cache_entry *centry;
1091 if ( (centry = centry_start(domain, status)) == NULL )
1094 centry_put_string( centry, name );
1096 fstrcpy(uname, alias);
1097 (void)strupper_m(uname);
1098 centry_end(centry, "NSS/AN/%s", uname);
1100 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias, name ));
1102 centry_free(centry);
1105 /***************************************************************************
1106 ***************************************************************************/
1108 NTSTATUS resolve_username_to_alias( TALLOC_CTX *mem_ctx,
1109 struct winbindd_domain *domain,
1110 const char *name, char **alias )
1112 struct winbind_cache *cache = get_cache(domain);
1113 struct cache_entry *centry = NULL;
1117 if ( domain->internal )
1118 return NT_STATUS_NOT_SUPPORTED;
1123 upper_name = talloc_strdup_upper(mem_ctx, name);
1124 if (upper_name == NULL) {
1125 return NT_STATUS_NO_MEMORY;
1128 centry = wcache_fetch(cache, domain, "NSS/NA/%s", upper_name);
1130 talloc_free(upper_name);
1135 status = centry->status;
1137 if (!NT_STATUS_IS_OK(status)) {
1138 centry_free(centry);
1142 *alias = centry_string( centry, mem_ctx );
1144 centry_free(centry);
1146 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1147 name, *alias ? *alias : "(none)"));
1149 return (*alias) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1153 /* If its not in cache and we are offline, then fail */
1155 if ( get_global_winbindd_state_offline() || !domain->online ) {
1156 DEBUG(8,("resolve_username_to_alias: rejecting query "
1157 "in offline mode\n"));
1158 return NT_STATUS_NOT_FOUND;
1161 status = nss_map_to_alias( mem_ctx, domain->name, name, alias );
1163 if ( NT_STATUS_IS_OK( status ) ) {
1164 wcache_save_username_alias(domain, status, name, *alias);
1167 if ( NT_STATUS_EQUAL( status, NT_STATUS_NONE_MAPPED ) ) {
1168 wcache_save_username_alias(domain, status, name, "(NULL)");
1171 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1172 nt_errstr(status)));
1174 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1175 set_domain_offline( domain );
1181 /***************************************************************************
1182 ***************************************************************************/
1184 NTSTATUS resolve_alias_to_username( TALLOC_CTX *mem_ctx,
1185 struct winbindd_domain *domain,
1186 const char *alias, char **name )
1188 struct winbind_cache *cache = get_cache(domain);
1189 struct cache_entry *centry = NULL;
1193 if ( domain->internal )
1194 return NT_STATUS_NOT_SUPPORTED;
1199 upper_name = talloc_strdup(mem_ctx, alias);
1200 if (upper_name == NULL) {
1201 return NT_STATUS_NO_MEMORY;
1203 if (!strupper_m(upper_name)) {
1204 talloc_free(upper_name);
1205 return NT_STATUS_INVALID_PARAMETER;
1208 centry = wcache_fetch(cache, domain, "NSS/AN/%s", upper_name);
1210 talloc_free(upper_name);
1215 status = centry->status;
1217 if (!NT_STATUS_IS_OK(status)) {
1218 centry_free(centry);
1222 *name = centry_string( centry, mem_ctx );
1224 centry_free(centry);
1226 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1227 alias, *name ? *name : "(none)"));
1229 return (*name) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1233 /* If its not in cache and we are offline, then fail */
1235 if ( get_global_winbindd_state_offline() || !domain->online ) {
1236 DEBUG(8,("resolve_alias_to_username: rejecting query "
1237 "in offline mode\n"));
1238 return NT_STATUS_NOT_FOUND;
1241 /* an alias cannot contain a domain prefix or '@' */
1243 if (strchr(alias, '\\') || strchr(alias, '@')) {
1244 DEBUG(10,("resolve_alias_to_username: skipping fully "
1245 "qualified name %s\n", alias));
1246 return NT_STATUS_OBJECT_NAME_INVALID;
1249 status = nss_map_from_alias( mem_ctx, domain->name, alias, name );
1251 if ( NT_STATUS_IS_OK( status ) ) {
1252 wcache_save_alias_username( domain, status, alias, *name );
1255 if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1256 wcache_save_alias_username(domain, status, alias, "(NULL)");
1259 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1260 nt_errstr(status)));
1262 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1263 set_domain_offline( domain );
1269 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const struct dom_sid *sid)
1271 struct winbind_cache *cache = get_cache(domain);
1273 fstring key_str, tmp;
1277 return NT_STATUS_INTERNAL_DB_ERROR;
1280 if (is_null_sid(sid)) {
1281 return NT_STATUS_INVALID_SID;
1284 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1285 return NT_STATUS_INVALID_SID;
1288 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
1290 ret = tdb_exists(cache->tdb, string_tdb_data(key_str));
1292 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1295 return NT_STATUS_OK;
1298 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1299 as new salted ones. */
1301 NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
1302 TALLOC_CTX *mem_ctx,
1303 const struct dom_sid *sid,
1304 const uint8_t **cached_nt_pass,
1305 const uint8_t **cached_salt)
1307 struct winbind_cache *cache = get_cache(domain);
1308 struct cache_entry *centry = NULL;
1314 return NT_STATUS_INTERNAL_DB_ERROR;
1317 if (is_null_sid(sid)) {
1318 return NT_STATUS_INVALID_SID;
1321 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1322 return NT_STATUS_INVALID_SID;
1325 /* Try and get a salted cred first. If we can't
1326 fall back to an unsalted cred. */
1328 centry = wcache_fetch(cache, domain, "CRED/%s",
1329 sid_to_fstring(tmp, sid));
1331 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1332 sid_string_dbg(sid)));
1333 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1337 * We don't use the time element at this moment,
1338 * but we have to consume it, so that we don't
1339 * neet to change the disk format of the cache.
1341 (void)centry_time(centry);
1343 /* In the salted case this isn't actually the nt_hash itself,
1344 but the MD5 of the salt + nt_hash. Let the caller
1345 sort this out. It can tell as we only return the cached_salt
1346 if we are returning a salted cred. */
1348 *cached_nt_pass = (const uint8_t *)centry_hash16(centry, mem_ctx);
1349 if (*cached_nt_pass == NULL) {
1352 sid_to_fstring(sidstr, sid);
1354 /* Bad (old) cred cache. Delete and pretend we
1356 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1358 wcache_delete("CRED/%s", sidstr);
1359 centry_free(centry);
1360 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1363 /* We only have 17 bytes more data in the salted cred case. */
1364 if (centry->len - centry->ofs == 17) {
1365 *cached_salt = (const uint8_t *)centry_hash16(centry, mem_ctx);
1367 *cached_salt = NULL;
1370 dump_data_pw("cached_nt_pass", *cached_nt_pass, NT_HASH_LEN);
1372 dump_data_pw("cached_salt", *cached_salt, NT_HASH_LEN);
1375 status = centry->status;
1377 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1378 sid_string_dbg(sid), nt_errstr(status) ));
1380 centry_free(centry);
1384 /* Store creds for a SID - only writes out new salted ones. */
1386 NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
1387 const struct dom_sid *sid,
1388 const uint8_t nt_pass[NT_HASH_LEN])
1390 struct cache_entry *centry;
1393 uint8_t cred_salt[NT_HASH_LEN];
1394 uint8_t salted_hash[NT_HASH_LEN];
1396 if (is_null_sid(sid)) {
1397 return NT_STATUS_INVALID_SID;
1400 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1401 return NT_STATUS_INVALID_SID;
1404 centry = centry_start(domain, NT_STATUS_OK);
1406 return NT_STATUS_INTERNAL_DB_ERROR;
1409 dump_data_pw("nt_pass", nt_pass, NT_HASH_LEN);
1411 centry_put_time(centry, time(NULL));
1413 /* Create a salt and then salt the hash. */
1414 generate_random_buffer(cred_salt, NT_HASH_LEN);
1415 E_md5hash(cred_salt, nt_pass, salted_hash);
1417 centry_put_hash16(centry, salted_hash);
1418 centry_put_hash16(centry, cred_salt);
1419 centry_end(centry, "CRED/%s", sid_to_fstring(sid_string, sid));
1421 DEBUG(10,("wcache_save_creds: %s\n", sid_string));
1423 centry_free(centry);
1425 return NT_STATUS_OK;
1429 /* Query display info. This is the basic user list fn */
1430 NTSTATUS wb_cache_query_user_list(struct winbindd_domain *domain,
1431 TALLOC_CTX *mem_ctx,
1434 struct winbind_cache *cache = get_cache(domain);
1435 struct cache_entry *centry = NULL;
1436 uint32_t num_rids = 0;
1437 uint32_t *rids = NULL;
1439 unsigned int i, retry;
1440 bool old_status = domain->online;
1447 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1452 num_rids = centry_uint32(centry);
1454 if (num_rids == 0) {
1458 rids = talloc_array(mem_ctx, uint32_t, num_rids);
1460 centry_free(centry);
1461 return NT_STATUS_NO_MEMORY;
1464 for (i=0; i<num_rids; i++) {
1465 rids[i] = centry_uint32(centry);
1469 status = centry->status;
1471 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1472 domain->name, nt_errstr(status) ));
1474 centry_free(centry);
1479 /* Return status value returned by seq number check */
1481 if (!NT_STATUS_IS_OK(domain->last_status))
1482 return domain->last_status;
1484 /* Put the query_user_list() in a retry loop. There appears to be
1485 * some bug either with Windows 2000 or Samba's handling of large
1486 * rpc replies. This manifests itself as sudden disconnection
1487 * at a random point in the enumeration of a large (60k) user list.
1488 * The retry loop simply tries the operation again. )-: It's not
1489 * pretty but an acceptable workaround until we work out what the
1490 * real problem is. */
1495 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1499 status = domain->backend->query_user_list(domain, mem_ctx,
1501 num_rids = talloc_array_length(rids);
1503 if (!NT_STATUS_IS_OK(status)) {
1504 DEBUG(3, ("query_user_list: returned 0x%08x, "
1505 "retrying\n", NT_STATUS_V(status)));
1507 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1508 DEBUG(3, ("query_user_list: flushing "
1509 "connection cache\n"));
1510 invalidate_cm_connection(domain);
1512 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1513 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1514 if (!domain->internal && old_status) {
1515 set_domain_offline(domain);
1517 /* store partial response. */
1520 * humm, what about the status used for cache?
1521 * Should it be NT_STATUS_OK?
1526 * domain is offline now, and there is no user entries,
1527 * try to fetch from cache again.
1529 if (cache->tdb && !domain->online && !domain->internal && old_status) {
1530 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1531 /* partial response... */
1535 goto do_fetch_cache;
1542 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
1546 refresh_sequence_number(domain);
1547 if (!NT_STATUS_IS_OK(status)) {
1550 centry = centry_start(domain, status);
1553 centry_put_uint32(centry, num_rids);
1554 for (i=0; i<num_rids; i++) {
1555 centry_put_uint32(centry, rids[i]);
1557 centry_end(centry, "UL/%s", domain->name);
1558 centry_free(centry);
1566 /* list all domain groups */
1567 NTSTATUS wb_cache_enum_dom_groups(struct winbindd_domain *domain,
1568 TALLOC_CTX *mem_ctx,
1569 uint32_t *num_entries,
1570 struct wb_acct_info **info)
1572 struct winbind_cache *cache = get_cache(domain);
1573 struct cache_entry *centry = NULL;
1578 old_status = domain->online;
1582 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1587 *num_entries = centry_uint32(centry);
1589 if (*num_entries == 0)
1592 (*info) = talloc_array(mem_ctx, struct wb_acct_info, *num_entries);
1594 smb_panic_fn("enum_dom_groups out of memory");
1596 for (i=0; i<(*num_entries); i++) {
1597 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1598 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1599 (*info)[i].rid = centry_uint32(centry);
1603 status = centry->status;
1605 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1606 domain->name, nt_errstr(status) ));
1608 centry_free(centry);
1615 /* Return status value returned by seq number check */
1617 if (!NT_STATUS_IS_OK(domain->last_status))
1618 return domain->last_status;
1620 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1623 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1625 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1626 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1627 if (!domain->internal && old_status) {
1628 set_domain_offline(domain);
1632 !domain->internal &&
1634 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1636 goto do_fetch_cache;
1641 refresh_sequence_number(domain);
1642 if (!NT_STATUS_IS_OK(status)) {
1645 centry = centry_start(domain, status);
1648 centry_put_uint32(centry, *num_entries);
1649 for (i=0; i<(*num_entries); i++) {
1650 centry_put_string(centry, (*info)[i].acct_name);
1651 centry_put_string(centry, (*info)[i].acct_desc);
1652 centry_put_uint32(centry, (*info)[i].rid);
1654 centry_end(centry, "GL/%s/domain", domain->name);
1655 centry_free(centry);
1661 /* list all domain groups */
1662 NTSTATUS wb_cache_enum_local_groups(struct winbindd_domain *domain,
1663 TALLOC_CTX *mem_ctx,
1664 uint32_t *num_entries,
1665 struct wb_acct_info **info)
1667 struct winbind_cache *cache = get_cache(domain);
1668 struct cache_entry *centry = NULL;
1673 old_status = domain->online;
1677 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1682 *num_entries = centry_uint32(centry);
1684 if (*num_entries == 0)
1687 (*info) = talloc_array(mem_ctx, struct wb_acct_info, *num_entries);
1689 smb_panic_fn("enum_dom_groups out of memory");
1691 for (i=0; i<(*num_entries); i++) {
1692 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1693 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1694 (*info)[i].rid = centry_uint32(centry);
1699 /* If we are returning cached data and the domain controller
1700 is down then we don't know whether the data is up to date
1701 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1704 if (wcache_server_down(domain)) {
1705 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1706 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1708 status = centry->status;
1710 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1711 domain->name, nt_errstr(status) ));
1713 centry_free(centry);
1720 /* Return status value returned by seq number check */
1722 if (!NT_STATUS_IS_OK(domain->last_status))
1723 return domain->last_status;
1725 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1728 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1730 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1731 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1732 if (!domain->internal && old_status) {
1733 set_domain_offline(domain);
1736 !domain->internal &&
1739 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1741 goto do_fetch_cache;
1746 refresh_sequence_number(domain);
1747 if (!NT_STATUS_IS_OK(status)) {
1750 centry = centry_start(domain, status);
1753 centry_put_uint32(centry, *num_entries);
1754 for (i=0; i<(*num_entries); i++) {
1755 centry_put_string(centry, (*info)[i].acct_name);
1756 centry_put_string(centry, (*info)[i].acct_desc);
1757 centry_put_uint32(centry, (*info)[i].rid);
1759 centry_end(centry, "GL/%s/local", domain->name);
1760 centry_free(centry);
1766 static NTSTATUS wcache_name_to_sid(struct winbindd_domain *domain,
1767 const char *domain_name,
1769 struct dom_sid *sid,
1770 enum lsa_SidType *type)
1772 struct winbind_cache *cache = get_cache(domain);
1773 struct cache_entry *centry;
1777 if (cache->tdb == NULL) {
1778 return NT_STATUS_NOT_FOUND;
1781 uname = talloc_strdup_upper(talloc_tos(), name);
1782 if (uname == NULL) {
1783 return NT_STATUS_NO_MEMORY;
1786 if ((domain_name == NULL) || (domain_name[0] == '\0')) {
1787 domain_name = domain->name;
1790 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1792 if (centry == NULL) {
1793 return NT_STATUS_NOT_FOUND;
1796 status = centry->status;
1797 if (NT_STATUS_IS_OK(status)) {
1798 *type = (enum lsa_SidType)centry_uint32(centry);
1799 centry_sid(centry, sid);
1802 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1803 "%s\n", domain->name, nt_errstr(status) ));
1805 centry_free(centry);
1809 /* convert a single name to a sid in a domain */
1810 NTSTATUS wb_cache_name_to_sid(struct winbindd_domain *domain,
1811 TALLOC_CTX *mem_ctx,
1812 const char *domain_name,
1815 struct dom_sid *sid,
1816 enum lsa_SidType *type)
1821 old_status = domain->online;
1823 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1824 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1830 /* If the seq number check indicated that there is a problem
1831 * with this DC, then return that status... except for
1832 * access_denied. This is special because the dc may be in
1833 * "restrict anonymous = 1" mode, in which case it will deny
1834 * most unauthenticated operations, but *will* allow the LSA
1835 * name-to-sid that we try as a fallback. */
1837 if (!(NT_STATUS_IS_OK(domain->last_status)
1838 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1839 return domain->last_status;
1841 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1844 status = domain->backend->name_to_sid(domain, mem_ctx, domain_name,
1845 name, flags, sid, type);
1847 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1848 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1849 if (!domain->internal && old_status) {
1850 set_domain_offline(domain);
1852 if (!domain->internal &&
1855 NTSTATUS cache_status;
1856 cache_status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1857 return cache_status;
1861 refresh_sequence_number(domain);
1863 if (domain->online &&
1864 (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
1865 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1867 /* Only save the reverse mapping if this was not a UPN */
1868 if (!strchr(name, '@')) {
1869 if (!strupper_m(discard_const_p(char, domain_name))) {
1870 return NT_STATUS_INVALID_PARAMETER;
1872 (void)strlower_m(discard_const_p(char, name));
1873 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1880 static NTSTATUS wcache_sid_to_name(struct winbindd_domain *domain,
1881 const struct dom_sid *sid,
1882 TALLOC_CTX *mem_ctx,
1885 enum lsa_SidType *type)
1887 struct winbind_cache *cache = get_cache(domain);
1888 struct cache_entry *centry;
1892 if (cache->tdb == NULL) {
1893 return NT_STATUS_NOT_FOUND;
1896 sid_string = sid_string_tos(sid);
1897 if (sid_string == NULL) {
1898 return NT_STATUS_NO_MEMORY;
1901 centry = wcache_fetch(cache, domain, "SN/%s", sid_string);
1902 TALLOC_FREE(sid_string);
1903 if (centry == NULL) {
1904 return NT_STATUS_NOT_FOUND;
1907 if (NT_STATUS_IS_OK(centry->status)) {
1908 *type = (enum lsa_SidType)centry_uint32(centry);
1909 *domain_name = centry_string(centry, mem_ctx);
1910 *name = centry_string(centry, mem_ctx);
1913 status = centry->status;
1914 centry_free(centry);
1916 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1917 "%s\n", domain->name, nt_errstr(status) ));
1922 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1924 NTSTATUS wb_cache_sid_to_name(struct winbindd_domain *domain,
1925 TALLOC_CTX *mem_ctx,
1926 const struct dom_sid *sid,
1929 enum lsa_SidType *type)
1934 old_status = domain->online;
1935 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
1937 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1942 *domain_name = NULL;
1944 /* If the seq number check indicated that there is a problem
1945 * with this DC, then return that status... except for
1946 * access_denied. This is special because the dc may be in
1947 * "restrict anonymous = 1" mode, in which case it will deny
1948 * most unauthenticated operations, but *will* allow the LSA
1949 * sid-to-name that we try as a fallback. */
1951 if (!(NT_STATUS_IS_OK(domain->last_status)
1952 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1953 return domain->last_status;
1955 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1958 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1960 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1961 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1962 if (!domain->internal && old_status) {
1963 set_domain_offline(domain);
1965 if (!domain->internal &&
1968 NTSTATUS cache_status;
1969 cache_status = wcache_sid_to_name(domain, sid, mem_ctx,
1970 domain_name, name, type);
1971 return cache_status;
1975 refresh_sequence_number(domain);
1976 if (!NT_STATUS_IS_OK(status)) {
1979 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1981 /* We can't save the name to sid mapping here, as with sid history a
1982 * later name2sid would give the wrong sid. */
1987 NTSTATUS wb_cache_rids_to_names(struct winbindd_domain *domain,
1988 TALLOC_CTX *mem_ctx,
1989 const struct dom_sid *domain_sid,
1994 enum lsa_SidType **types)
1996 struct winbind_cache *cache = get_cache(domain);
1998 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
2003 old_status = domain->online;
2004 *domain_name = NULL;
2012 if (num_rids == 0) {
2013 return NT_STATUS_OK;
2016 *names = talloc_array(mem_ctx, char *, num_rids);
2017 *types = talloc_array(mem_ctx, enum lsa_SidType, num_rids);
2019 if ((*names == NULL) || (*types == NULL)) {
2020 result = NT_STATUS_NO_MEMORY;
2024 have_mapped = have_unmapped = false;
2026 for (i=0; i<num_rids; i++) {
2028 struct cache_entry *centry;
2031 if (!sid_compose(&sid, domain_sid, rids[i])) {
2032 result = NT_STATUS_INTERNAL_ERROR;
2036 centry = wcache_fetch(cache, domain, "SN/%s",
2037 sid_to_fstring(tmp, &sid));
2042 (*types)[i] = SID_NAME_UNKNOWN;
2043 (*names)[i] = talloc_strdup(*names, "");
2045 if (NT_STATUS_IS_OK(centry->status)) {
2048 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
2050 dom = centry_string(centry, mem_ctx);
2051 if (*domain_name == NULL) {
2057 (*names)[i] = centry_string(centry, *names);
2059 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)
2060 || NT_STATUS_EQUAL(centry->status, STATUS_SOME_UNMAPPED)) {
2061 have_unmapped = true;
2064 /* something's definitely wrong */
2065 result = centry->status;
2066 centry_free(centry);
2070 centry_free(centry);
2074 return NT_STATUS_NONE_MAPPED;
2076 if (!have_unmapped) {
2077 return NT_STATUS_OK;
2079 return STATUS_SOME_UNMAPPED;
2083 TALLOC_FREE(*names);
2084 TALLOC_FREE(*types);
2086 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
2087 rids, num_rids, domain_name,
2090 if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
2091 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2092 if (!domain->internal && old_status) {
2093 set_domain_offline(domain);
2096 !domain->internal &&
2099 have_mapped = have_unmapped = false;
2101 *names = talloc_array(mem_ctx, char *, num_rids);
2102 if (*names == NULL) {
2103 result = NT_STATUS_NO_MEMORY;
2107 *types = talloc_array(mem_ctx, enum lsa_SidType,
2109 if (*types == NULL) {
2110 result = NT_STATUS_NO_MEMORY;
2114 for (i=0; i<num_rids; i++) {
2116 struct cache_entry *centry;
2119 if (!sid_compose(&sid, domain_sid, rids[i])) {
2120 result = NT_STATUS_INTERNAL_ERROR;
2124 centry = wcache_fetch(cache, domain, "SN/%s",
2125 sid_to_fstring(tmp, &sid));
2127 (*types)[i] = SID_NAME_UNKNOWN;
2128 (*names)[i] = talloc_strdup(*names, "");
2132 (*types)[i] = SID_NAME_UNKNOWN;
2133 (*names)[i] = talloc_strdup(*names, "");
2135 if (NT_STATUS_IS_OK(centry->status)) {
2138 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
2140 dom = centry_string(centry, mem_ctx);
2141 if (*domain_name == NULL) {
2147 (*names)[i] = centry_string(centry, *names);
2149 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
2150 have_unmapped = true;
2153 /* something's definitely wrong */
2154 result = centry->status;
2155 centry_free(centry);
2159 centry_free(centry);
2163 return NT_STATUS_NONE_MAPPED;
2165 if (!have_unmapped) {
2166 return NT_STATUS_OK;
2168 return STATUS_SOME_UNMAPPED;
2172 None of the queried rids has been found so save all negative entries
2174 if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
2175 for (i = 0; i < num_rids; i++) {
2177 const char *name = "";
2178 const enum lsa_SidType type = SID_NAME_UNKNOWN;
2179 NTSTATUS status = NT_STATUS_NONE_MAPPED;
2181 if (!sid_compose(&sid, domain_sid, rids[i])) {
2182 return NT_STATUS_INTERNAL_ERROR;
2185 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2193 Some or all of the queried rids have been found.
2195 if (!NT_STATUS_IS_OK(result) &&
2196 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
2200 refresh_sequence_number(domain);
2202 for (i=0; i<num_rids; i++) {
2206 if (!sid_compose(&sid, domain_sid, rids[i])) {
2207 result = NT_STATUS_INTERNAL_ERROR;
2211 status = (*types)[i] == SID_NAME_UNKNOWN ?
2212 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
2214 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2215 (*names)[i], (*types)[i]);
2221 TALLOC_FREE(*names);
2222 TALLOC_FREE(*types);
2226 static NTSTATUS wcache_query_user(struct winbindd_domain *domain,
2227 TALLOC_CTX *mem_ctx,
2228 const struct dom_sid *user_sid,
2229 struct wbint_userinfo *info)
2231 struct winbind_cache *cache = get_cache(domain);
2232 struct cache_entry *centry = NULL;
2236 if (cache->tdb == NULL) {
2237 return NT_STATUS_NOT_FOUND;
2240 sid_string = sid_string_tos(user_sid);
2241 if (sid_string == NULL) {
2242 return NT_STATUS_NO_MEMORY;
2245 centry = wcache_fetch(cache, domain, "U/%s", sid_string);
2246 TALLOC_FREE(sid_string);
2247 if (centry == NULL) {
2248 return NT_STATUS_NOT_FOUND;
2252 * If we have an access denied cache entry and a cached info3
2253 * in the samlogon cache then do a query. This will force the
2254 * rpc back end to return the info3 data.
2257 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED) &&
2258 netsamlogon_cache_have(user_sid)) {
2259 DEBUG(10, ("query_user: cached access denied and have cached "
2261 domain->last_status = NT_STATUS_OK;
2262 centry_free(centry);
2263 return NT_STATUS_NOT_FOUND;
2266 /* if status is not ok then this is a negative hit
2267 and the rest of the data doesn't matter */
2268 status = centry->status;
2269 if (NT_STATUS_IS_OK(status)) {
2270 info->domain_name = centry_string(centry, mem_ctx);
2271 info->acct_name = centry_string(centry, mem_ctx);
2272 info->full_name = centry_string(centry, mem_ctx);
2273 info->homedir = centry_string(centry, mem_ctx);
2274 info->shell = centry_string(centry, mem_ctx);
2275 info->uid = centry_uint32(centry);
2276 info->primary_gid = centry_uint32(centry);
2277 info->primary_group_name = centry_string(centry, mem_ctx);
2278 centry_sid(centry, &info->user_sid);
2279 centry_sid(centry, &info->group_sid);
2282 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2283 "%s\n", domain->name, nt_errstr(status) ));
2285 centry_free(centry);
2291 * @brief Query a fullname from the username cache (for further gecos processing)
2293 * @param domain A pointer to the winbindd_domain struct.
2294 * @param mem_ctx The talloc context.
2295 * @param user_sid The user sid.
2296 * @param full_name A pointer to the full_name string.
2298 * @return NTSTATUS code
2300 NTSTATUS wcache_query_user_fullname(struct winbindd_domain *domain,
2301 TALLOC_CTX *mem_ctx,
2302 const struct dom_sid *user_sid,
2303 const char **full_name)
2306 struct wbint_userinfo info;
2308 status = wcache_query_user(domain, mem_ctx, user_sid, &info);
2309 if (!NT_STATUS_IS_OK(status)) {
2313 if (info.full_name != NULL) {
2314 *full_name = talloc_strdup(mem_ctx, info.full_name);
2315 if (*full_name == NULL) {
2316 return NT_STATUS_NO_MEMORY;
2320 return NT_STATUS_OK;
2323 static NTSTATUS wcache_lookup_usergroups(struct winbindd_domain *domain,
2324 TALLOC_CTX *mem_ctx,
2325 const struct dom_sid *user_sid,
2326 uint32_t *pnum_sids,
2327 struct dom_sid **psids)
2329 struct winbind_cache *cache = get_cache(domain);
2330 struct cache_entry *centry = NULL;
2332 uint32_t i, num_sids;
2333 struct dom_sid *sids;
2336 if (cache->tdb == NULL) {
2337 return NT_STATUS_NOT_FOUND;
2340 centry = wcache_fetch(cache, domain, "UG/%s",
2341 sid_to_fstring(sid_string, user_sid));
2342 if (centry == NULL) {
2343 return NT_STATUS_NOT_FOUND;
2346 /* If we have an access denied cache entry and a cached info3 in the
2347 samlogon cache then do a query. This will force the rpc back end
2348 to return the info3 data. */
2350 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)
2351 && netsamlogon_cache_have(user_sid)) {
2352 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2354 domain->last_status = NT_STATUS_OK;
2355 centry_free(centry);
2356 return NT_STATUS_NOT_FOUND;
2359 num_sids = centry_uint32(centry);
2360 sids = talloc_array(mem_ctx, struct dom_sid, num_sids);
2362 centry_free(centry);
2363 return NT_STATUS_NO_MEMORY;
2366 for (i=0; i<num_sids; i++) {
2367 centry_sid(centry, &sids[i]);
2370 status = centry->status;
2372 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2373 "status: %s\n", domain->name, nt_errstr(status)));
2375 centry_free(centry);
2377 *pnum_sids = num_sids;
2382 /* Lookup groups a user is a member of. */
2383 NTSTATUS wb_cache_lookup_usergroups(struct winbindd_domain *domain,
2384 TALLOC_CTX *mem_ctx,
2385 const struct dom_sid *user_sid,
2386 uint32_t *num_groups,
2387 struct dom_sid **user_gids)
2389 struct cache_entry *centry = NULL;
2395 old_status = domain->online;
2396 status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2397 num_groups, user_gids);
2398 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2403 (*user_gids) = NULL;
2405 /* Return status value returned by seq number check */
2407 if (!NT_STATUS_IS_OK(domain->last_status))
2408 return domain->last_status;
2410 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2413 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
2415 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2416 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2417 if (!domain->internal && old_status) {
2418 set_domain_offline(domain);
2420 if (!domain->internal &&
2423 NTSTATUS cache_status;
2424 cache_status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2425 num_groups, user_gids);
2426 return cache_status;
2429 if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
2433 refresh_sequence_number(domain);
2434 if (!NT_STATUS_IS_OK(status)) {
2437 centry = centry_start(domain, status);
2441 centry_put_uint32(centry, *num_groups);
2442 for (i=0; i<(*num_groups); i++) {
2443 centry_put_sid(centry, &(*user_gids)[i]);
2446 centry_end(centry, "UG/%s", sid_to_fstring(sid_string, user_sid));
2447 centry_free(centry);
2453 static char *wcache_make_sidlist(TALLOC_CTX *mem_ctx, uint32_t num_sids,
2454 const struct dom_sid *sids)
2459 sidlist = talloc_strdup(mem_ctx, "");
2460 if (sidlist == NULL) {
2463 for (i=0; i<num_sids; i++) {
2465 sidlist = talloc_asprintf_append_buffer(
2466 sidlist, "/%s", sid_to_fstring(tmp, &sids[i]));
2467 if (sidlist == NULL) {
2474 static NTSTATUS wcache_lookup_useraliases(struct winbindd_domain *domain,
2475 TALLOC_CTX *mem_ctx,
2477 const struct dom_sid *sids,
2478 uint32_t *pnum_aliases,
2479 uint32_t **paliases)
2481 struct winbind_cache *cache = get_cache(domain);
2482 struct cache_entry *centry = NULL;
2483 uint32_t i, num_aliases;
2488 if (cache->tdb == NULL) {
2489 return NT_STATUS_NOT_FOUND;
2492 if (num_sids == 0) {
2495 return NT_STATUS_OK;
2498 /* We need to cache indexed by the whole list of SIDs, the aliases
2499 * resulting might come from any of the SIDs. */
2501 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2502 if (sidlist == NULL) {
2503 return NT_STATUS_NO_MEMORY;
2506 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
2507 TALLOC_FREE(sidlist);
2508 if (centry == NULL) {
2509 return NT_STATUS_NOT_FOUND;
2512 num_aliases = centry_uint32(centry);
2513 aliases = talloc_array(mem_ctx, uint32_t, num_aliases);
2514 if (aliases == NULL) {
2515 centry_free(centry);
2516 return NT_STATUS_NO_MEMORY;
2519 for (i=0; i<num_aliases; i++) {
2520 aliases[i] = centry_uint32(centry);
2523 status = centry->status;
2525 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2526 "status %s\n", domain->name, nt_errstr(status)));
2528 centry_free(centry);
2530 *pnum_aliases = num_aliases;
2531 *paliases = aliases;
2536 NTSTATUS wb_cache_lookup_useraliases(struct winbindd_domain *domain,
2537 TALLOC_CTX *mem_ctx,
2539 const struct dom_sid *sids,
2540 uint32_t *num_aliases,
2541 uint32_t **alias_rids)
2543 struct cache_entry *centry = NULL;
2549 old_status = domain->online;
2550 status = wcache_lookup_useraliases(domain, mem_ctx, num_sids, sids,
2551 num_aliases, alias_rids);
2552 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2557 (*alias_rids) = NULL;
2559 if (!NT_STATUS_IS_OK(domain->last_status))
2560 return domain->last_status;
2562 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2563 "for domain %s\n", domain->name ));
2565 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2566 if (sidlist == NULL) {
2567 return NT_STATUS_NO_MEMORY;
2570 status = domain->backend->lookup_useraliases(domain, mem_ctx,
2572 num_aliases, alias_rids);
2574 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2575 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2576 if (!domain->internal && old_status) {
2577 set_domain_offline(domain);
2579 if (!domain->internal &&
2582 NTSTATUS cache_status;
2583 cache_status = wcache_lookup_useraliases(domain, mem_ctx, num_sids,
2584 sids, num_aliases, alias_rids);
2585 return cache_status;
2589 refresh_sequence_number(domain);
2590 if (!NT_STATUS_IS_OK(status)) {
2593 centry = centry_start(domain, status);
2596 centry_put_uint32(centry, *num_aliases);
2597 for (i=0; i<(*num_aliases); i++)
2598 centry_put_uint32(centry, (*alias_rids)[i]);
2599 centry_end(centry, "UA%s", sidlist);
2600 centry_free(centry);
2606 static NTSTATUS wcache_lookup_groupmem(struct winbindd_domain *domain,
2607 TALLOC_CTX *mem_ctx,
2608 const struct dom_sid *group_sid,
2609 uint32_t *num_names,
2610 struct dom_sid **sid_mem, char ***names,
2611 uint32_t **name_types)
2613 struct winbind_cache *cache = get_cache(domain);
2614 struct cache_entry *centry = NULL;
2619 if (cache->tdb == NULL) {
2620 return NT_STATUS_NOT_FOUND;
2623 sid_string = sid_string_tos(group_sid);
2624 if (sid_string == NULL) {
2625 return NT_STATUS_NO_MEMORY;
2628 centry = wcache_fetch(cache, domain, "GM/%s", sid_string);
2629 TALLOC_FREE(sid_string);
2630 if (centry == NULL) {
2631 return NT_STATUS_NOT_FOUND;
2638 *num_names = centry_uint32(centry);
2639 if (*num_names == 0) {
2640 centry_free(centry);
2641 return NT_STATUS_OK;
2644 *sid_mem = talloc_array(mem_ctx, struct dom_sid, *num_names);
2645 *names = talloc_array(mem_ctx, char *, *num_names);
2646 *name_types = talloc_array(mem_ctx, uint32_t, *num_names);
2648 if ((*sid_mem == NULL) || (*names == NULL) || (*name_types == NULL)) {
2649 TALLOC_FREE(*sid_mem);
2650 TALLOC_FREE(*names);
2651 TALLOC_FREE(*name_types);
2652 centry_free(centry);
2653 return NT_STATUS_NO_MEMORY;
2656 for (i=0; i<(*num_names); i++) {
2657 centry_sid(centry, &(*sid_mem)[i]);
2658 (*names)[i] = centry_string(centry, mem_ctx);
2659 (*name_types)[i] = centry_uint32(centry);
2662 status = centry->status;
2664 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2665 "status: %s\n", domain->name, nt_errstr(status)));
2667 centry_free(centry);
2671 NTSTATUS wb_cache_lookup_groupmem(struct winbindd_domain *domain,
2672 TALLOC_CTX *mem_ctx,
2673 const struct dom_sid *group_sid,
2674 enum lsa_SidType type,
2675 uint32_t *num_names,
2676 struct dom_sid **sid_mem,
2678 uint32_t **name_types)
2680 struct cache_entry *centry = NULL;
2686 old_status = domain->online;
2687 status = wcache_lookup_groupmem(domain, mem_ctx, group_sid, num_names,
2688 sid_mem, names, name_types);
2689 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2696 (*name_types) = NULL;
2698 /* Return status value returned by seq number check */
2700 if (!NT_STATUS_IS_OK(domain->last_status))
2701 return domain->last_status;
2703 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2706 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid,
2708 sid_mem, names, name_types);
2710 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2711 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2712 if (!domain->internal && old_status) {
2713 set_domain_offline(domain);
2715 if (!domain->internal &&
2718 NTSTATUS cache_status;
2719 cache_status = wcache_lookup_groupmem(domain, mem_ctx, group_sid,
2720 num_names, sid_mem, names,
2722 return cache_status;
2726 refresh_sequence_number(domain);
2727 if (!NT_STATUS_IS_OK(status)) {
2730 centry = centry_start(domain, status);
2733 centry_put_uint32(centry, *num_names);
2734 for (i=0; i<(*num_names); i++) {
2735 centry_put_sid(centry, &(*sid_mem)[i]);
2736 centry_put_string(centry, (*names)[i]);
2737 centry_put_uint32(centry, (*name_types)[i]);
2739 centry_end(centry, "GM/%s", sid_to_fstring(sid_string, group_sid));
2740 centry_free(centry);
2746 /* find the sequence number for a domain */
2747 NTSTATUS wb_cache_sequence_number(struct winbindd_domain *domain,
2750 refresh_sequence_number(domain);
2752 *seq = domain->sequence_number;
2754 return NT_STATUS_OK;
2757 /* enumerate trusted domains
2758 * (we need to have the list of trustdoms in the cache when we go offline) -
2760 NTSTATUS wb_cache_trusted_domains(struct winbindd_domain *domain,
2761 TALLOC_CTX *mem_ctx,
2762 struct netr_DomainTrustList *trusts)
2765 struct winbind_cache *cache;
2766 struct winbindd_tdc_domain *dom_list = NULL;
2767 size_t num_domains = 0;
2768 bool retval = false;
2772 old_status = domain->online;
2774 trusts->array = NULL;
2776 cache = get_cache(domain);
2777 if (!cache || !cache->tdb) {
2781 if (domain->online) {
2785 retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2786 if (!retval || !num_domains || !dom_list) {
2787 TALLOC_FREE(dom_list);
2792 trusts->array = talloc_zero_array(mem_ctx, struct netr_DomainTrust, num_domains);
2793 if (!trusts->array) {
2794 TALLOC_FREE(dom_list);
2795 return NT_STATUS_NO_MEMORY;
2798 for (i = 0; i < num_domains; i++) {
2799 struct netr_DomainTrust *trust;
2800 struct dom_sid *sid;
2801 struct winbindd_domain *dom;
2803 dom = find_domain_from_name_noinit(dom_list[i].domain_name);
2804 if (dom && dom->internal) {
2808 trust = &trusts->array[trusts->count];
2809 trust->netbios_name = talloc_strdup(trusts->array, dom_list[i].domain_name);
2810 trust->dns_name = talloc_strdup(trusts->array, dom_list[i].dns_name);
2811 sid = talloc(trusts->array, struct dom_sid);
2812 if (!trust->netbios_name || !trust->dns_name ||
2814 TALLOC_FREE(dom_list);
2815 TALLOC_FREE(trusts->array);
2816 return NT_STATUS_NO_MEMORY;
2819 trust->trust_flags = dom_list[i].trust_flags;
2820 trust->trust_attributes = dom_list[i].trust_attribs;
2821 trust->trust_type = dom_list[i].trust_type;
2822 sid_copy(sid, &dom_list[i].sid);
2827 TALLOC_FREE(dom_list);
2828 return NT_STATUS_OK;
2831 /* Return status value returned by seq number check */
2833 if (!NT_STATUS_IS_OK(domain->last_status))
2834 return domain->last_status;
2836 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2839 status = domain->backend->trusted_domains(domain, mem_ctx, trusts);
2841 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2842 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2843 if (!domain->internal && old_status) {
2844 set_domain_offline(domain);
2846 if (!domain->internal &&
2849 retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2850 if (retval && num_domains && dom_list) {
2851 TALLOC_FREE(trusts->array);
2853 goto do_fetch_cache;
2857 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2858 * so that the generic centry handling still applies correctly -
2861 if (!NT_STATUS_IS_ERR(status)) {
2862 status = NT_STATUS_OK;
2867 /* get lockout policy */
2868 NTSTATUS wb_cache_lockout_policy(struct winbindd_domain *domain,
2869 TALLOC_CTX *mem_ctx,
2870 struct samr_DomInfo12 *policy)
2872 struct winbind_cache *cache = get_cache(domain);
2873 struct cache_entry *centry = NULL;
2877 old_status = domain->online;
2881 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2887 policy->lockout_duration = centry_nttime(centry);
2888 policy->lockout_window = centry_nttime(centry);
2889 policy->lockout_threshold = centry_uint16(centry);
2891 status = centry->status;
2893 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2894 domain->name, nt_errstr(status) ));
2896 centry_free(centry);
2900 ZERO_STRUCTP(policy);
2902 /* Return status value returned by seq number check */
2904 if (!NT_STATUS_IS_OK(domain->last_status))
2905 return domain->last_status;
2907 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2910 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2912 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2913 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2914 if (!domain->internal && old_status) {
2915 set_domain_offline(domain);
2918 !domain->internal &&
2921 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2923 goto do_fetch_cache;
2928 refresh_sequence_number(domain);
2929 if (!NT_STATUS_IS_OK(status)) {
2932 wcache_save_lockout_policy(domain, status, policy);
2937 /* get password policy */
2938 NTSTATUS wb_cache_password_policy(struct winbindd_domain *domain,
2939 TALLOC_CTX *mem_ctx,
2940 struct samr_DomInfo1 *policy)
2942 struct winbind_cache *cache = get_cache(domain);
2943 struct cache_entry *centry = NULL;
2947 old_status = domain->online;
2951 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2957 policy->min_password_length = centry_uint16(centry);
2958 policy->password_history_length = centry_uint16(centry);
2959 policy->password_properties = centry_uint32(centry);
2960 policy->max_password_age = centry_nttime(centry);
2961 policy->min_password_age = centry_nttime(centry);
2963 status = centry->status;
2965 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2966 domain->name, nt_errstr(status) ));
2968 centry_free(centry);
2972 ZERO_STRUCTP(policy);
2974 /* Return status value returned by seq number check */
2976 if (!NT_STATUS_IS_OK(domain->last_status))
2977 return domain->last_status;
2979 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2982 status = domain->backend->password_policy(domain, mem_ctx, policy);
2984 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2985 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2986 if (!domain->internal && old_status) {
2987 set_domain_offline(domain);
2990 !domain->internal &&
2993 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2995 goto do_fetch_cache;
3000 refresh_sequence_number(domain);
3001 if (!NT_STATUS_IS_OK(status)) {
3004 wcache_save_password_policy(domain, status, policy);
3010 /* Invalidate cached user and group lists coherently */
3012 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3015 if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
3016 strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
3017 tdb_delete(the_tdb, kbuf);
3022 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3024 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
3025 const struct dom_sid *sid)
3027 fstring key_str, sid_string;
3028 struct winbind_cache *cache;
3030 /* don't clear cached U/SID and UG/SID entries when we want to logon
3033 if (lp_winbind_offline_logon()) {
3040 cache = get_cache(domain);
3046 /* Clear U/SID cache entry */
3047 fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, sid));
3048 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
3049 tdb_delete(cache->tdb, string_tdb_data(key_str));
3051 /* Clear UG/SID cache entry */
3052 fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, sid));
3053 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
3054 tdb_delete(cache->tdb, string_tdb_data(key_str));
3056 /* Samba/winbindd never needs this. */
3057 netsamlogon_clear_cached_user(sid);
3060 bool wcache_invalidate_cache(void)
3062 struct winbindd_domain *domain;
3064 for (domain = domain_list(); domain; domain = domain->next) {
3065 struct winbind_cache *cache = get_cache(domain);
3067 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3068 "entries for %s\n", domain->name));
3071 tdb_traverse(cache->tdb, traverse_fn, NULL);
3080 bool wcache_invalidate_cache_noinit(void)
3082 struct winbindd_domain *domain;
3084 for (domain = domain_list(); domain; domain = domain->next) {
3085 struct winbind_cache *cache;
3087 /* Skip uninitialized domains. */
3088 if (!domain->initialized && !domain->internal) {
3092 cache = get_cache(domain);
3094 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3095 "entries for %s\n", domain->name));
3098 tdb_traverse(cache->tdb, traverse_fn, NULL);
3100 * Flushing cache has nothing to with domains.
3101 * return here if we successfully flushed once.
3102 * To avoid unnecessary traversing the cache.
3113 static bool init_wcache(void)
3117 if (wcache == NULL) {
3118 wcache = SMB_XMALLOC_P(struct winbind_cache);
3119 ZERO_STRUCTP(wcache);
3122 if (wcache->tdb != NULL)
3125 db_path = wcache_path();
3126 if (db_path == NULL) {
3130 /* when working offline we must not clear the cache on restart */
3131 wcache->tdb = tdb_open_log(db_path,
3132 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3133 TDB_INCOMPATIBLE_HASH |
3134 (lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
3135 O_RDWR|O_CREAT, 0600);
3136 TALLOC_FREE(db_path);
3137 if (wcache->tdb == NULL) {
3138 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3145 /************************************************************************
3146 This is called by the parent to initialize the cache file.
3147 We don't need sophisticated locking here as we know we're the
3149 ************************************************************************/
3151 bool initialize_winbindd_cache(void)
3153 bool cache_bad = true;
3156 if (!init_wcache()) {
3157 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3161 /* Check version number. */
3162 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
3163 vers == WINBINDD_CACHE_VERSION) {
3170 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3171 "and re-creating with version number %d\n",
3172 WINBINDD_CACHE_VERSION ));
3174 tdb_close(wcache->tdb);
3177 db_path = wcache_path();
3178 if (db_path == NULL) {
3182 if (unlink(db_path) == -1) {
3183 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3186 TALLOC_FREE(db_path);
3189 TALLOC_FREE(db_path);
3190 if (!init_wcache()) {
3191 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3192 "init_wcache failed.\n"));
3196 /* Write the version. */
3197 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
3198 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3199 tdb_errorstr(wcache->tdb) ));
3204 tdb_close(wcache->tdb);
3209 void close_winbindd_cache(void)
3215 tdb_close(wcache->tdb);
3220 bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
3221 char **domain_name, char **name,
3222 enum lsa_SidType *type)
3224 struct winbindd_domain *domain;
3227 domain = find_lookup_domain_from_sid(sid);
3228 if (domain == NULL) {
3231 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
3233 return NT_STATUS_IS_OK(status);
3236 bool lookup_cached_name(const char *domain_name,
3238 struct dom_sid *sid,
3239 enum lsa_SidType *type)
3241 struct winbindd_domain *domain;
3243 bool original_online_state;
3245 domain = find_lookup_domain_from_name(domain_name);
3246 if (domain == NULL) {
3250 /* If we are doing a cached logon, temporarily set the domain
3251 offline so the cache won't expire the entry */
3253 original_online_state = domain->online;
3254 domain->online = false;
3255 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
3256 domain->online = original_online_state;
3258 return NT_STATUS_IS_OK(status);
3262 * Cache a name to sid without checking the sequence number.
3263 * Used when caching from a trusted PAC.
3266 void cache_name2sid_trusted(struct winbindd_domain *domain,
3267 const char *domain_name,
3269 enum lsa_SidType type,
3270 const struct dom_sid *sid)
3273 * Ensure we store the mapping with the
3274 * existing sequence number from the cache.
3277 (void)fetch_cache_seqnum(domain, time(NULL));
3278 wcache_save_name_to_sid(domain,
3286 void cache_name2sid(struct winbindd_domain *domain,
3287 const char *domain_name, const char *name,
3288 enum lsa_SidType type, const struct dom_sid *sid)
3290 refresh_sequence_number(domain);
3291 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
3296 * The original idea that this cache only contains centries has
3297 * been blurred - now other stuff gets put in here. Ensure we
3298 * ignore these things on cleanup.
3301 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
3302 TDB_DATA dbuf, void *state)
3304 struct cache_entry *centry;
3306 if (is_non_centry_key(kbuf)) {
3310 centry = wcache_fetch_raw((char *)kbuf.dptr);
3315 if (!NT_STATUS_IS_OK(centry->status)) {
3316 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
3317 tdb_delete(the_tdb, kbuf);
3320 centry_free(centry);
3324 /* flush the cache */
3325 static void wcache_flush_cache(void)
3332 tdb_close(wcache->tdb);
3335 if (!winbindd_use_cache()) {
3339 db_path = wcache_path();
3340 if (db_path == NULL) {
3344 /* when working offline we must not clear the cache on restart */
3345 wcache->tdb = tdb_open_log(db_path,
3346 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3347 TDB_INCOMPATIBLE_HASH |
3348 (lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
3349 O_RDWR|O_CREAT, 0600);
3350 TALLOC_FREE(db_path);
3352 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3356 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
3358 DEBUG(10,("wcache_flush_cache success\n"));
3361 /* Count cached creds */
3363 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3366 int *cred_count = (int*)state;
3368 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3374 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
3376 struct winbind_cache *cache = get_cache(domain);
3381 return NT_STATUS_INTERNAL_DB_ERROR;
3384 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
3386 return NT_STATUS_OK;
3390 struct cred_list *prev, *next;
3395 static struct cred_list *wcache_cred_list;
3397 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3400 struct cred_list *cred;
3402 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3404 cred = SMB_MALLOC_P(struct cred_list);
3406 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3412 /* save a copy of the key */
3414 fstrcpy(cred->name, (const char *)kbuf.dptr);
3415 DLIST_ADD(wcache_cred_list, cred);
3421 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const struct dom_sid *sid)
3423 struct winbind_cache *cache = get_cache(domain);
3426 struct cred_list *cred, *next, *oldest = NULL;
3429 return NT_STATUS_INTERNAL_DB_ERROR;
3432 /* we possibly already have an entry */
3433 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
3435 fstring key_str, tmp;
3437 DEBUG(11,("we already have an entry, deleting that\n"));
3439 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
3441 tdb_delete(cache->tdb, string_tdb_data(key_str));
3443 return NT_STATUS_OK;
3446 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
3448 return NT_STATUS_OK;
3449 } else if ((ret < 0) || (wcache_cred_list == NULL)) {
3450 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3453 ZERO_STRUCTP(oldest);
3455 for (cred = wcache_cred_list; cred; cred = cred->next) {
3460 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
3462 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3464 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
3468 t = IVAL(data.dptr, 0);
3469 SAFE_FREE(data.dptr);
3472 oldest = SMB_MALLOC_P(struct cred_list);
3473 if (oldest == NULL) {
3474 status = NT_STATUS_NO_MEMORY;
3478 fstrcpy(oldest->name, cred->name);
3479 oldest->created = t;
3483 if (t < oldest->created) {
3484 fstrcpy(oldest->name, cred->name);
3485 oldest->created = t;
3489 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
3490 status = NT_STATUS_OK;
3492 status = NT_STATUS_UNSUCCESSFUL;
3495 for (cred = wcache_cred_list; cred; cred = next) {
3497 DLIST_REMOVE(wcache_cred_list, cred);
3505 /* Change the global online/offline state. */
3506 bool set_global_winbindd_state_offline(void)
3510 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3512 /* Only go offline if someone has created
3513 the key "WINBINDD_OFFLINE" in the cache tdb. */
3515 if (wcache == NULL || wcache->tdb == NULL) {
3516 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3520 if (!lp_winbind_offline_logon()) {
3521 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3525 if (global_winbindd_offline_state) {
3526 /* Already offline. */
3530 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
3532 if (!data.dptr || data.dsize != 4) {
3533 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3534 SAFE_FREE(data.dptr);
3537 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3538 global_winbindd_offline_state = true;
3539 SAFE_FREE(data.dptr);
3544 void set_global_winbindd_state_online(void)
3546 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3548 if (!lp_winbind_offline_logon()) {
3549 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3553 if (!global_winbindd_offline_state) {
3554 /* Already online. */
3557 global_winbindd_offline_state = false;
3563 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3564 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
3567 bool get_global_winbindd_state_offline(void)
3569 return global_winbindd_offline_state;
3572 /***********************************************************************
3573 Validate functions for all possible cache tdb keys.
3574 ***********************************************************************/
3576 static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
3577 struct tdb_validation_status *state)
3579 struct cache_entry *centry;
3581 centry = SMB_XMALLOC_P(struct cache_entry);
3582 centry->data = (unsigned char *)smb_memdup(data.dptr, data.dsize);
3583 if (!centry->data) {
3587 centry->len = data.dsize;
3590 if (centry->len < 16) {
3591 /* huh? corrupt cache? */
3592 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3593 "(len < 16) ?\n", kstr));
3594 centry_free(centry);
3595 state->bad_entry = true;
3596 state->success = false;
3600 centry->status = NT_STATUS(centry_uint32(centry));
3601 centry->sequence_number = centry_uint32(centry);
3602 centry->timeout = centry_uint64_t(centry);
3606 static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3607 struct tdb_validation_status *state)
3609 if (dbuf.dsize != 8) {
3610 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3611 keystr, (unsigned int)dbuf.dsize ));
3612 state->bad_entry = true;
3618 static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3619 struct tdb_validation_status *state)
3621 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3626 (void)centry_uint32(centry);
3627 if (NT_STATUS_IS_OK(centry->status)) {
3629 (void)centry_sid(centry, &sid);
3632 centry_free(centry);
3634 if (!(state->success)) {
3637 DEBUG(10,("validate_ns: %s ok\n", keystr));
3641 static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3642 struct tdb_validation_status *state)
3644 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3649 if (NT_STATUS_IS_OK(centry->status)) {
3650 (void)centry_uint32(centry);
3651 (void)centry_string(centry, mem_ctx);
3652 (void)centry_string(centry, mem_ctx);
3655 centry_free(centry);
3657 if (!(state->success)) {
3660 DEBUG(10,("validate_sn: %s ok\n", keystr));
3664 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3665 struct tdb_validation_status *state)
3667 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3674 (void)centry_string(centry, mem_ctx);
3675 (void)centry_string(centry, mem_ctx);
3676 (void)centry_string(centry, mem_ctx);
3677 (void)centry_string(centry, mem_ctx);
3678 (void)centry_string(centry, mem_ctx);
3679 (void)centry_uint32(centry);
3680 (void)centry_uint32(centry);
3681 (void)centry_string(centry, mem_ctx);
3682 (void)centry_sid(centry, &sid);
3683 (void)centry_sid(centry, &sid);
3685 centry_free(centry);
3687 if (!(state->success)) {
3690 DEBUG(10,("validate_u: %s ok\n", keystr));
3694 static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3695 struct tdb_validation_status *state)
3697 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3703 (void)centry_nttime(centry);
3704 (void)centry_nttime(centry);
3705 (void)centry_uint16(centry);
3707 centry_free(centry);
3709 if (!(state->success)) {
3712 DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
3716 static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3717 struct tdb_validation_status *state)
3719 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3725 (void)centry_uint16(centry);
3726 (void)centry_uint16(centry);
3727 (void)centry_uint32(centry);
3728 (void)centry_nttime(centry);
3729 (void)centry_nttime(centry);
3731 centry_free(centry);
3733 if (!(state->success)) {
3736 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
3740 static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3741 struct tdb_validation_status *state)
3743 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3749 (void)centry_time(centry);
3750 (void)centry_hash16(centry, mem_ctx);
3752 /* We only have 17 bytes more data in the salted cred case. */
3753 if (centry->len - centry->ofs == 17) {
3754 (void)centry_hash16(centry, mem_ctx);
3757 centry_free(centry);
3759 if (!(state->success)) {
3762 DEBUG(10,("validate_cred: %s ok\n", keystr));
3766 static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3767 struct tdb_validation_status *state)
3769 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3770 int32_t num_entries, i;
3776 num_entries = (int32_t)centry_uint32(centry);
3778 for (i=0; i< num_entries; i++) {
3779 (void)centry_uint32(centry);
3782 centry_free(centry);
3784 if (!(state->success)) {
3787 DEBUG(10,("validate_ul: %s ok\n", keystr));
3791 static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3792 struct tdb_validation_status *state)
3794 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3795 int32_t num_entries, i;
3801 num_entries = centry_uint32(centry);
3803 for (i=0; i< num_entries; i++) {
3804 (void)centry_string(centry, mem_ctx);
3805 (void)centry_string(centry, mem_ctx);
3806 (void)centry_uint32(centry);
3809 centry_free(centry);
3811 if (!(state->success)) {
3814 DEBUG(10,("validate_gl: %s ok\n", keystr));
3818 static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3819 struct tdb_validation_status *state)
3821 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3822 int32_t num_groups, i;
3828 num_groups = centry_uint32(centry);
3830 for (i=0; i< num_groups; i++) {
3832 centry_sid(centry, &sid);
3835 centry_free(centry);
3837 if (!(state->success)) {
3840 DEBUG(10,("validate_ug: %s ok\n", keystr));
3844 static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3845 struct tdb_validation_status *state)
3847 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3848 int32_t num_aliases, i;
3854 num_aliases = centry_uint32(centry);
3856 for (i=0; i < num_aliases; i++) {
3857 (void)centry_uint32(centry);
3860 centry_free(centry);
3862 if (!(state->success)) {
3865 DEBUG(10,("validate_ua: %s ok\n", keystr));
3869 static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3870 struct tdb_validation_status *state)
3872 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3873 int32_t num_names, i;
3879 num_names = centry_uint32(centry);
3881 for (i=0; i< num_names; i++) {
3883 centry_sid(centry, &sid);
3884 (void)centry_string(centry, mem_ctx);
3885 (void)centry_uint32(centry);
3888 centry_free(centry);
3890 if (!(state->success)) {
3893 DEBUG(10,("validate_gm: %s ok\n", keystr));
3897 static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3898 struct tdb_validation_status *state)
3900 /* Can't say anything about this other than must be nonzero. */
3901 if (dbuf.dsize == 0) {
3902 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3904 state->bad_entry = true;
3905 state->success = false;
3909 DEBUG(10,("validate_dr: %s ok\n", keystr));
3913 static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3914 struct tdb_validation_status *state)
3916 /* Can't say anything about this other than must be nonzero. */
3917 if (dbuf.dsize == 0) {
3918 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3920 state->bad_entry = true;
3921 state->success = false;
3925 DEBUG(10,("validate_de: %s ok\n", keystr));
3929 static int validate_nss_an(TALLOC_CTX *mem_ctx, const char *keystr,
3931 struct tdb_validation_status *state)
3933 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3939 (void)centry_string( centry, mem_ctx );
3941 centry_free(centry);
3943 if (!(state->success)) {
3946 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3950 static int validate_nss_na(TALLOC_CTX *mem_ctx, const char *keystr,
3952 struct tdb_validation_status *state)
3954 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3960 (void)centry_string( centry, mem_ctx );
3962 centry_free(centry);
3964 if (!(state->success)) {
3967 DBG_DEBUG("%s ok\n", keystr);
3971 static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
3973 struct tdb_validation_status *state)
3975 if (dbuf.dsize == 0) {
3976 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3977 "key %s (len ==0) ?\n", keystr));
3978 state->bad_entry = true;
3979 state->success = false;
3983 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
3984 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3988 static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3989 struct tdb_validation_status *state)
3991 if (dbuf.dsize != 4) {
3992 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3993 keystr, (unsigned int)dbuf.dsize ));
3994 state->bad_entry = true;
3995 state->success = false;
3998 DEBUG(10,("validate_offline: %s ok\n", keystr));
4002 static int validate_ndr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
4003 struct tdb_validation_status *state)
4006 * Ignore validation for now. The proper way to do this is with a
4007 * checksum. Just pure parsing does not really catch much.
4012 static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
4013 struct tdb_validation_status *state)
4015 if (dbuf.dsize != 4) {
4016 DEBUG(0, ("validate_cache_version: Corrupt cache for "
4017 "key %s (len %u != 4) ?\n",
4018 keystr, (unsigned int)dbuf.dsize));
4019 state->bad_entry = true;
4020 state->success = false;
4024 DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
4028 /***********************************************************************
4029 A list of all possible cache tdb keys with associated validation
4031 ***********************************************************************/
4033 struct key_val_struct {
4034 const char *keyname;
4035 int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
4037 {"SEQNUM/", validate_seqnum},
4038 {"NS/", validate_ns},
4039 {"SN/", validate_sn},
4041 {"LOC_POL/", validate_loc_pol},
4042 {"PWD_POL/", validate_pwd_pol},
4043 {"CRED/", validate_cred},
4044 {"UL/", validate_ul},
4045 {"GL/", validate_gl},
4046 {"UG/", validate_ug},
4047 {"UA", validate_ua},
4048 {"GM/", validate_gm},
4049 {"DR/", validate_dr},
4050 {"DE/", validate_de},
4051 {"TRUSTDOMCACHE/", validate_trustdomcache},
4052 {"NSS/NA/", validate_nss_na},
4053 {"NSS/AN/", validate_nss_an},
4054 {"WINBINDD_OFFLINE", validate_offline},
4055 {"NDR/", validate_ndr},
4056 {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
4060 /***********************************************************************
4061 Function to look at every entry in the tdb and validate it as far as
4063 ***********************************************************************/
4065 static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
4068 unsigned int max_key_len = 1024;
4069 struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
4071 /* Paranoia check. */
4072 if (strncmp("UA/", (const char *)kbuf.dptr, 3) == 0 ||
4073 strncmp("NDR/", (const char *)kbuf.dptr, 4) == 0) {
4074 max_key_len = 1024 * 1024;
4076 if (kbuf.dsize > max_key_len) {
4077 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4079 (unsigned int)kbuf.dsize, (unsigned int)max_key_len));
4083 for (i = 0; key_val[i].keyname; i++) {
4084 size_t namelen = strlen(key_val[i].keyname);
4085 if (kbuf.dsize >= namelen && (
4086 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
4087 TALLOC_CTX *mem_ctx;
4091 keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
4095 memcpy(keystr, kbuf.dptr, kbuf.dsize);
4096 keystr[kbuf.dsize] = '\0';
4098 mem_ctx = talloc_init("validate_ctx");
4104 ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
4108 talloc_destroy(mem_ctx);
4113 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4114 dump_data(0, (uint8_t *)kbuf.dptr, kbuf.dsize);
4115 DEBUG(0,("data :\n"));
4116 dump_data(0, (uint8_t *)dbuf.dptr, dbuf.dsize);
4117 v_state->unknown_key = true;
4118 v_state->success = false;
4119 return 1; /* terminate. */
4122 static void validate_panic(const char *const why)
4124 DEBUG(0,("validating cache: would panic %s\n", why ));
4125 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4129 static int wbcache_update_centry_fn(TDB_CONTEXT *tdb,
4137 if (is_non_centry_key(key)) {
4141 if (data.dptr == NULL || data.dsize == 0) {
4142 if (tdb_delete(tdb, key) < 0) {
4143 DEBUG(0, ("tdb_delete for [%s] failed!\n",
4149 /* add timeout to blob (uint64_t) */
4150 blob.dsize = data.dsize + 8;
4152 blob.dptr = SMB_XMALLOC_ARRAY(uint8_t, blob.dsize);
4153 if (blob.dptr == NULL) {
4156 memset(blob.dptr, 0, blob.dsize);
4158 /* copy status and seqnum */
4159 memcpy(blob.dptr, data.dptr, 8);
4162 ctimeout = lp_winbind_cache_time() + time(NULL);
4163 SBVAL(blob.dptr, 8, ctimeout);
4166 memcpy(blob.dptr + 16, data.dptr + 8, data.dsize - 8);
4168 if (tdb_store(tdb, key, blob, TDB_REPLACE) < 0) {
4169 DEBUG(0, ("tdb_store to update [%s] failed!\n",
4171 SAFE_FREE(blob.dptr);
4175 SAFE_FREE(blob.dptr);
4179 static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT *tdb)
4183 DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
4185 rc = tdb_traverse(tdb, wbcache_update_centry_fn, NULL);
4193 /***********************************************************************
4194 Try and validate every entry in the winbindd cache. If we fail here,
4195 delete the cache tdb and return non-zero.
4196 ***********************************************************************/
4198 int winbindd_validate_cache(void)
4201 char *tdb_path = NULL;
4202 TDB_CONTEXT *tdb = NULL;
4206 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4207 smb_panic_fn = validate_panic;
4209 tdb_path = wcache_path();
4210 if (tdb_path == NULL) {
4214 tdb = tdb_open_log(tdb_path,
4215 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
4216 TDB_INCOMPATIBLE_HASH |
4217 ( lp_winbind_offline_logon()
4219 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
4223 DEBUG(0, ("winbindd_validate_cache: "
4224 "error opening/initializing tdb\n"));
4228 /* Version check and upgrade code. */
4229 if (!tdb_fetch_uint32(tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers_id)) {
4230 DEBUG(10, ("Fresh database\n"));
4231 tdb_store_uint32(tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION);
4232 vers_id = WINBINDD_CACHE_VERSION;
4235 if (vers_id != WINBINDD_CACHE_VERSION) {
4236 if (vers_id == WINBINDD_CACHE_VER1) {
4237 ok = wbcache_upgrade_v1_to_v2(tdb);
4239 DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
4244 tdb_store_uint32(tdb,
4245 WINBINDD_CACHE_VERSION_KEYSTR,
4246 WINBINDD_CACHE_VERSION);
4247 vers_id = WINBINDD_CACHE_VER2;
4253 ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
4256 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4257 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
4262 TALLOC_FREE(tdb_path);
4263 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4264 smb_panic_fn = smb_panic;
4268 /***********************************************************************
4269 Try and validate every entry in the winbindd cache.
4270 ***********************************************************************/
4272 int winbindd_validate_cache_nobackup(void)
4277 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4278 smb_panic_fn = validate_panic;
4280 tdb_path = wcache_path();
4281 if (tdb_path == NULL) {
4282 goto err_panic_restore;
4285 if (wcache == NULL || wcache->tdb == NULL) {
4286 ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
4288 ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
4292 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4296 TALLOC_FREE(tdb_path);
4298 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4300 smb_panic_fn = smb_panic;
4304 bool winbindd_cache_validate_and_initialize(void)
4306 close_winbindd_cache();
4308 if (lp_winbind_offline_logon()) {
4309 if (winbindd_validate_cache() < 0) {
4310 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4311 "could be restored.\n"));
4315 return initialize_winbindd_cache();
4318 /*********************************************************************
4319 ********************************************************************/
4321 static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
4322 struct winbindd_tdc_domain **domains,
4323 size_t *num_domains )
4325 struct winbindd_tdc_domain *list = NULL;
4327 bool set_only = false;
4329 /* don't allow duplicates */
4334 for ( i=0; i< (*num_domains); i++ ) {
4335 if ( strequal( new_dom->name, list[i].domain_name ) ) {
4336 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4347 list = talloc_array( NULL, struct winbindd_tdc_domain, 1 );
4350 list = talloc_realloc( *domains, *domains,
4351 struct winbindd_tdc_domain,
4356 ZERO_STRUCT( list[idx] );
4362 list[idx].domain_name = talloc_strdup(list, new_dom->name);
4363 if (list[idx].domain_name == NULL) {
4366 if (new_dom->alt_name != NULL) {
4367 list[idx].dns_name = talloc_strdup(list, new_dom->alt_name);
4368 if (list[idx].dns_name == NULL) {
4373 if ( !is_null_sid( &new_dom->sid ) ) {
4374 sid_copy( &list[idx].sid, &new_dom->sid );
4376 sid_copy(&list[idx].sid, &global_sid_NULL);
4379 if ( new_dom->domain_flags != 0x0 )
4380 list[idx].trust_flags = new_dom->domain_flags;
4382 if ( new_dom->domain_type != 0x0 )
4383 list[idx].trust_type = new_dom->domain_type;
4385 if ( new_dom->domain_trust_attribs != 0x0 )
4386 list[idx].trust_attribs = new_dom->domain_trust_attribs;
4390 *num_domains = idx + 1;
4396 /*********************************************************************
4397 ********************************************************************/
4399 static TDB_DATA make_tdc_key( const char *domain_name )
4401 char *keystr = NULL;
4402 TDB_DATA key = { NULL, 0 };
4404 if ( !domain_name ) {
4405 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4409 if (asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name ) == -1) {
4412 key = string_term_tdb_data(keystr);
4417 /*********************************************************************
4418 ********************************************************************/
4420 static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
4422 unsigned char **buf )
4424 unsigned char *buffer = NULL;
4429 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4437 /* Store the number of array items first */
4438 len += tdb_pack( buffer+len, buflen-len, "d",
4441 /* now pack each domain trust record */
4442 for ( i=0; i<num_domains; i++ ) {
4447 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4448 domains[i].domain_name,
4449 domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
4452 len += tdb_pack( buffer+len, buflen-len, "fffddd",
4453 domains[i].domain_name,
4454 domains[i].dns_name ? domains[i].dns_name : "",
4455 sid_to_fstring(tmp, &domains[i].sid),
4456 domains[i].trust_flags,
4457 domains[i].trust_attribs,
4458 domains[i].trust_type );
4461 if ( buflen < len ) {
4463 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
4464 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4478 /*********************************************************************
4479 ********************************************************************/
4481 static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
4482 struct winbindd_tdc_domain **domains )
4484 fstring domain_name, dns_name, sid_string;
4485 uint32_t type, attribs, flags;
4489 struct winbindd_tdc_domain *list = NULL;
4491 /* get the number of domains */
4492 len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
4494 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4498 list = talloc_array( NULL, struct winbindd_tdc_domain, num_domains );
4500 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4504 for ( i=0; i<num_domains; i++ ) {
4507 this_len = tdb_unpack( buf+len, buflen-len, "fffddd",
4515 if ( this_len == -1 ) {
4516 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4517 TALLOC_FREE( list );
4522 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4523 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4524 domain_name, dns_name, sid_string,
4525 flags, attribs, type));
4527 list[i].domain_name = talloc_strdup( list, domain_name );
4528 list[i].dns_name = NULL;
4529 if (dns_name[0] != '\0') {
4530 list[i].dns_name = talloc_strdup(list, dns_name);
4532 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
4533 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4536 list[i].trust_flags = flags;
4537 list[i].trust_attribs = attribs;
4538 list[i].trust_type = type;
4546 /*********************************************************************
4547 ********************************************************************/
4549 static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
4551 TDB_DATA key = make_tdc_key( lp_workgroup() );
4552 TDB_DATA data = { NULL, 0 };
4558 /* See if we were asked to delete the cache entry */
4561 ret = tdb_delete( wcache->tdb, key );
4565 data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
4572 ret = tdb_store( wcache->tdb, key, data, 0 );
4575 SAFE_FREE( data.dptr );
4576 SAFE_FREE( key.dptr );
4578 return ( ret == 0 );
4581 /*********************************************************************
4582 ********************************************************************/
4584 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
4586 TDB_DATA key = make_tdc_key( lp_workgroup() );
4587 TDB_DATA data = { NULL, 0 };
4595 data = tdb_fetch( wcache->tdb, key );
4597 SAFE_FREE( key.dptr );
4602 *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
4604 SAFE_FREE( data.dptr );
4612 /*********************************************************************
4613 ********************************************************************/
4615 bool wcache_tdc_add_domain( struct winbindd_domain *domain )
4617 struct winbindd_tdc_domain *dom_list = NULL;
4618 size_t num_domains = 0;
4621 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4622 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4623 domain->name, domain->alt_name,
4624 sid_string_dbg(&domain->sid),
4625 domain->domain_flags,
4626 domain->domain_trust_attribs,
4627 domain->domain_type));
4629 if ( !init_wcache() ) {
4633 /* fetch the list */
4635 wcache_tdc_fetch_list( &dom_list, &num_domains );
4637 /* add the new domain */
4639 if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
4643 /* pack the domain */
4645 if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
4653 TALLOC_FREE( dom_list );
4658 static struct winbindd_tdc_domain *wcache_tdc_dup_domain(
4659 TALLOC_CTX *mem_ctx, const struct winbindd_tdc_domain *src)
4661 struct winbindd_tdc_domain *dst;
4663 dst = talloc(mem_ctx, struct winbindd_tdc_domain);
4667 dst->domain_name = talloc_strdup(dst, src->domain_name);
4668 if (dst->domain_name == NULL) {
4672 dst->dns_name = NULL;
4673 if (src->dns_name != NULL) {
4674 dst->dns_name = talloc_strdup(dst, src->dns_name);
4675 if (dst->dns_name == NULL) {
4680 sid_copy(&dst->sid, &src->sid);
4681 dst->trust_flags = src->trust_flags;
4682 dst->trust_type = src->trust_type;
4683 dst->trust_attribs = src->trust_attribs;
4690 /*********************************************************************
4691 ********************************************************************/
4693 struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
4695 struct winbindd_tdc_domain *dom_list = NULL;
4696 size_t num_domains = 0;
4698 struct winbindd_tdc_domain *d = NULL;
4700 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
4702 if ( !init_wcache() ) {
4706 /* fetch the list */
4708 wcache_tdc_fetch_list( &dom_list, &num_domains );
4710 for ( i=0; i<num_domains; i++ ) {
4711 if ( strequal(name, dom_list[i].domain_name) ||
4712 strequal(name, dom_list[i].dns_name) )
4714 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4717 d = wcache_tdc_dup_domain(ctx, &dom_list[i]);
4722 TALLOC_FREE( dom_list );
4727 /*********************************************************************
4728 ********************************************************************/
4730 void wcache_tdc_clear( void )
4732 if ( !init_wcache() )
4735 wcache_tdc_store_list( NULL, 0 );
4740 static bool wcache_ndr_key(TALLOC_CTX *mem_ctx, const char *domain_name,
4741 uint32_t opnum, const DATA_BLOB *req,
4747 key = talloc_asprintf(mem_ctx, "NDR/%s/%d/", domain_name, (int)opnum);
4751 keylen = talloc_get_size(key) - 1;
4753 key = talloc_realloc(mem_ctx, key, char, keylen + req->length);
4757 memcpy(key + keylen, req->data, req->length);
4759 pkey->dptr = (uint8_t *)key;
4760 pkey->dsize = talloc_get_size(key);
4764 static bool wcache_opnum_cacheable(uint32_t opnum)
4767 case NDR_WBINT_PING:
4768 case NDR_WBINT_QUERYSEQUENCENUMBER:
4769 case NDR_WBINT_ALLOCATEUID:
4770 case NDR_WBINT_ALLOCATEGID:
4771 case NDR_WBINT_CHECKMACHINEACCOUNT:
4772 case NDR_WBINT_CHANGEMACHINEACCOUNT:
4773 case NDR_WBINT_PINGDC:
4779 bool wcache_fetch_ndr(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
4780 uint32_t opnum, const DATA_BLOB *req, DATA_BLOB *resp)
4785 if (!wcache_opnum_cacheable(opnum) ||
4786 is_my_own_sam_domain(domain) ||
4787 is_builtin_domain(domain)) {
4791 if (wcache->tdb == NULL) {
4795 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4798 data = tdb_fetch(wcache->tdb, key);
4799 TALLOC_FREE(key.dptr);
4801 if (data.dptr == NULL) {
4804 if (data.dsize < 12) {
4808 if (!is_domain_offline(domain)) {
4809 uint32_t entry_seqnum, dom_seqnum, last_check;
4810 uint64_t entry_timeout;
4812 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum,
4816 entry_seqnum = IVAL(data.dptr, 0);
4817 if (entry_seqnum != dom_seqnum) {
4818 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4819 (int)entry_seqnum));
4822 entry_timeout = BVAL(data.dptr, 4);
4823 if (time(NULL) > entry_timeout) {
4824 DEBUG(10, ("Entry has timed out\n"));
4829 resp->data = (uint8_t *)talloc_memdup(mem_ctx, data.dptr + 12,
4831 if (resp->data == NULL) {
4832 DEBUG(10, ("talloc failed\n"));
4835 resp->length = data.dsize - 12;
4839 SAFE_FREE(data.dptr);
4843 void wcache_store_ndr(struct winbindd_domain *domain, uint32_t opnum,
4844 const DATA_BLOB *req, const DATA_BLOB *resp)
4847 uint32_t dom_seqnum, last_check;
4850 if (!wcache_opnum_cacheable(opnum) ||
4851 is_my_own_sam_domain(domain) ||
4852 is_builtin_domain(domain)) {
4856 if (wcache->tdb == NULL) {
4860 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum, &last_check)) {
4861 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4866 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4870 timeout = time(NULL) + lp_winbind_cache_time();
4872 data.dsize = resp->length + 12;
4873 data.dptr = talloc_array(key.dptr, uint8_t, data.dsize);
4874 if (data.dptr == NULL) {
4878 SIVAL(data.dptr, 0, dom_seqnum);
4879 SBVAL(data.dptr, 4, timeout);
4880 memcpy(data.dptr + 12, resp->data, resp->length);
4882 tdb_store(wcache->tdb, key, data, 0);
4885 TALLOC_FREE(key.dptr);