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 if (domain->backend == NULL) {
152 struct winbindd_domain *our_domain = domain;
154 /* find our domain first so we can figure out if we
155 are joined to a kerberized domain */
157 if (!domain->primary) {
158 our_domain = find_our_domain();
161 if ((our_domain->active_directory || IS_DC)
162 && domain->active_directory
163 && !lp_winbind_rpc_only())
165 DBG_INFO("Setting ADS methods for domain %s\n",
167 domain->backend = &reconnect_ads_methods;
170 #endif /* HAVE_ADS */
172 if (domain->backend == NULL) {
173 DBG_INFO("Setting MS-RPC methods for domain %s\n", domain->name);
174 domain->backend = &reconnect_methods;
181 ret = SMB_XMALLOC_P(struct winbind_cache);
185 wcache_flush_cache();
191 free a centry structure
193 static void centry_free(struct cache_entry *centry)
197 SAFE_FREE(centry->data);
201 static bool centry_check_bytes(struct cache_entry *centry, size_t nbytes)
203 if (centry->len - centry->ofs < nbytes) {
204 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
205 (unsigned int)nbytes,
206 centry->len - centry->ofs));
213 pull a uint64_t from a cache entry
215 static uint64_t centry_uint64_t(struct cache_entry *centry)
219 if (!centry_check_bytes(centry, 8)) {
220 smb_panic_fn("centry_uint64_t");
222 ret = BVAL(centry->data, centry->ofs);
228 pull a uint32_t from a cache entry
230 static uint32_t centry_uint32(struct cache_entry *centry)
234 if (!centry_check_bytes(centry, 4)) {
235 smb_panic_fn("centry_uint32");
237 ret = IVAL(centry->data, centry->ofs);
243 pull a uint16_t from a cache entry
245 static uint16_t centry_uint16(struct cache_entry *centry)
248 if (!centry_check_bytes(centry, 2)) {
249 smb_panic_fn("centry_uint16");
251 ret = SVAL(centry->data, centry->ofs);
257 pull a uint8_t from a cache entry
259 static uint8_t centry_uint8(struct cache_entry *centry)
262 if (!centry_check_bytes(centry, 1)) {
263 smb_panic_fn("centry_uint8");
265 ret = CVAL(centry->data, centry->ofs);
271 pull a NTTIME from a cache entry
273 static NTTIME centry_nttime(struct cache_entry *centry)
276 if (!centry_check_bytes(centry, 8)) {
277 smb_panic_fn("centry_nttime");
279 ret = IVAL(centry->data, centry->ofs);
281 ret += (uint64_t)IVAL(centry->data, centry->ofs) << 32;
287 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
289 static time_t centry_time(struct cache_entry *centry)
291 return (time_t)centry_nttime(centry);
294 /* pull a string from a cache entry, using the supplied
297 static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
302 len = centry_uint8(centry);
305 /* a deliberate NULL string */
309 if (!centry_check_bytes(centry, (size_t)len)) {
310 smb_panic_fn("centry_string");
313 ret = talloc_array(mem_ctx, char, len+1);
315 smb_panic_fn("centry_string out of memory\n");
317 memcpy(ret,centry->data + centry->ofs, len);
323 /* pull a hash16 from a cache entry, using the supplied
326 static char *centry_hash16(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
331 len = centry_uint8(centry);
334 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
339 if (!centry_check_bytes(centry, 16)) {
343 ret = talloc_array(mem_ctx, char, 16);
345 smb_panic_fn("centry_hash out of memory\n");
347 memcpy(ret,centry->data + centry->ofs, 16);
352 /* pull a sid from a cache entry, using the supplied
355 static bool centry_sid(struct cache_entry *centry, struct dom_sid *sid)
360 sid_string = centry_string(centry, talloc_tos());
361 if (sid_string == NULL) {
364 ret = string_to_sid(sid, sid_string);
365 TALLOC_FREE(sid_string);
371 pull a NTSTATUS from a cache entry
373 static NTSTATUS centry_ntstatus(struct cache_entry *centry)
377 status = NT_STATUS(centry_uint32(centry));
382 /* the server is considered down if it can't give us a sequence number */
383 static bool wcache_server_down(struct winbindd_domain *domain)
390 ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
393 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
398 struct wcache_seqnum_state {
400 uint32_t *last_seq_check;
403 static int wcache_seqnum_parser(TDB_DATA key, TDB_DATA data,
406 struct wcache_seqnum_state *state = private_data;
408 if (data.dsize != 8) {
409 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
414 *state->seqnum = IVAL(data.dptr, 0);
415 *state->last_seq_check = IVAL(data.dptr, 4);
419 static bool wcache_fetch_seqnum(const char *domain_name, uint32_t *seqnum,
420 uint32_t *last_seq_check)
422 struct wcache_seqnum_state state = {
423 .seqnum = seqnum, .last_seq_check = last_seq_check
425 size_t len = strlen(domain_name);
427 TDB_DATA key = { .dptr = (uint8_t *)keystr, .dsize = sizeof(keystr) };
430 if (wcache->tdb == NULL) {
431 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
435 snprintf(keystr, sizeof(keystr), "SEQNUM/%s", domain_name);
437 ret = tdb_parse_record(wcache->tdb, key, wcache_seqnum_parser,
442 static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
444 uint32_t last_check, time_diff;
446 if (!wcache_fetch_seqnum(domain->name, &domain->sequence_number,
448 return NT_STATUS_UNSUCCESSFUL;
450 domain->last_seq_check = last_check;
452 /* have we expired? */
454 time_diff = now - domain->last_seq_check;
455 if ((int)time_diff > lp_winbind_cache_time()) {
456 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
457 domain->name, domain->sequence_number,
458 (uint32_t)domain->last_seq_check));
459 return NT_STATUS_UNSUCCESSFUL;
462 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
463 domain->name, domain->sequence_number,
464 (uint32_t)domain->last_seq_check));
469 bool wcache_store_seqnum(const char *domain_name, uint32_t seqnum,
470 time_t last_seq_check)
472 size_t len = strlen(domain_name);
474 TDB_DATA key = { .dptr = (uint8_t *)keystr, .dsize = sizeof(keystr) };
478 if (wcache->tdb == NULL) {
479 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
483 snprintf(keystr, sizeof(keystr), "SEQNUM/%s", domain_name);
485 SIVAL(buf, 0, seqnum);
486 SIVAL(buf, 4, last_seq_check);
488 ret = tdb_store(wcache->tdb, key, make_tdb_data(buf, sizeof(buf)),
491 DEBUG(10, ("tdb_store_bystring failed: %s\n",
492 tdb_errorstr(wcache->tdb)));
496 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
497 domain_name, seqnum, (unsigned)last_seq_check));
502 static bool store_cache_seqnum( struct winbindd_domain *domain )
504 return wcache_store_seqnum(domain->name, domain->sequence_number,
505 domain->last_seq_check);
509 refresh the domain sequence number on timeout.
512 static void refresh_sequence_number(struct winbindd_domain *domain)
516 time_t t = time(NULL);
517 unsigned cache_time = lp_winbind_cache_time();
519 if (is_domain_offline(domain)) {
525 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
526 /* trying to reconnect is expensive, don't do it too often */
527 if (domain->sequence_number == DOM_SEQUENCE_NONE) {
532 time_diff = t - domain->last_seq_check;
534 /* see if we have to refetch the domain sequence number */
535 if ((time_diff < cache_time) &&
536 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
537 NT_STATUS_IS_OK(domain->last_status)) {
538 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
542 /* try to get the sequence number from the tdb cache first */
543 /* this will update the timestamp as well */
545 status = fetch_cache_seqnum( domain, t );
546 if (NT_STATUS_IS_OK(status) &&
547 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
548 NT_STATUS_IS_OK(domain->last_status)) {
552 /* important! make sure that we know if this is a native
553 mode domain or not. And that we can contact it. */
555 if ( winbindd_can_contact_domain( domain ) ) {
556 status = domain->backend->sequence_number(domain,
557 &domain->sequence_number);
559 /* just use the current time */
560 status = NT_STATUS_OK;
561 domain->sequence_number = time(NULL);
565 /* the above call could have set our domain->backend to NULL when
566 * coming from offline to online mode, make sure to reinitialize the
567 * backend - Guenther */
570 if (!NT_STATUS_IS_OK(status)) {
571 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status)));
572 domain->sequence_number = DOM_SEQUENCE_NONE;
575 domain->last_status = status;
576 domain->last_seq_check = time(NULL);
578 /* save the new sequence number in the cache */
579 store_cache_seqnum( domain );
582 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
583 domain->name, domain->sequence_number));
589 decide if a cache entry has expired
591 static bool centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
593 /* If we've been told to be offline - stay in that state... */
594 if (lp_winbind_offline_logon() && global_winbindd_offline_state) {
595 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
596 keystr, domain->name ));
600 /* when the domain is offline return the cached entry.
601 * This deals with transient offline states... */
603 if (!domain->online) {
604 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
605 keystr, domain->name ));
609 /* if the server is OK and our cache entry came from when it was down then
610 the entry is invalid */
611 if ((domain->sequence_number != DOM_SEQUENCE_NONE) &&
612 (centry->sequence_number == DOM_SEQUENCE_NONE)) {
613 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
614 keystr, domain->name ));
618 /* if the server is down or the cache entry is not older than the
619 current sequence number or it did not timeout then it is OK */
620 if (wcache_server_down(domain)
621 || ((centry->sequence_number == domain->sequence_number)
622 && ((time_t)centry->timeout > time(NULL)))) {
623 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
624 keystr, domain->name ));
628 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
629 keystr, domain->name ));
635 static struct cache_entry *wcache_fetch_raw(char *kstr)
638 struct cache_entry *centry;
641 key = string_tdb_data(kstr);
642 data = tdb_fetch(wcache->tdb, key);
648 centry = SMB_XMALLOC_P(struct cache_entry);
649 centry->data = (unsigned char *)data.dptr;
650 centry->len = data.dsize;
653 if (centry->len < 16) {
654 /* huh? corrupt cache? */
655 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s "
656 "(len < 16)?\n", kstr));
661 centry->status = centry_ntstatus(centry);
662 centry->sequence_number = centry_uint32(centry);
663 centry->timeout = centry_uint64_t(centry);
668 static bool is_my_own_sam_domain(struct winbindd_domain *domain)
670 if (strequal(domain->name, get_global_sam_name()) &&
671 sid_check_is_our_sam(&domain->sid)) {
678 static bool is_builtin_domain(struct winbindd_domain *domain)
680 if (strequal(domain->name, "BUILTIN") &&
681 sid_check_is_builtin(&domain->sid)) {
689 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
690 number and return status
692 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
693 struct winbindd_domain *domain,
694 const char *format, ...) PRINTF_ATTRIBUTE(3,4);
695 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
696 struct winbindd_domain *domain,
697 const char *format, ...)
701 struct cache_entry *centry;
703 if (!winbindd_use_cache() ||
704 is_my_own_sam_domain(domain) ||
705 is_builtin_domain(domain)) {
709 refresh_sequence_number(domain);
711 va_start(ap, format);
712 smb_xvasprintf(&kstr, format, ap);
715 centry = wcache_fetch_raw(kstr);
716 if (centry == NULL) {
721 if (centry_expired(domain, kstr, centry)) {
723 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
724 kstr, domain->name ));
731 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
732 kstr, domain->name ));
738 static void wcache_delete(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
739 static void wcache_delete(const char *format, ...)
745 va_start(ap, format);
746 smb_xvasprintf(&kstr, format, ap);
749 key = string_tdb_data(kstr);
751 tdb_delete(wcache->tdb, key);
756 make sure we have at least len bytes available in a centry
758 static void centry_expand(struct cache_entry *centry, uint32_t len)
760 if (centry->len - centry->ofs >= len)
763 centry->data = SMB_REALLOC_ARRAY(centry->data, unsigned char,
766 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
767 smb_panic_fn("out of memory in centry_expand");
772 push a uint64_t into a centry
774 static void centry_put_uint64_t(struct cache_entry *centry, uint64_t v)
776 centry_expand(centry, 8);
777 SBVAL(centry->data, centry->ofs, v);
782 push a uint32_t into a centry
784 static void centry_put_uint32(struct cache_entry *centry, uint32_t v)
786 centry_expand(centry, 4);
787 SIVAL(centry->data, centry->ofs, v);
792 push a uint16_t into a centry
794 static void centry_put_uint16(struct cache_entry *centry, uint16_t v)
796 centry_expand(centry, 2);
797 SSVAL(centry->data, centry->ofs, v);
802 push a uint8_t into a centry
804 static void centry_put_uint8(struct cache_entry *centry, uint8_t v)
806 centry_expand(centry, 1);
807 SCVAL(centry->data, centry->ofs, v);
812 push a string into a centry
814 static void centry_put_string(struct cache_entry *centry, const char *s)
819 /* null strings are marked as len 0xFFFF */
820 centry_put_uint8(centry, 0xFF);
825 /* can't handle more than 254 char strings. Truncating is probably best */
827 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len));
830 centry_put_uint8(centry, len);
831 centry_expand(centry, len);
832 memcpy(centry->data + centry->ofs, s, len);
837 push a 16 byte hash into a centry - treat as 16 byte string.
839 static void centry_put_hash16(struct cache_entry *centry, const uint8_t val[16])
841 centry_put_uint8(centry, 16);
842 centry_expand(centry, 16);
843 memcpy(centry->data + centry->ofs, val, 16);
847 static void centry_put_sid(struct cache_entry *centry, const struct dom_sid *sid)
850 centry_put_string(centry, sid_to_fstring(sid_string, sid));
855 put NTSTATUS into a centry
857 static void centry_put_ntstatus(struct cache_entry *centry, NTSTATUS status)
859 uint32_t status_value = NT_STATUS_V(status);
860 centry_put_uint32(centry, status_value);
865 push a NTTIME into a centry
867 static void centry_put_nttime(struct cache_entry *centry, NTTIME nt)
869 centry_expand(centry, 8);
870 SIVAL(centry->data, centry->ofs, nt & 0xFFFFFFFF);
872 SIVAL(centry->data, centry->ofs, nt >> 32);
877 push a time_t into a centry - use a 64 bit size.
878 NTTIME here is being used as a convenient 64-bit size.
880 static void centry_put_time(struct cache_entry *centry, time_t t)
882 NTTIME nt = (NTTIME)t;
883 centry_put_nttime(centry, nt);
887 start a centry for output. When finished, call centry_end()
889 static struct cache_entry *centry_start(struct winbindd_domain *domain,
892 struct cache_entry *centry;
897 centry = SMB_XMALLOC_P(struct cache_entry);
899 centry->len = 8192; /* reasonable default */
900 centry->data = SMB_XMALLOC_ARRAY(uint8_t, centry->len);
902 centry->sequence_number = domain->sequence_number;
903 centry->timeout = lp_winbind_cache_time() + time(NULL);
904 centry_put_ntstatus(centry, status);
905 centry_put_uint32(centry, centry->sequence_number);
906 centry_put_uint64_t(centry, centry->timeout);
911 finish a centry and write it to the tdb
913 static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
914 static void centry_end(struct cache_entry *centry, const char *format, ...)
920 if (!winbindd_use_cache()) {
924 va_start(ap, format);
925 smb_xvasprintf(&kstr, format, ap);
928 key = string_tdb_data(kstr);
929 data.dptr = centry->data;
930 data.dsize = centry->ofs;
932 tdb_store(wcache->tdb, key, data, TDB_REPLACE);
936 static void wcache_save_name_to_sid(struct winbindd_domain *domain,
937 NTSTATUS status, const char *domain_name,
938 const char *name, const struct dom_sid *sid,
939 enum lsa_SidType type)
941 struct cache_entry *centry;
944 centry = centry_start(domain, status);
948 if ((domain_name == NULL) || (domain_name[0] == '\0')) {
949 struct winbindd_domain *mydomain =
950 find_domain_from_sid_noinit(sid);
951 if (mydomain != NULL) {
952 domain_name = mydomain->name;
956 centry_put_uint32(centry, type);
957 centry_put_sid(centry, sid);
958 fstrcpy(uname, name);
959 (void)strupper_m(uname);
960 centry_end(centry, "NS/%s/%s", domain_name, uname);
961 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name,
962 uname, sid_string_dbg(sid), nt_errstr(status)));
966 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
967 const struct dom_sid *sid, const char *domain_name, const char *name, enum lsa_SidType type)
969 struct cache_entry *centry;
972 centry = centry_start(domain, status);
976 if ((domain_name == NULL) || (domain_name[0] == '\0')) {
977 struct winbindd_domain *mydomain =
978 find_domain_from_sid_noinit(sid);
979 if (mydomain != NULL) {
980 domain_name = mydomain->name;
984 if (NT_STATUS_IS_OK(status)) {
985 centry_put_uint32(centry, type);
986 centry_put_string(centry, domain_name);
987 centry_put_string(centry, name);
990 centry_end(centry, "SN/%s", sid_to_fstring(sid_string, sid));
991 DEBUG(10,("wcache_save_sid_to_name: %s -> %s\\%s (%s)\n", sid_string,
992 domain_name, name, nt_errstr(status)));
996 static void wcache_save_lockout_policy(struct winbindd_domain *domain,
998 struct samr_DomInfo12 *lockout_policy)
1000 struct cache_entry *centry;
1002 centry = centry_start(domain, status);
1006 centry_put_nttime(centry, lockout_policy->lockout_duration);
1007 centry_put_nttime(centry, lockout_policy->lockout_window);
1008 centry_put_uint16(centry, lockout_policy->lockout_threshold);
1010 centry_end(centry, "LOC_POL/%s", domain->name);
1012 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
1014 centry_free(centry);
1019 static void wcache_save_password_policy(struct winbindd_domain *domain,
1021 struct samr_DomInfo1 *policy)
1023 struct cache_entry *centry;
1025 centry = centry_start(domain, status);
1029 centry_put_uint16(centry, policy->min_password_length);
1030 centry_put_uint16(centry, policy->password_history_length);
1031 centry_put_uint32(centry, policy->password_properties);
1032 centry_put_nttime(centry, policy->max_password_age);
1033 centry_put_nttime(centry, policy->min_password_age);
1035 centry_end(centry, "PWD_POL/%s", domain->name);
1037 DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
1039 centry_free(centry);
1042 /***************************************************************************
1043 ***************************************************************************/
1045 static void wcache_save_username_alias(struct winbindd_domain *domain,
1047 const char *name, const char *alias)
1049 struct cache_entry *centry;
1052 if ( (centry = centry_start(domain, status)) == NULL )
1055 centry_put_string( centry, alias );
1057 fstrcpy(uname, name);
1058 (void)strupper_m(uname);
1059 centry_end(centry, "NSS/NA/%s", uname);
1061 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name, alias ));
1063 centry_free(centry);
1066 static void wcache_save_alias_username(struct winbindd_domain *domain,
1068 const char *alias, const char *name)
1070 struct cache_entry *centry;
1073 if ( (centry = centry_start(domain, status)) == NULL )
1076 centry_put_string( centry, name );
1078 fstrcpy(uname, alias);
1079 (void)strupper_m(uname);
1080 centry_end(centry, "NSS/AN/%s", uname);
1082 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias, name ));
1084 centry_free(centry);
1087 /***************************************************************************
1088 ***************************************************************************/
1090 NTSTATUS resolve_username_to_alias( TALLOC_CTX *mem_ctx,
1091 struct winbindd_domain *domain,
1092 const char *name, char **alias )
1094 struct winbind_cache *cache = get_cache(domain);
1095 struct cache_entry *centry = NULL;
1099 if ( domain->internal )
1100 return NT_STATUS_NOT_SUPPORTED;
1105 upper_name = talloc_strdup_upper(mem_ctx, name);
1106 if (upper_name == NULL) {
1107 return NT_STATUS_NO_MEMORY;
1110 centry = wcache_fetch(cache, domain, "NSS/NA/%s", upper_name);
1112 talloc_free(upper_name);
1117 status = centry->status;
1119 if (!NT_STATUS_IS_OK(status)) {
1120 centry_free(centry);
1124 *alias = centry_string( centry, mem_ctx );
1126 centry_free(centry);
1128 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1129 name, *alias ? *alias : "(none)"));
1131 return (*alias) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1135 /* If its not in cache and we are offline, then fail */
1137 if ( get_global_winbindd_state_offline() || !domain->online ) {
1138 DEBUG(8,("resolve_username_to_alias: rejecting query "
1139 "in offline mode\n"));
1140 return NT_STATUS_NOT_FOUND;
1143 status = nss_map_to_alias( mem_ctx, domain->name, name, alias );
1145 if ( NT_STATUS_IS_OK( status ) ) {
1146 wcache_save_username_alias(domain, status, name, *alias);
1149 if ( NT_STATUS_EQUAL( status, NT_STATUS_NONE_MAPPED ) ) {
1150 wcache_save_username_alias(domain, status, name, "(NULL)");
1153 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1154 nt_errstr(status)));
1156 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1157 set_domain_offline( domain );
1163 /***************************************************************************
1164 ***************************************************************************/
1166 NTSTATUS resolve_alias_to_username( TALLOC_CTX *mem_ctx,
1167 struct winbindd_domain *domain,
1168 const char *alias, char **name )
1170 struct winbind_cache *cache = get_cache(domain);
1171 struct cache_entry *centry = NULL;
1175 if ( domain->internal )
1176 return NT_STATUS_NOT_SUPPORTED;
1181 upper_name = talloc_strdup(mem_ctx, alias);
1182 if (upper_name == NULL) {
1183 return NT_STATUS_NO_MEMORY;
1185 if (!strupper_m(upper_name)) {
1186 talloc_free(upper_name);
1187 return NT_STATUS_INVALID_PARAMETER;
1190 centry = wcache_fetch(cache, domain, "NSS/AN/%s", upper_name);
1192 talloc_free(upper_name);
1197 status = centry->status;
1199 if (!NT_STATUS_IS_OK(status)) {
1200 centry_free(centry);
1204 *name = centry_string( centry, mem_ctx );
1206 centry_free(centry);
1208 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1209 alias, *name ? *name : "(none)"));
1211 return (*name) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1215 /* If its not in cache and we are offline, then fail */
1217 if ( get_global_winbindd_state_offline() || !domain->online ) {
1218 DEBUG(8,("resolve_alias_to_username: rejecting query "
1219 "in offline mode\n"));
1220 return NT_STATUS_NOT_FOUND;
1223 /* an alias cannot contain a domain prefix or '@' */
1225 if (strchr(alias, '\\') || strchr(alias, '@')) {
1226 DEBUG(10,("resolve_alias_to_username: skipping fully "
1227 "qualified name %s\n", alias));
1228 return NT_STATUS_OBJECT_NAME_INVALID;
1231 status = nss_map_from_alias( mem_ctx, domain->name, alias, name );
1233 if ( NT_STATUS_IS_OK( status ) ) {
1234 wcache_save_alias_username( domain, status, alias, *name );
1237 if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1238 wcache_save_alias_username(domain, status, alias, "(NULL)");
1241 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1242 nt_errstr(status)));
1244 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1245 set_domain_offline( domain );
1251 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const struct dom_sid *sid)
1253 struct winbind_cache *cache = get_cache(domain);
1255 fstring key_str, tmp;
1259 return NT_STATUS_INTERNAL_DB_ERROR;
1262 if (is_null_sid(sid)) {
1263 return NT_STATUS_INVALID_SID;
1266 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1267 return NT_STATUS_INVALID_SID;
1270 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
1272 ret = tdb_exists(cache->tdb, string_tdb_data(key_str));
1274 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1277 return NT_STATUS_OK;
1280 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1281 as new salted ones. */
1283 NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
1284 TALLOC_CTX *mem_ctx,
1285 const struct dom_sid *sid,
1286 const uint8_t **cached_nt_pass,
1287 const uint8_t **cached_salt)
1289 struct winbind_cache *cache = get_cache(domain);
1290 struct cache_entry *centry = NULL;
1296 return NT_STATUS_INTERNAL_DB_ERROR;
1299 if (is_null_sid(sid)) {
1300 return NT_STATUS_INVALID_SID;
1303 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1304 return NT_STATUS_INVALID_SID;
1307 /* Try and get a salted cred first. If we can't
1308 fall back to an unsalted cred. */
1310 centry = wcache_fetch(cache, domain, "CRED/%s",
1311 sid_to_fstring(tmp, sid));
1313 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1314 sid_string_dbg(sid)));
1315 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1319 * We don't use the time element at this moment,
1320 * but we have to consume it, so that we don't
1321 * neet to change the disk format of the cache.
1323 (void)centry_time(centry);
1325 /* In the salted case this isn't actually the nt_hash itself,
1326 but the MD5 of the salt + nt_hash. Let the caller
1327 sort this out. It can tell as we only return the cached_salt
1328 if we are returning a salted cred. */
1330 *cached_nt_pass = (const uint8_t *)centry_hash16(centry, mem_ctx);
1331 if (*cached_nt_pass == NULL) {
1334 sid_to_fstring(sidstr, sid);
1336 /* Bad (old) cred cache. Delete and pretend we
1338 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1340 wcache_delete("CRED/%s", sidstr);
1341 centry_free(centry);
1342 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1345 /* We only have 17 bytes more data in the salted cred case. */
1346 if (centry->len - centry->ofs == 17) {
1347 *cached_salt = (const uint8_t *)centry_hash16(centry, mem_ctx);
1349 *cached_salt = NULL;
1352 dump_data_pw("cached_nt_pass", *cached_nt_pass, NT_HASH_LEN);
1354 dump_data_pw("cached_salt", *cached_salt, NT_HASH_LEN);
1357 status = centry->status;
1359 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1360 sid_string_dbg(sid), nt_errstr(status) ));
1362 centry_free(centry);
1366 /* Store creds for a SID - only writes out new salted ones. */
1368 NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
1369 const struct dom_sid *sid,
1370 const uint8_t nt_pass[NT_HASH_LEN])
1372 struct cache_entry *centry;
1375 uint8_t cred_salt[NT_HASH_LEN];
1376 uint8_t salted_hash[NT_HASH_LEN];
1378 if (is_null_sid(sid)) {
1379 return NT_STATUS_INVALID_SID;
1382 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1383 return NT_STATUS_INVALID_SID;
1386 centry = centry_start(domain, NT_STATUS_OK);
1388 return NT_STATUS_INTERNAL_DB_ERROR;
1391 dump_data_pw("nt_pass", nt_pass, NT_HASH_LEN);
1393 centry_put_time(centry, time(NULL));
1395 /* Create a salt and then salt the hash. */
1396 generate_random_buffer(cred_salt, NT_HASH_LEN);
1397 E_md5hash(cred_salt, nt_pass, salted_hash);
1399 centry_put_hash16(centry, salted_hash);
1400 centry_put_hash16(centry, cred_salt);
1401 centry_end(centry, "CRED/%s", sid_to_fstring(sid_string, sid));
1403 DEBUG(10,("wcache_save_creds: %s\n", sid_string));
1405 centry_free(centry);
1407 return NT_STATUS_OK;
1411 /* Query display info. This is the basic user list fn */
1412 NTSTATUS wb_cache_query_user_list(struct winbindd_domain *domain,
1413 TALLOC_CTX *mem_ctx,
1416 struct winbind_cache *cache = get_cache(domain);
1417 struct cache_entry *centry = NULL;
1418 uint32_t num_rids = 0;
1419 uint32_t *rids = NULL;
1421 unsigned int i, retry;
1422 bool old_status = domain->online;
1429 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1434 num_rids = centry_uint32(centry);
1436 if (num_rids == 0) {
1440 rids = talloc_array(mem_ctx, uint32_t, num_rids);
1442 centry_free(centry);
1443 return NT_STATUS_NO_MEMORY;
1446 for (i=0; i<num_rids; i++) {
1447 rids[i] = centry_uint32(centry);
1451 status = centry->status;
1453 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1454 domain->name, nt_errstr(status) ));
1456 centry_free(centry);
1461 /* Return status value returned by seq number check */
1463 if (!NT_STATUS_IS_OK(domain->last_status))
1464 return domain->last_status;
1466 /* Put the query_user_list() in a retry loop. There appears to be
1467 * some bug either with Windows 2000 or Samba's handling of large
1468 * rpc replies. This manifests itself as sudden disconnection
1469 * at a random point in the enumeration of a large (60k) user list.
1470 * The retry loop simply tries the operation again. )-: It's not
1471 * pretty but an acceptable workaround until we work out what the
1472 * real problem is. */
1477 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1481 status = domain->backend->query_user_list(domain, mem_ctx,
1483 num_rids = talloc_array_length(rids);
1485 if (!NT_STATUS_IS_OK(status)) {
1486 DEBUG(3, ("query_user_list: returned 0x%08x, "
1487 "retrying\n", NT_STATUS_V(status)));
1489 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1490 DEBUG(3, ("query_user_list: flushing "
1491 "connection cache\n"));
1492 invalidate_cm_connection(domain);
1494 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1495 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1496 if (!domain->internal && old_status) {
1497 set_domain_offline(domain);
1499 /* store partial response. */
1502 * humm, what about the status used for cache?
1503 * Should it be NT_STATUS_OK?
1508 * domain is offline now, and there is no user entries,
1509 * try to fetch from cache again.
1511 if (cache->tdb && !domain->online && !domain->internal && old_status) {
1512 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1513 /* partial response... */
1517 goto do_fetch_cache;
1524 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
1528 refresh_sequence_number(domain);
1529 if (!NT_STATUS_IS_OK(status)) {
1532 centry = centry_start(domain, status);
1535 centry_put_uint32(centry, num_rids);
1536 for (i=0; i<num_rids; i++) {
1537 centry_put_uint32(centry, rids[i]);
1539 centry_end(centry, "UL/%s", domain->name);
1540 centry_free(centry);
1548 /* list all domain groups */
1549 NTSTATUS wb_cache_enum_dom_groups(struct winbindd_domain *domain,
1550 TALLOC_CTX *mem_ctx,
1551 uint32_t *num_entries,
1552 struct wb_acct_info **info)
1554 struct winbind_cache *cache = get_cache(domain);
1555 struct cache_entry *centry = NULL;
1560 old_status = domain->online;
1564 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1569 *num_entries = centry_uint32(centry);
1571 if (*num_entries == 0)
1574 (*info) = talloc_array(mem_ctx, struct wb_acct_info, *num_entries);
1576 smb_panic_fn("enum_dom_groups out of memory");
1578 for (i=0; i<(*num_entries); i++) {
1579 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1580 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1581 (*info)[i].rid = centry_uint32(centry);
1585 status = centry->status;
1587 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1588 domain->name, nt_errstr(status) ));
1590 centry_free(centry);
1597 /* Return status value returned by seq number check */
1599 if (!NT_STATUS_IS_OK(domain->last_status))
1600 return domain->last_status;
1602 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1605 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1607 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1608 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1609 if (!domain->internal && old_status) {
1610 set_domain_offline(domain);
1614 !domain->internal &&
1616 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1618 goto do_fetch_cache;
1623 refresh_sequence_number(domain);
1624 if (!NT_STATUS_IS_OK(status)) {
1627 centry = centry_start(domain, status);
1630 centry_put_uint32(centry, *num_entries);
1631 for (i=0; i<(*num_entries); i++) {
1632 centry_put_string(centry, (*info)[i].acct_name);
1633 centry_put_string(centry, (*info)[i].acct_desc);
1634 centry_put_uint32(centry, (*info)[i].rid);
1636 centry_end(centry, "GL/%s/domain", domain->name);
1637 centry_free(centry);
1643 /* list all domain groups */
1644 NTSTATUS wb_cache_enum_local_groups(struct winbindd_domain *domain,
1645 TALLOC_CTX *mem_ctx,
1646 uint32_t *num_entries,
1647 struct wb_acct_info **info)
1649 struct winbind_cache *cache = get_cache(domain);
1650 struct cache_entry *centry = NULL;
1655 old_status = domain->online;
1659 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1664 *num_entries = centry_uint32(centry);
1666 if (*num_entries == 0)
1669 (*info) = talloc_array(mem_ctx, struct wb_acct_info, *num_entries);
1671 smb_panic_fn("enum_dom_groups out of memory");
1673 for (i=0; i<(*num_entries); i++) {
1674 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1675 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1676 (*info)[i].rid = centry_uint32(centry);
1681 /* If we are returning cached data and the domain controller
1682 is down then we don't know whether the data is up to date
1683 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1686 if (wcache_server_down(domain)) {
1687 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1688 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1690 status = centry->status;
1692 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1693 domain->name, nt_errstr(status) ));
1695 centry_free(centry);
1702 /* Return status value returned by seq number check */
1704 if (!NT_STATUS_IS_OK(domain->last_status))
1705 return domain->last_status;
1707 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1710 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1712 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1713 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1714 if (!domain->internal && old_status) {
1715 set_domain_offline(domain);
1718 !domain->internal &&
1721 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1723 goto do_fetch_cache;
1728 refresh_sequence_number(domain);
1729 if (!NT_STATUS_IS_OK(status)) {
1732 centry = centry_start(domain, status);
1735 centry_put_uint32(centry, *num_entries);
1736 for (i=0; i<(*num_entries); i++) {
1737 centry_put_string(centry, (*info)[i].acct_name);
1738 centry_put_string(centry, (*info)[i].acct_desc);
1739 centry_put_uint32(centry, (*info)[i].rid);
1741 centry_end(centry, "GL/%s/local", domain->name);
1742 centry_free(centry);
1748 static NTSTATUS wcache_name_to_sid(struct winbindd_domain *domain,
1749 const char *domain_name,
1751 struct dom_sid *sid,
1752 enum lsa_SidType *type)
1754 struct winbind_cache *cache = get_cache(domain);
1755 struct cache_entry *centry;
1759 if (cache->tdb == NULL) {
1760 return NT_STATUS_NOT_FOUND;
1763 uname = talloc_strdup_upper(talloc_tos(), name);
1764 if (uname == NULL) {
1765 return NT_STATUS_NO_MEMORY;
1768 if ((domain_name == NULL) || (domain_name[0] == '\0')) {
1769 domain_name = domain->name;
1772 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1774 if (centry == NULL) {
1775 return NT_STATUS_NOT_FOUND;
1778 status = centry->status;
1779 if (NT_STATUS_IS_OK(status)) {
1780 *type = (enum lsa_SidType)centry_uint32(centry);
1781 centry_sid(centry, sid);
1784 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1785 "%s\n", domain->name, nt_errstr(status) ));
1787 centry_free(centry);
1791 /* convert a single name to a sid in a domain */
1792 NTSTATUS wb_cache_name_to_sid(struct winbindd_domain *domain,
1793 TALLOC_CTX *mem_ctx,
1794 const char *domain_name,
1797 struct dom_sid *sid,
1798 enum lsa_SidType *type)
1803 old_status = domain->online;
1805 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1806 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1812 /* If the seq number check indicated that there is a problem
1813 * with this DC, then return that status... except for
1814 * access_denied. This is special because the dc may be in
1815 * "restrict anonymous = 1" mode, in which case it will deny
1816 * most unauthenticated operations, but *will* allow the LSA
1817 * name-to-sid that we try as a fallback. */
1819 if (!(NT_STATUS_IS_OK(domain->last_status)
1820 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1821 return domain->last_status;
1823 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1826 status = domain->backend->name_to_sid(domain, mem_ctx, domain_name,
1827 name, flags, sid, type);
1829 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1830 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1831 if (!domain->internal && old_status) {
1832 set_domain_offline(domain);
1834 if (!domain->internal &&
1837 NTSTATUS cache_status;
1838 cache_status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1839 return cache_status;
1843 refresh_sequence_number(domain);
1845 if (domain->online &&
1846 (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
1847 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1849 /* Only save the reverse mapping if this was not a UPN */
1850 if (!strchr(name, '@')) {
1851 if (!strupper_m(discard_const_p(char, domain_name))) {
1852 return NT_STATUS_INVALID_PARAMETER;
1854 (void)strlower_m(discard_const_p(char, name));
1855 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1862 static NTSTATUS wcache_sid_to_name(struct winbindd_domain *domain,
1863 const struct dom_sid *sid,
1864 TALLOC_CTX *mem_ctx,
1867 enum lsa_SidType *type)
1869 struct winbind_cache *cache = get_cache(domain);
1870 struct cache_entry *centry;
1874 if (cache->tdb == NULL) {
1875 return NT_STATUS_NOT_FOUND;
1878 sid_string = sid_string_tos(sid);
1879 if (sid_string == NULL) {
1880 return NT_STATUS_NO_MEMORY;
1883 centry = wcache_fetch(cache, domain, "SN/%s", sid_string);
1884 TALLOC_FREE(sid_string);
1885 if (centry == NULL) {
1886 return NT_STATUS_NOT_FOUND;
1889 if (NT_STATUS_IS_OK(centry->status)) {
1890 *type = (enum lsa_SidType)centry_uint32(centry);
1891 *domain_name = centry_string(centry, mem_ctx);
1892 *name = centry_string(centry, mem_ctx);
1895 status = centry->status;
1896 centry_free(centry);
1898 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1899 "%s\n", domain->name, nt_errstr(status) ));
1904 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1906 NTSTATUS wb_cache_sid_to_name(struct winbindd_domain *domain,
1907 TALLOC_CTX *mem_ctx,
1908 const struct dom_sid *sid,
1911 enum lsa_SidType *type)
1916 old_status = domain->online;
1917 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
1919 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1924 *domain_name = NULL;
1926 /* If the seq number check indicated that there is a problem
1927 * with this DC, then return that status... except for
1928 * access_denied. This is special because the dc may be in
1929 * "restrict anonymous = 1" mode, in which case it will deny
1930 * most unauthenticated operations, but *will* allow the LSA
1931 * sid-to-name that we try as a fallback. */
1933 if (!(NT_STATUS_IS_OK(domain->last_status)
1934 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1935 return domain->last_status;
1937 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1940 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1942 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1943 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1944 if (!domain->internal && old_status) {
1945 set_domain_offline(domain);
1947 if (!domain->internal &&
1950 NTSTATUS cache_status;
1951 cache_status = wcache_sid_to_name(domain, sid, mem_ctx,
1952 domain_name, name, type);
1953 return cache_status;
1957 refresh_sequence_number(domain);
1958 if (!NT_STATUS_IS_OK(status)) {
1961 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1963 /* We can't save the name to sid mapping here, as with sid history a
1964 * later name2sid would give the wrong sid. */
1969 NTSTATUS wb_cache_rids_to_names(struct winbindd_domain *domain,
1970 TALLOC_CTX *mem_ctx,
1971 const struct dom_sid *domain_sid,
1976 enum lsa_SidType **types)
1978 struct winbind_cache *cache = get_cache(domain);
1980 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1985 old_status = domain->online;
1986 *domain_name = NULL;
1994 if (num_rids == 0) {
1995 return NT_STATUS_OK;
1998 *names = talloc_array(mem_ctx, char *, num_rids);
1999 *types = talloc_array(mem_ctx, enum lsa_SidType, num_rids);
2001 if ((*names == NULL) || (*types == NULL)) {
2002 result = NT_STATUS_NO_MEMORY;
2006 have_mapped = have_unmapped = false;
2008 for (i=0; i<num_rids; i++) {
2010 struct cache_entry *centry;
2013 if (!sid_compose(&sid, domain_sid, rids[i])) {
2014 result = NT_STATUS_INTERNAL_ERROR;
2018 centry = wcache_fetch(cache, domain, "SN/%s",
2019 sid_to_fstring(tmp, &sid));
2024 (*types)[i] = SID_NAME_UNKNOWN;
2025 (*names)[i] = talloc_strdup(*names, "");
2027 if (NT_STATUS_IS_OK(centry->status)) {
2030 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
2032 dom = centry_string(centry, mem_ctx);
2033 if (*domain_name == NULL) {
2039 (*names)[i] = centry_string(centry, *names);
2041 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)
2042 || NT_STATUS_EQUAL(centry->status, STATUS_SOME_UNMAPPED)) {
2043 have_unmapped = true;
2046 /* something's definitely wrong */
2047 result = centry->status;
2048 centry_free(centry);
2052 centry_free(centry);
2056 return NT_STATUS_NONE_MAPPED;
2058 if (!have_unmapped) {
2059 return NT_STATUS_OK;
2061 return STATUS_SOME_UNMAPPED;
2065 TALLOC_FREE(*names);
2066 TALLOC_FREE(*types);
2068 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
2069 rids, num_rids, domain_name,
2072 if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
2073 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2074 if (!domain->internal && old_status) {
2075 set_domain_offline(domain);
2078 !domain->internal &&
2081 have_mapped = have_unmapped = false;
2083 *names = talloc_array(mem_ctx, char *, num_rids);
2084 if (*names == NULL) {
2085 result = NT_STATUS_NO_MEMORY;
2089 *types = talloc_array(mem_ctx, enum lsa_SidType,
2091 if (*types == NULL) {
2092 result = NT_STATUS_NO_MEMORY;
2096 for (i=0; i<num_rids; i++) {
2098 struct cache_entry *centry;
2101 if (!sid_compose(&sid, domain_sid, rids[i])) {
2102 result = NT_STATUS_INTERNAL_ERROR;
2106 centry = wcache_fetch(cache, domain, "SN/%s",
2107 sid_to_fstring(tmp, &sid));
2109 (*types)[i] = SID_NAME_UNKNOWN;
2110 (*names)[i] = talloc_strdup(*names, "");
2114 (*types)[i] = SID_NAME_UNKNOWN;
2115 (*names)[i] = talloc_strdup(*names, "");
2117 if (NT_STATUS_IS_OK(centry->status)) {
2120 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
2122 dom = centry_string(centry, mem_ctx);
2123 if (*domain_name == NULL) {
2129 (*names)[i] = centry_string(centry, *names);
2131 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
2132 have_unmapped = true;
2135 /* something's definitely wrong */
2136 result = centry->status;
2137 centry_free(centry);
2141 centry_free(centry);
2145 return NT_STATUS_NONE_MAPPED;
2147 if (!have_unmapped) {
2148 return NT_STATUS_OK;
2150 return STATUS_SOME_UNMAPPED;
2154 None of the queried rids has been found so save all negative entries
2156 if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
2157 for (i = 0; i < num_rids; i++) {
2159 const char *name = "";
2160 const enum lsa_SidType type = SID_NAME_UNKNOWN;
2161 NTSTATUS status = NT_STATUS_NONE_MAPPED;
2163 if (!sid_compose(&sid, domain_sid, rids[i])) {
2164 return NT_STATUS_INTERNAL_ERROR;
2167 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2175 Some or all of the queried rids have been found.
2177 if (!NT_STATUS_IS_OK(result) &&
2178 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
2182 refresh_sequence_number(domain);
2184 for (i=0; i<num_rids; i++) {
2188 if (!sid_compose(&sid, domain_sid, rids[i])) {
2189 result = NT_STATUS_INTERNAL_ERROR;
2193 status = (*types)[i] == SID_NAME_UNKNOWN ?
2194 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
2196 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2197 (*names)[i], (*types)[i]);
2203 TALLOC_FREE(*names);
2204 TALLOC_FREE(*types);
2208 static NTSTATUS wcache_query_user(struct winbindd_domain *domain,
2209 TALLOC_CTX *mem_ctx,
2210 const struct dom_sid *user_sid,
2211 struct wbint_userinfo *info)
2213 struct winbind_cache *cache = get_cache(domain);
2214 struct cache_entry *centry = NULL;
2218 if (cache->tdb == NULL) {
2219 return NT_STATUS_NOT_FOUND;
2222 sid_string = sid_string_tos(user_sid);
2223 if (sid_string == NULL) {
2224 return NT_STATUS_NO_MEMORY;
2227 centry = wcache_fetch(cache, domain, "U/%s", sid_string);
2228 TALLOC_FREE(sid_string);
2229 if (centry == NULL) {
2230 return NT_STATUS_NOT_FOUND;
2234 * If we have an access denied cache entry and a cached info3
2235 * in the samlogon cache then do a query. This will force the
2236 * rpc back end to return the info3 data.
2239 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED) &&
2240 netsamlogon_cache_have(user_sid)) {
2241 DEBUG(10, ("query_user: cached access denied and have cached "
2243 domain->last_status = NT_STATUS_OK;
2244 centry_free(centry);
2245 return NT_STATUS_NOT_FOUND;
2248 /* if status is not ok then this is a negative hit
2249 and the rest of the data doesn't matter */
2250 status = centry->status;
2251 if (NT_STATUS_IS_OK(status)) {
2252 info->domain_name = centry_string(centry, mem_ctx);
2253 info->acct_name = centry_string(centry, mem_ctx);
2254 info->full_name = centry_string(centry, mem_ctx);
2255 info->homedir = centry_string(centry, mem_ctx);
2256 info->shell = centry_string(centry, mem_ctx);
2257 info->uid = centry_uint32(centry);
2258 info->primary_gid = centry_uint32(centry);
2259 info->primary_group_name = centry_string(centry, mem_ctx);
2260 centry_sid(centry, &info->user_sid);
2261 centry_sid(centry, &info->group_sid);
2264 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2265 "%s\n", domain->name, nt_errstr(status) ));
2267 centry_free(centry);
2273 * @brief Query a fullname from the username cache (for further gecos processing)
2275 * @param domain A pointer to the winbindd_domain struct.
2276 * @param mem_ctx The talloc context.
2277 * @param user_sid The user sid.
2278 * @param full_name A pointer to the full_name string.
2280 * @return NTSTATUS code
2282 NTSTATUS wcache_query_user_fullname(struct winbindd_domain *domain,
2283 TALLOC_CTX *mem_ctx,
2284 const struct dom_sid *user_sid,
2285 const char **full_name)
2288 struct wbint_userinfo info;
2290 status = wcache_query_user(domain, mem_ctx, user_sid, &info);
2291 if (!NT_STATUS_IS_OK(status)) {
2295 if (info.full_name != NULL) {
2296 *full_name = talloc_strdup(mem_ctx, info.full_name);
2297 if (*full_name == NULL) {
2298 return NT_STATUS_NO_MEMORY;
2302 return NT_STATUS_OK;
2305 static NTSTATUS wcache_lookup_usergroups(struct winbindd_domain *domain,
2306 TALLOC_CTX *mem_ctx,
2307 const struct dom_sid *user_sid,
2308 uint32_t *pnum_sids,
2309 struct dom_sid **psids)
2311 struct winbind_cache *cache = get_cache(domain);
2312 struct cache_entry *centry = NULL;
2314 uint32_t i, num_sids;
2315 struct dom_sid *sids;
2318 if (cache->tdb == NULL) {
2319 return NT_STATUS_NOT_FOUND;
2322 centry = wcache_fetch(cache, domain, "UG/%s",
2323 sid_to_fstring(sid_string, user_sid));
2324 if (centry == NULL) {
2325 return NT_STATUS_NOT_FOUND;
2328 /* If we have an access denied cache entry and a cached info3 in the
2329 samlogon cache then do a query. This will force the rpc back end
2330 to return the info3 data. */
2332 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)
2333 && netsamlogon_cache_have(user_sid)) {
2334 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2336 domain->last_status = NT_STATUS_OK;
2337 centry_free(centry);
2338 return NT_STATUS_NOT_FOUND;
2341 num_sids = centry_uint32(centry);
2342 sids = talloc_array(mem_ctx, struct dom_sid, num_sids);
2344 centry_free(centry);
2345 return NT_STATUS_NO_MEMORY;
2348 for (i=0; i<num_sids; i++) {
2349 centry_sid(centry, &sids[i]);
2352 status = centry->status;
2354 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2355 "status: %s\n", domain->name, nt_errstr(status)));
2357 centry_free(centry);
2359 *pnum_sids = num_sids;
2364 /* Lookup groups a user is a member of. */
2365 NTSTATUS wb_cache_lookup_usergroups(struct winbindd_domain *domain,
2366 TALLOC_CTX *mem_ctx,
2367 const struct dom_sid *user_sid,
2368 uint32_t *num_groups,
2369 struct dom_sid **user_gids)
2371 struct cache_entry *centry = NULL;
2377 old_status = domain->online;
2378 status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2379 num_groups, user_gids);
2380 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2385 (*user_gids) = NULL;
2387 /* Return status value returned by seq number check */
2389 if (!NT_STATUS_IS_OK(domain->last_status))
2390 return domain->last_status;
2392 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2395 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
2397 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2398 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2399 if (!domain->internal && old_status) {
2400 set_domain_offline(domain);
2402 if (!domain->internal &&
2405 NTSTATUS cache_status;
2406 cache_status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2407 num_groups, user_gids);
2408 return cache_status;
2411 if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
2415 refresh_sequence_number(domain);
2416 if (!NT_STATUS_IS_OK(status)) {
2419 centry = centry_start(domain, status);
2423 centry_put_uint32(centry, *num_groups);
2424 for (i=0; i<(*num_groups); i++) {
2425 centry_put_sid(centry, &(*user_gids)[i]);
2428 centry_end(centry, "UG/%s", sid_to_fstring(sid_string, user_sid));
2429 centry_free(centry);
2435 static char *wcache_make_sidlist(TALLOC_CTX *mem_ctx, uint32_t num_sids,
2436 const struct dom_sid *sids)
2441 sidlist = talloc_strdup(mem_ctx, "");
2442 if (sidlist == NULL) {
2445 for (i=0; i<num_sids; i++) {
2447 sidlist = talloc_asprintf_append_buffer(
2448 sidlist, "/%s", sid_to_fstring(tmp, &sids[i]));
2449 if (sidlist == NULL) {
2456 static NTSTATUS wcache_lookup_useraliases(struct winbindd_domain *domain,
2457 TALLOC_CTX *mem_ctx,
2459 const struct dom_sid *sids,
2460 uint32_t *pnum_aliases,
2461 uint32_t **paliases)
2463 struct winbind_cache *cache = get_cache(domain);
2464 struct cache_entry *centry = NULL;
2465 uint32_t i, num_aliases;
2470 if (cache->tdb == NULL) {
2471 return NT_STATUS_NOT_FOUND;
2474 if (num_sids == 0) {
2477 return NT_STATUS_OK;
2480 /* We need to cache indexed by the whole list of SIDs, the aliases
2481 * resulting might come from any of the SIDs. */
2483 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2484 if (sidlist == NULL) {
2485 return NT_STATUS_NO_MEMORY;
2488 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
2489 TALLOC_FREE(sidlist);
2490 if (centry == NULL) {
2491 return NT_STATUS_NOT_FOUND;
2494 num_aliases = centry_uint32(centry);
2495 aliases = talloc_array(mem_ctx, uint32_t, num_aliases);
2496 if (aliases == NULL) {
2497 centry_free(centry);
2498 return NT_STATUS_NO_MEMORY;
2501 for (i=0; i<num_aliases; i++) {
2502 aliases[i] = centry_uint32(centry);
2505 status = centry->status;
2507 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2508 "status %s\n", domain->name, nt_errstr(status)));
2510 centry_free(centry);
2512 *pnum_aliases = num_aliases;
2513 *paliases = aliases;
2518 NTSTATUS wb_cache_lookup_useraliases(struct winbindd_domain *domain,
2519 TALLOC_CTX *mem_ctx,
2521 const struct dom_sid *sids,
2522 uint32_t *num_aliases,
2523 uint32_t **alias_rids)
2525 struct cache_entry *centry = NULL;
2531 old_status = domain->online;
2532 status = wcache_lookup_useraliases(domain, mem_ctx, num_sids, sids,
2533 num_aliases, alias_rids);
2534 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2539 (*alias_rids) = NULL;
2541 if (!NT_STATUS_IS_OK(domain->last_status))
2542 return domain->last_status;
2544 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2545 "for domain %s\n", domain->name ));
2547 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2548 if (sidlist == NULL) {
2549 return NT_STATUS_NO_MEMORY;
2552 status = domain->backend->lookup_useraliases(domain, mem_ctx,
2554 num_aliases, alias_rids);
2556 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2557 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2558 if (!domain->internal && old_status) {
2559 set_domain_offline(domain);
2561 if (!domain->internal &&
2564 NTSTATUS cache_status;
2565 cache_status = wcache_lookup_useraliases(domain, mem_ctx, num_sids,
2566 sids, num_aliases, alias_rids);
2567 return cache_status;
2571 refresh_sequence_number(domain);
2572 if (!NT_STATUS_IS_OK(status)) {
2575 centry = centry_start(domain, status);
2578 centry_put_uint32(centry, *num_aliases);
2579 for (i=0; i<(*num_aliases); i++)
2580 centry_put_uint32(centry, (*alias_rids)[i]);
2581 centry_end(centry, "UA%s", sidlist);
2582 centry_free(centry);
2588 static NTSTATUS wcache_lookup_groupmem(struct winbindd_domain *domain,
2589 TALLOC_CTX *mem_ctx,
2590 const struct dom_sid *group_sid,
2591 uint32_t *num_names,
2592 struct dom_sid **sid_mem, char ***names,
2593 uint32_t **name_types)
2595 struct winbind_cache *cache = get_cache(domain);
2596 struct cache_entry *centry = NULL;
2601 if (cache->tdb == NULL) {
2602 return NT_STATUS_NOT_FOUND;
2605 sid_string = sid_string_tos(group_sid);
2606 if (sid_string == NULL) {
2607 return NT_STATUS_NO_MEMORY;
2610 centry = wcache_fetch(cache, domain, "GM/%s", sid_string);
2611 TALLOC_FREE(sid_string);
2612 if (centry == NULL) {
2613 return NT_STATUS_NOT_FOUND;
2620 *num_names = centry_uint32(centry);
2621 if (*num_names == 0) {
2622 centry_free(centry);
2623 return NT_STATUS_OK;
2626 *sid_mem = talloc_array(mem_ctx, struct dom_sid, *num_names);
2627 *names = talloc_array(mem_ctx, char *, *num_names);
2628 *name_types = talloc_array(mem_ctx, uint32_t, *num_names);
2630 if ((*sid_mem == NULL) || (*names == NULL) || (*name_types == NULL)) {
2631 TALLOC_FREE(*sid_mem);
2632 TALLOC_FREE(*names);
2633 TALLOC_FREE(*name_types);
2634 centry_free(centry);
2635 return NT_STATUS_NO_MEMORY;
2638 for (i=0; i<(*num_names); i++) {
2639 centry_sid(centry, &(*sid_mem)[i]);
2640 (*names)[i] = centry_string(centry, mem_ctx);
2641 (*name_types)[i] = centry_uint32(centry);
2644 status = centry->status;
2646 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2647 "status: %s\n", domain->name, nt_errstr(status)));
2649 centry_free(centry);
2653 NTSTATUS wb_cache_lookup_groupmem(struct winbindd_domain *domain,
2654 TALLOC_CTX *mem_ctx,
2655 const struct dom_sid *group_sid,
2656 enum lsa_SidType type,
2657 uint32_t *num_names,
2658 struct dom_sid **sid_mem,
2660 uint32_t **name_types)
2662 struct cache_entry *centry = NULL;
2668 old_status = domain->online;
2669 status = wcache_lookup_groupmem(domain, mem_ctx, group_sid, num_names,
2670 sid_mem, names, name_types);
2671 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2678 (*name_types) = NULL;
2680 /* Return status value returned by seq number check */
2682 if (!NT_STATUS_IS_OK(domain->last_status))
2683 return domain->last_status;
2685 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2688 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid,
2690 sid_mem, names, name_types);
2692 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2693 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2694 if (!domain->internal && old_status) {
2695 set_domain_offline(domain);
2697 if (!domain->internal &&
2700 NTSTATUS cache_status;
2701 cache_status = wcache_lookup_groupmem(domain, mem_ctx, group_sid,
2702 num_names, sid_mem, names,
2704 return cache_status;
2708 refresh_sequence_number(domain);
2709 if (!NT_STATUS_IS_OK(status)) {
2712 centry = centry_start(domain, status);
2715 centry_put_uint32(centry, *num_names);
2716 for (i=0; i<(*num_names); i++) {
2717 centry_put_sid(centry, &(*sid_mem)[i]);
2718 centry_put_string(centry, (*names)[i]);
2719 centry_put_uint32(centry, (*name_types)[i]);
2721 centry_end(centry, "GM/%s", sid_to_fstring(sid_string, group_sid));
2722 centry_free(centry);
2728 /* find the sequence number for a domain */
2729 NTSTATUS wb_cache_sequence_number(struct winbindd_domain *domain,
2732 refresh_sequence_number(domain);
2734 *seq = domain->sequence_number;
2736 return NT_STATUS_OK;
2739 /* enumerate trusted domains
2740 * (we need to have the list of trustdoms in the cache when we go offline) -
2742 NTSTATUS wb_cache_trusted_domains(struct winbindd_domain *domain,
2743 TALLOC_CTX *mem_ctx,
2744 struct netr_DomainTrustList *trusts)
2747 struct winbind_cache *cache;
2748 struct winbindd_tdc_domain *dom_list = NULL;
2749 size_t num_domains = 0;
2750 bool retval = false;
2754 old_status = domain->online;
2756 trusts->array = NULL;
2758 cache = get_cache(domain);
2759 if (!cache || !cache->tdb) {
2763 if (domain->online) {
2767 retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2768 if (!retval || !num_domains || !dom_list) {
2769 TALLOC_FREE(dom_list);
2774 trusts->array = talloc_zero_array(mem_ctx, struct netr_DomainTrust, num_domains);
2775 if (!trusts->array) {
2776 TALLOC_FREE(dom_list);
2777 return NT_STATUS_NO_MEMORY;
2780 for (i = 0; i < num_domains; i++) {
2781 struct netr_DomainTrust *trust;
2782 struct dom_sid *sid;
2783 struct winbindd_domain *dom;
2785 dom = find_domain_from_name_noinit(dom_list[i].domain_name);
2786 if (dom && dom->internal) {
2790 trust = &trusts->array[trusts->count];
2791 trust->netbios_name = talloc_strdup(trusts->array, dom_list[i].domain_name);
2792 trust->dns_name = talloc_strdup(trusts->array, dom_list[i].dns_name);
2793 sid = talloc(trusts->array, struct dom_sid);
2794 if (!trust->netbios_name || !trust->dns_name ||
2796 TALLOC_FREE(dom_list);
2797 TALLOC_FREE(trusts->array);
2798 return NT_STATUS_NO_MEMORY;
2801 trust->trust_flags = dom_list[i].trust_flags;
2802 trust->trust_attributes = dom_list[i].trust_attribs;
2803 trust->trust_type = dom_list[i].trust_type;
2804 sid_copy(sid, &dom_list[i].sid);
2809 TALLOC_FREE(dom_list);
2810 return NT_STATUS_OK;
2813 /* Return status value returned by seq number check */
2815 if (!NT_STATUS_IS_OK(domain->last_status))
2816 return domain->last_status;
2818 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2821 status = domain->backend->trusted_domains(domain, mem_ctx, trusts);
2823 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2824 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2825 if (!domain->internal && old_status) {
2826 set_domain_offline(domain);
2828 if (!domain->internal &&
2831 retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2832 if (retval && num_domains && dom_list) {
2833 TALLOC_FREE(trusts->array);
2835 goto do_fetch_cache;
2839 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2840 * so that the generic centry handling still applies correctly -
2843 if (!NT_STATUS_IS_ERR(status)) {
2844 status = NT_STATUS_OK;
2849 /* get lockout policy */
2850 NTSTATUS wb_cache_lockout_policy(struct winbindd_domain *domain,
2851 TALLOC_CTX *mem_ctx,
2852 struct samr_DomInfo12 *policy)
2854 struct winbind_cache *cache = get_cache(domain);
2855 struct cache_entry *centry = NULL;
2859 old_status = domain->online;
2863 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2869 policy->lockout_duration = centry_nttime(centry);
2870 policy->lockout_window = centry_nttime(centry);
2871 policy->lockout_threshold = centry_uint16(centry);
2873 status = centry->status;
2875 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2876 domain->name, nt_errstr(status) ));
2878 centry_free(centry);
2882 ZERO_STRUCTP(policy);
2884 /* Return status value returned by seq number check */
2886 if (!NT_STATUS_IS_OK(domain->last_status))
2887 return domain->last_status;
2889 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2892 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2894 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2895 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2896 if (!domain->internal && old_status) {
2897 set_domain_offline(domain);
2900 !domain->internal &&
2903 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2905 goto do_fetch_cache;
2910 refresh_sequence_number(domain);
2911 if (!NT_STATUS_IS_OK(status)) {
2914 wcache_save_lockout_policy(domain, status, policy);
2919 /* get password policy */
2920 NTSTATUS wb_cache_password_policy(struct winbindd_domain *domain,
2921 TALLOC_CTX *mem_ctx,
2922 struct samr_DomInfo1 *policy)
2924 struct winbind_cache *cache = get_cache(domain);
2925 struct cache_entry *centry = NULL;
2929 old_status = domain->online;
2933 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2939 policy->min_password_length = centry_uint16(centry);
2940 policy->password_history_length = centry_uint16(centry);
2941 policy->password_properties = centry_uint32(centry);
2942 policy->max_password_age = centry_nttime(centry);
2943 policy->min_password_age = centry_nttime(centry);
2945 status = centry->status;
2947 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2948 domain->name, nt_errstr(status) ));
2950 centry_free(centry);
2954 ZERO_STRUCTP(policy);
2956 /* Return status value returned by seq number check */
2958 if (!NT_STATUS_IS_OK(domain->last_status))
2959 return domain->last_status;
2961 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2964 status = domain->backend->password_policy(domain, mem_ctx, policy);
2966 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2967 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2968 if (!domain->internal && old_status) {
2969 set_domain_offline(domain);
2972 !domain->internal &&
2975 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2977 goto do_fetch_cache;
2982 refresh_sequence_number(domain);
2983 if (!NT_STATUS_IS_OK(status)) {
2986 wcache_save_password_policy(domain, status, policy);
2992 /* Invalidate cached user and group lists coherently */
2994 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2997 if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
2998 strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
2999 tdb_delete(the_tdb, kbuf);
3004 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3006 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
3007 const struct dom_sid *sid)
3009 fstring key_str, sid_string;
3010 struct winbind_cache *cache;
3012 /* don't clear cached U/SID and UG/SID entries when we want to logon
3015 if (lp_winbind_offline_logon()) {
3022 cache = get_cache(domain);
3028 /* Clear U/SID cache entry */
3029 fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, sid));
3030 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
3031 tdb_delete(cache->tdb, string_tdb_data(key_str));
3033 /* Clear UG/SID cache entry */
3034 fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, sid));
3035 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
3036 tdb_delete(cache->tdb, string_tdb_data(key_str));
3038 /* Samba/winbindd never needs this. */
3039 netsamlogon_clear_cached_user(sid);
3042 bool wcache_invalidate_cache(void)
3044 struct winbindd_domain *domain;
3046 for (domain = domain_list(); domain; domain = domain->next) {
3047 struct winbind_cache *cache = get_cache(domain);
3049 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3050 "entries for %s\n", domain->name));
3053 tdb_traverse(cache->tdb, traverse_fn, NULL);
3062 bool wcache_invalidate_cache_noinit(void)
3064 struct winbindd_domain *domain;
3066 for (domain = domain_list(); domain; domain = domain->next) {
3067 struct winbind_cache *cache;
3069 /* Skip uninitialized domains. */
3070 if (!domain->initialized && !domain->internal) {
3074 cache = get_cache(domain);
3076 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3077 "entries for %s\n", domain->name));
3080 tdb_traverse(cache->tdb, traverse_fn, NULL);
3082 * Flushing cache has nothing to with domains.
3083 * return here if we successfully flushed once.
3084 * To avoid unnecessary traversing the cache.
3095 static bool init_wcache(void)
3099 if (wcache == NULL) {
3100 wcache = SMB_XMALLOC_P(struct winbind_cache);
3101 ZERO_STRUCTP(wcache);
3104 if (wcache->tdb != NULL)
3107 db_path = wcache_path();
3108 if (db_path == NULL) {
3112 /* when working offline we must not clear the cache on restart */
3113 wcache->tdb = tdb_open_log(db_path,
3114 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3115 TDB_INCOMPATIBLE_HASH |
3116 (lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
3117 O_RDWR|O_CREAT, 0600);
3118 TALLOC_FREE(db_path);
3119 if (wcache->tdb == NULL) {
3120 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3127 /************************************************************************
3128 This is called by the parent to initialize the cache file.
3129 We don't need sophisticated locking here as we know we're the
3131 ************************************************************************/
3133 bool initialize_winbindd_cache(void)
3135 bool cache_bad = true;
3138 if (!init_wcache()) {
3139 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3143 /* Check version number. */
3144 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
3145 vers == WINBINDD_CACHE_VERSION) {
3152 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3153 "and re-creating with version number %d\n",
3154 WINBINDD_CACHE_VERSION ));
3156 tdb_close(wcache->tdb);
3159 db_path = wcache_path();
3160 if (db_path == NULL) {
3164 if (unlink(db_path) == -1) {
3165 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3168 TALLOC_FREE(db_path);
3171 TALLOC_FREE(db_path);
3172 if (!init_wcache()) {
3173 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3174 "init_wcache failed.\n"));
3178 /* Write the version. */
3179 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
3180 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3181 tdb_errorstr(wcache->tdb) ));
3186 tdb_close(wcache->tdb);
3191 void close_winbindd_cache(void)
3197 tdb_close(wcache->tdb);
3202 bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
3203 char **domain_name, char **name,
3204 enum lsa_SidType *type)
3206 struct winbindd_domain *domain;
3209 domain = find_lookup_domain_from_sid(sid);
3210 if (domain == NULL) {
3213 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
3215 return NT_STATUS_IS_OK(status);
3218 bool lookup_cached_name(const char *domain_name,
3220 struct dom_sid *sid,
3221 enum lsa_SidType *type)
3223 struct winbindd_domain *domain;
3225 bool original_online_state;
3227 domain = find_lookup_domain_from_name(domain_name);
3228 if (domain == NULL) {
3232 /* If we are doing a cached logon, temporarily set the domain
3233 offline so the cache won't expire the entry */
3235 original_online_state = domain->online;
3236 domain->online = false;
3237 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
3238 domain->online = original_online_state;
3240 return NT_STATUS_IS_OK(status);
3244 * Cache a name to sid without checking the sequence number.
3245 * Used when caching from a trusted PAC.
3248 void cache_name2sid_trusted(struct winbindd_domain *domain,
3249 const char *domain_name,
3251 enum lsa_SidType type,
3252 const struct dom_sid *sid)
3255 * Ensure we store the mapping with the
3256 * existing sequence number from the cache.
3259 (void)fetch_cache_seqnum(domain, time(NULL));
3260 wcache_save_name_to_sid(domain,
3268 void cache_name2sid(struct winbindd_domain *domain,
3269 const char *domain_name, const char *name,
3270 enum lsa_SidType type, const struct dom_sid *sid)
3272 refresh_sequence_number(domain);
3273 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
3278 * The original idea that this cache only contains centries has
3279 * been blurred - now other stuff gets put in here. Ensure we
3280 * ignore these things on cleanup.
3283 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
3284 TDB_DATA dbuf, void *state)
3286 struct cache_entry *centry;
3288 if (is_non_centry_key(kbuf)) {
3292 centry = wcache_fetch_raw((char *)kbuf.dptr);
3297 if (!NT_STATUS_IS_OK(centry->status)) {
3298 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
3299 tdb_delete(the_tdb, kbuf);
3302 centry_free(centry);
3306 /* flush the cache */
3307 static void wcache_flush_cache(void)
3314 tdb_close(wcache->tdb);
3317 if (!winbindd_use_cache()) {
3321 db_path = wcache_path();
3322 if (db_path == NULL) {
3326 /* when working offline we must not clear the cache on restart */
3327 wcache->tdb = tdb_open_log(db_path,
3328 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3329 TDB_INCOMPATIBLE_HASH |
3330 (lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
3331 O_RDWR|O_CREAT, 0600);
3332 TALLOC_FREE(db_path);
3334 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3338 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
3340 DEBUG(10,("wcache_flush_cache success\n"));
3343 /* Count cached creds */
3345 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3348 int *cred_count = (int*)state;
3350 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3356 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
3358 struct winbind_cache *cache = get_cache(domain);
3363 return NT_STATUS_INTERNAL_DB_ERROR;
3366 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
3368 return NT_STATUS_OK;
3372 struct cred_list *prev, *next;
3377 static struct cred_list *wcache_cred_list;
3379 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3382 struct cred_list *cred;
3384 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3386 cred = SMB_MALLOC_P(struct cred_list);
3388 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3394 /* save a copy of the key */
3396 fstrcpy(cred->name, (const char *)kbuf.dptr);
3397 DLIST_ADD(wcache_cred_list, cred);
3403 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const struct dom_sid *sid)
3405 struct winbind_cache *cache = get_cache(domain);
3408 struct cred_list *cred, *next, *oldest = NULL;
3411 return NT_STATUS_INTERNAL_DB_ERROR;
3414 /* we possibly already have an entry */
3415 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
3417 fstring key_str, tmp;
3419 DEBUG(11,("we already have an entry, deleting that\n"));
3421 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
3423 tdb_delete(cache->tdb, string_tdb_data(key_str));
3425 return NT_STATUS_OK;
3428 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
3430 return NT_STATUS_OK;
3431 } else if ((ret < 0) || (wcache_cred_list == NULL)) {
3432 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3435 ZERO_STRUCTP(oldest);
3437 for (cred = wcache_cred_list; cred; cred = cred->next) {
3442 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
3444 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3446 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
3450 t = IVAL(data.dptr, 0);
3451 SAFE_FREE(data.dptr);
3454 oldest = SMB_MALLOC_P(struct cred_list);
3455 if (oldest == NULL) {
3456 status = NT_STATUS_NO_MEMORY;
3460 fstrcpy(oldest->name, cred->name);
3461 oldest->created = t;
3465 if (t < oldest->created) {
3466 fstrcpy(oldest->name, cred->name);
3467 oldest->created = t;
3471 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
3472 status = NT_STATUS_OK;
3474 status = NT_STATUS_UNSUCCESSFUL;
3477 for (cred = wcache_cred_list; cred; cred = next) {
3479 DLIST_REMOVE(wcache_cred_list, cred);
3487 /* Change the global online/offline state. */
3488 bool set_global_winbindd_state_offline(void)
3492 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3494 /* Only go offline if someone has created
3495 the key "WINBINDD_OFFLINE" in the cache tdb. */
3497 if (wcache == NULL || wcache->tdb == NULL) {
3498 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3502 if (!lp_winbind_offline_logon()) {
3503 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3507 if (global_winbindd_offline_state) {
3508 /* Already offline. */
3512 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
3514 if (!data.dptr || data.dsize != 4) {
3515 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3516 SAFE_FREE(data.dptr);
3519 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3520 global_winbindd_offline_state = true;
3521 SAFE_FREE(data.dptr);
3526 void set_global_winbindd_state_online(void)
3528 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3530 if (!lp_winbind_offline_logon()) {
3531 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3535 if (!global_winbindd_offline_state) {
3536 /* Already online. */
3539 global_winbindd_offline_state = false;
3545 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3546 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
3549 bool get_global_winbindd_state_offline(void)
3551 return global_winbindd_offline_state;
3554 /***********************************************************************
3555 Validate functions for all possible cache tdb keys.
3556 ***********************************************************************/
3558 static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
3559 struct tdb_validation_status *state)
3561 struct cache_entry *centry;
3563 centry = SMB_XMALLOC_P(struct cache_entry);
3564 centry->data = (unsigned char *)smb_memdup(data.dptr, data.dsize);
3565 if (!centry->data) {
3569 centry->len = data.dsize;
3572 if (centry->len < 16) {
3573 /* huh? corrupt cache? */
3574 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3575 "(len < 16) ?\n", kstr));
3576 centry_free(centry);
3577 state->bad_entry = true;
3578 state->success = false;
3582 centry->status = NT_STATUS(centry_uint32(centry));
3583 centry->sequence_number = centry_uint32(centry);
3584 centry->timeout = centry_uint64_t(centry);
3588 static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3589 struct tdb_validation_status *state)
3591 if (dbuf.dsize != 8) {
3592 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3593 keystr, (unsigned int)dbuf.dsize ));
3594 state->bad_entry = true;
3600 static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3601 struct tdb_validation_status *state)
3603 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3608 (void)centry_uint32(centry);
3609 if (NT_STATUS_IS_OK(centry->status)) {
3611 (void)centry_sid(centry, &sid);
3614 centry_free(centry);
3616 if (!(state->success)) {
3619 DEBUG(10,("validate_ns: %s ok\n", keystr));
3623 static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3624 struct tdb_validation_status *state)
3626 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3631 if (NT_STATUS_IS_OK(centry->status)) {
3632 (void)centry_uint32(centry);
3633 (void)centry_string(centry, mem_ctx);
3634 (void)centry_string(centry, mem_ctx);
3637 centry_free(centry);
3639 if (!(state->success)) {
3642 DEBUG(10,("validate_sn: %s ok\n", keystr));
3646 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3647 struct tdb_validation_status *state)
3649 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3656 (void)centry_string(centry, mem_ctx);
3657 (void)centry_string(centry, mem_ctx);
3658 (void)centry_string(centry, mem_ctx);
3659 (void)centry_string(centry, mem_ctx);
3660 (void)centry_string(centry, mem_ctx);
3661 (void)centry_uint32(centry);
3662 (void)centry_uint32(centry);
3663 (void)centry_string(centry, mem_ctx);
3664 (void)centry_sid(centry, &sid);
3665 (void)centry_sid(centry, &sid);
3667 centry_free(centry);
3669 if (!(state->success)) {
3672 DEBUG(10,("validate_u: %s ok\n", keystr));
3676 static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3677 struct tdb_validation_status *state)
3679 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3685 (void)centry_nttime(centry);
3686 (void)centry_nttime(centry);
3687 (void)centry_uint16(centry);
3689 centry_free(centry);
3691 if (!(state->success)) {
3694 DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
3698 static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3699 struct tdb_validation_status *state)
3701 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3707 (void)centry_uint16(centry);
3708 (void)centry_uint16(centry);
3709 (void)centry_uint32(centry);
3710 (void)centry_nttime(centry);
3711 (void)centry_nttime(centry);
3713 centry_free(centry);
3715 if (!(state->success)) {
3718 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
3722 static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3723 struct tdb_validation_status *state)
3725 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3731 (void)centry_time(centry);
3732 (void)centry_hash16(centry, mem_ctx);
3734 /* We only have 17 bytes more data in the salted cred case. */
3735 if (centry->len - centry->ofs == 17) {
3736 (void)centry_hash16(centry, mem_ctx);
3739 centry_free(centry);
3741 if (!(state->success)) {
3744 DEBUG(10,("validate_cred: %s ok\n", keystr));
3748 static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3749 struct tdb_validation_status *state)
3751 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3752 int32_t num_entries, i;
3758 num_entries = (int32_t)centry_uint32(centry);
3760 for (i=0; i< num_entries; i++) {
3761 (void)centry_uint32(centry);
3764 centry_free(centry);
3766 if (!(state->success)) {
3769 DEBUG(10,("validate_ul: %s ok\n", keystr));
3773 static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3774 struct tdb_validation_status *state)
3776 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3777 int32_t num_entries, i;
3783 num_entries = centry_uint32(centry);
3785 for (i=0; i< num_entries; i++) {
3786 (void)centry_string(centry, mem_ctx);
3787 (void)centry_string(centry, mem_ctx);
3788 (void)centry_uint32(centry);
3791 centry_free(centry);
3793 if (!(state->success)) {
3796 DEBUG(10,("validate_gl: %s ok\n", keystr));
3800 static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3801 struct tdb_validation_status *state)
3803 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3804 int32_t num_groups, i;
3810 num_groups = centry_uint32(centry);
3812 for (i=0; i< num_groups; i++) {
3814 centry_sid(centry, &sid);
3817 centry_free(centry);
3819 if (!(state->success)) {
3822 DEBUG(10,("validate_ug: %s ok\n", keystr));
3826 static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3827 struct tdb_validation_status *state)
3829 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3830 int32_t num_aliases, i;
3836 num_aliases = centry_uint32(centry);
3838 for (i=0; i < num_aliases; i++) {
3839 (void)centry_uint32(centry);
3842 centry_free(centry);
3844 if (!(state->success)) {
3847 DEBUG(10,("validate_ua: %s ok\n", keystr));
3851 static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3852 struct tdb_validation_status *state)
3854 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3855 int32_t num_names, i;
3861 num_names = centry_uint32(centry);
3863 for (i=0; i< num_names; i++) {
3865 centry_sid(centry, &sid);
3866 (void)centry_string(centry, mem_ctx);
3867 (void)centry_uint32(centry);
3870 centry_free(centry);
3872 if (!(state->success)) {
3875 DEBUG(10,("validate_gm: %s ok\n", keystr));
3879 static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3880 struct tdb_validation_status *state)
3882 /* Can't say anything about this other than must be nonzero. */
3883 if (dbuf.dsize == 0) {
3884 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3886 state->bad_entry = true;
3887 state->success = false;
3891 DEBUG(10,("validate_dr: %s ok\n", keystr));
3895 static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3896 struct tdb_validation_status *state)
3898 /* Can't say anything about this other than must be nonzero. */
3899 if (dbuf.dsize == 0) {
3900 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3902 state->bad_entry = true;
3903 state->success = false;
3907 DEBUG(10,("validate_de: %s ok\n", keystr));
3911 static int validate_nss_an(TALLOC_CTX *mem_ctx, const char *keystr,
3913 struct tdb_validation_status *state)
3915 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3921 (void)centry_string( centry, mem_ctx );
3923 centry_free(centry);
3925 if (!(state->success)) {
3928 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3932 static int validate_nss_na(TALLOC_CTX *mem_ctx, const char *keystr,
3934 struct tdb_validation_status *state)
3936 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3942 (void)centry_string( centry, mem_ctx );
3944 centry_free(centry);
3946 if (!(state->success)) {
3949 DBG_DEBUG("%s ok\n", keystr);
3953 static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
3955 struct tdb_validation_status *state)
3957 if (dbuf.dsize == 0) {
3958 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3959 "key %s (len ==0) ?\n", keystr));
3960 state->bad_entry = true;
3961 state->success = false;
3965 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
3966 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3970 static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3971 struct tdb_validation_status *state)
3973 if (dbuf.dsize != 4) {
3974 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3975 keystr, (unsigned int)dbuf.dsize ));
3976 state->bad_entry = true;
3977 state->success = false;
3980 DEBUG(10,("validate_offline: %s ok\n", keystr));
3984 static int validate_ndr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3985 struct tdb_validation_status *state)
3988 * Ignore validation for now. The proper way to do this is with a
3989 * checksum. Just pure parsing does not really catch much.
3994 static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3995 struct tdb_validation_status *state)
3997 if (dbuf.dsize != 4) {
3998 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3999 "key %s (len %u != 4) ?\n",
4000 keystr, (unsigned int)dbuf.dsize));
4001 state->bad_entry = true;
4002 state->success = false;
4006 DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
4010 /***********************************************************************
4011 A list of all possible cache tdb keys with associated validation
4013 ***********************************************************************/
4015 struct key_val_struct {
4016 const char *keyname;
4017 int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
4019 {"SEQNUM/", validate_seqnum},
4020 {"NS/", validate_ns},
4021 {"SN/", validate_sn},
4023 {"LOC_POL/", validate_loc_pol},
4024 {"PWD_POL/", validate_pwd_pol},
4025 {"CRED/", validate_cred},
4026 {"UL/", validate_ul},
4027 {"GL/", validate_gl},
4028 {"UG/", validate_ug},
4029 {"UA", validate_ua},
4030 {"GM/", validate_gm},
4031 {"DR/", validate_dr},
4032 {"DE/", validate_de},
4033 {"TRUSTDOMCACHE/", validate_trustdomcache},
4034 {"NSS/NA/", validate_nss_na},
4035 {"NSS/AN/", validate_nss_an},
4036 {"WINBINDD_OFFLINE", validate_offline},
4037 {"NDR/", validate_ndr},
4038 {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
4042 /***********************************************************************
4043 Function to look at every entry in the tdb and validate it as far as
4045 ***********************************************************************/
4047 static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
4050 unsigned int max_key_len = 1024;
4051 struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
4053 /* Paranoia check. */
4054 if (strncmp("UA/", (const char *)kbuf.dptr, 3) == 0 ||
4055 strncmp("NDR/", (const char *)kbuf.dptr, 4) == 0) {
4056 max_key_len = 1024 * 1024;
4058 if (kbuf.dsize > max_key_len) {
4059 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4061 (unsigned int)kbuf.dsize, (unsigned int)max_key_len));
4065 for (i = 0; key_val[i].keyname; i++) {
4066 size_t namelen = strlen(key_val[i].keyname);
4067 if (kbuf.dsize >= namelen && (
4068 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
4069 TALLOC_CTX *mem_ctx;
4073 keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
4077 memcpy(keystr, kbuf.dptr, kbuf.dsize);
4078 keystr[kbuf.dsize] = '\0';
4080 mem_ctx = talloc_init("validate_ctx");
4086 ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
4090 talloc_destroy(mem_ctx);
4095 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4096 dump_data(0, (uint8_t *)kbuf.dptr, kbuf.dsize);
4097 DEBUG(0,("data :\n"));
4098 dump_data(0, (uint8_t *)dbuf.dptr, dbuf.dsize);
4099 v_state->unknown_key = true;
4100 v_state->success = false;
4101 return 1; /* terminate. */
4104 static void validate_panic(const char *const why)
4106 DEBUG(0,("validating cache: would panic %s\n", why ));
4107 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4111 static int wbcache_update_centry_fn(TDB_CONTEXT *tdb,
4119 if (is_non_centry_key(key)) {
4123 if (data.dptr == NULL || data.dsize == 0) {
4124 if (tdb_delete(tdb, key) < 0) {
4125 DEBUG(0, ("tdb_delete for [%s] failed!\n",
4131 /* add timeout to blob (uint64_t) */
4132 blob.dsize = data.dsize + 8;
4134 blob.dptr = SMB_XMALLOC_ARRAY(uint8_t, blob.dsize);
4135 if (blob.dptr == NULL) {
4138 memset(blob.dptr, 0, blob.dsize);
4140 /* copy status and seqnum */
4141 memcpy(blob.dptr, data.dptr, 8);
4144 ctimeout = lp_winbind_cache_time() + time(NULL);
4145 SBVAL(blob.dptr, 8, ctimeout);
4148 memcpy(blob.dptr + 16, data.dptr + 8, data.dsize - 8);
4150 if (tdb_store(tdb, key, blob, TDB_REPLACE) < 0) {
4151 DEBUG(0, ("tdb_store to update [%s] failed!\n",
4153 SAFE_FREE(blob.dptr);
4157 SAFE_FREE(blob.dptr);
4161 static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT *tdb)
4165 DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
4167 rc = tdb_traverse(tdb, wbcache_update_centry_fn, NULL);
4175 /***********************************************************************
4176 Try and validate every entry in the winbindd cache. If we fail here,
4177 delete the cache tdb and return non-zero.
4178 ***********************************************************************/
4180 int winbindd_validate_cache(void)
4183 char *tdb_path = NULL;
4184 TDB_CONTEXT *tdb = NULL;
4188 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4189 smb_panic_fn = validate_panic;
4191 tdb_path = wcache_path();
4192 if (tdb_path == NULL) {
4196 tdb = tdb_open_log(tdb_path,
4197 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
4198 TDB_INCOMPATIBLE_HASH |
4199 ( lp_winbind_offline_logon()
4201 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
4205 DEBUG(0, ("winbindd_validate_cache: "
4206 "error opening/initializing tdb\n"));
4210 /* Version check and upgrade code. */
4211 if (!tdb_fetch_uint32(tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers_id)) {
4212 DEBUG(10, ("Fresh database\n"));
4213 tdb_store_uint32(tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION);
4214 vers_id = WINBINDD_CACHE_VERSION;
4217 if (vers_id != WINBINDD_CACHE_VERSION) {
4218 if (vers_id == WINBINDD_CACHE_VER1) {
4219 ok = wbcache_upgrade_v1_to_v2(tdb);
4221 DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
4226 tdb_store_uint32(tdb,
4227 WINBINDD_CACHE_VERSION_KEYSTR,
4228 WINBINDD_CACHE_VERSION);
4229 vers_id = WINBINDD_CACHE_VER2;
4235 ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
4238 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4239 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
4244 TALLOC_FREE(tdb_path);
4245 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4246 smb_panic_fn = smb_panic;
4250 /***********************************************************************
4251 Try and validate every entry in the winbindd cache.
4252 ***********************************************************************/
4254 int winbindd_validate_cache_nobackup(void)
4259 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4260 smb_panic_fn = validate_panic;
4262 tdb_path = wcache_path();
4263 if (tdb_path == NULL) {
4264 goto err_panic_restore;
4267 if (wcache == NULL || wcache->tdb == NULL) {
4268 ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
4270 ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
4274 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4278 TALLOC_FREE(tdb_path);
4280 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4282 smb_panic_fn = smb_panic;
4286 bool winbindd_cache_validate_and_initialize(void)
4288 close_winbindd_cache();
4290 if (lp_winbind_offline_logon()) {
4291 if (winbindd_validate_cache() < 0) {
4292 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4293 "could be restored.\n"));
4297 return initialize_winbindd_cache();
4300 /*********************************************************************
4301 ********************************************************************/
4303 static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
4304 struct winbindd_tdc_domain **domains,
4305 size_t *num_domains )
4307 struct winbindd_tdc_domain *list = NULL;
4309 bool set_only = false;
4311 /* don't allow duplicates */
4316 for ( i=0; i< (*num_domains); i++ ) {
4317 if ( strequal( new_dom->name, list[i].domain_name ) ) {
4318 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4329 list = talloc_array( NULL, struct winbindd_tdc_domain, 1 );
4332 list = talloc_realloc( *domains, *domains,
4333 struct winbindd_tdc_domain,
4338 ZERO_STRUCT( list[idx] );
4344 list[idx].domain_name = talloc_strdup(list, new_dom->name);
4345 if (list[idx].domain_name == NULL) {
4348 if (new_dom->alt_name != NULL) {
4349 list[idx].dns_name = talloc_strdup(list, new_dom->alt_name);
4350 if (list[idx].dns_name == NULL) {
4355 if ( !is_null_sid( &new_dom->sid ) ) {
4356 sid_copy( &list[idx].sid, &new_dom->sid );
4358 sid_copy(&list[idx].sid, &global_sid_NULL);
4361 if ( new_dom->domain_flags != 0x0 )
4362 list[idx].trust_flags = new_dom->domain_flags;
4364 if ( new_dom->domain_type != 0x0 )
4365 list[idx].trust_type = new_dom->domain_type;
4367 if ( new_dom->domain_trust_attribs != 0x0 )
4368 list[idx].trust_attribs = new_dom->domain_trust_attribs;
4372 *num_domains = idx + 1;
4378 /*********************************************************************
4379 ********************************************************************/
4381 static TDB_DATA make_tdc_key( const char *domain_name )
4383 char *keystr = NULL;
4384 TDB_DATA key = { NULL, 0 };
4386 if ( !domain_name ) {
4387 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4391 if (asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name ) == -1) {
4394 key = string_term_tdb_data(keystr);
4399 /*********************************************************************
4400 ********************************************************************/
4402 static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
4404 unsigned char **buf )
4406 unsigned char *buffer = NULL;
4411 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4419 /* Store the number of array items first */
4420 len += tdb_pack( buffer+len, buflen-len, "d",
4423 /* now pack each domain trust record */
4424 for ( i=0; i<num_domains; i++ ) {
4429 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4430 domains[i].domain_name,
4431 domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
4434 len += tdb_pack( buffer+len, buflen-len, "fffddd",
4435 domains[i].domain_name,
4436 domains[i].dns_name ? domains[i].dns_name : "",
4437 sid_to_fstring(tmp, &domains[i].sid),
4438 domains[i].trust_flags,
4439 domains[i].trust_attribs,
4440 domains[i].trust_type );
4443 if ( buflen < len ) {
4445 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
4446 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4460 /*********************************************************************
4461 ********************************************************************/
4463 static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
4464 struct winbindd_tdc_domain **domains )
4466 fstring domain_name, dns_name, sid_string;
4467 uint32_t type, attribs, flags;
4471 struct winbindd_tdc_domain *list = NULL;
4473 /* get the number of domains */
4474 len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
4476 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4480 list = talloc_array( NULL, struct winbindd_tdc_domain, num_domains );
4482 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4486 for ( i=0; i<num_domains; i++ ) {
4489 this_len = tdb_unpack( buf+len, buflen-len, "fffddd",
4497 if ( this_len == -1 ) {
4498 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4499 TALLOC_FREE( list );
4504 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4505 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4506 domain_name, dns_name, sid_string,
4507 flags, attribs, type));
4509 list[i].domain_name = talloc_strdup( list, domain_name );
4510 list[i].dns_name = NULL;
4511 if (dns_name[0] != '\0') {
4512 list[i].dns_name = talloc_strdup(list, dns_name);
4514 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
4515 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4518 list[i].trust_flags = flags;
4519 list[i].trust_attribs = attribs;
4520 list[i].trust_type = type;
4528 /*********************************************************************
4529 ********************************************************************/
4531 static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
4533 TDB_DATA key = make_tdc_key( lp_workgroup() );
4534 TDB_DATA data = { NULL, 0 };
4540 /* See if we were asked to delete the cache entry */
4543 ret = tdb_delete( wcache->tdb, key );
4547 data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
4554 ret = tdb_store( wcache->tdb, key, data, 0 );
4557 SAFE_FREE( data.dptr );
4558 SAFE_FREE( key.dptr );
4560 return ( ret == 0 );
4563 /*********************************************************************
4564 ********************************************************************/
4566 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
4568 TDB_DATA key = make_tdc_key( lp_workgroup() );
4569 TDB_DATA data = { NULL, 0 };
4577 data = tdb_fetch( wcache->tdb, key );
4579 SAFE_FREE( key.dptr );
4584 *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
4586 SAFE_FREE( data.dptr );
4594 /*********************************************************************
4595 ********************************************************************/
4597 bool wcache_tdc_add_domain( struct winbindd_domain *domain )
4599 struct winbindd_tdc_domain *dom_list = NULL;
4600 size_t num_domains = 0;
4603 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4604 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4605 domain->name, domain->alt_name,
4606 sid_string_dbg(&domain->sid),
4607 domain->domain_flags,
4608 domain->domain_trust_attribs,
4609 domain->domain_type));
4611 if ( !init_wcache() ) {
4615 /* fetch the list */
4617 wcache_tdc_fetch_list( &dom_list, &num_domains );
4619 /* add the new domain */
4621 if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
4625 /* pack the domain */
4627 if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
4635 TALLOC_FREE( dom_list );
4640 static struct winbindd_tdc_domain *wcache_tdc_dup_domain(
4641 TALLOC_CTX *mem_ctx, const struct winbindd_tdc_domain *src)
4643 struct winbindd_tdc_domain *dst;
4645 dst = talloc(mem_ctx, struct winbindd_tdc_domain);
4649 dst->domain_name = talloc_strdup(dst, src->domain_name);
4650 if (dst->domain_name == NULL) {
4654 dst->dns_name = NULL;
4655 if (src->dns_name != NULL) {
4656 dst->dns_name = talloc_strdup(dst, src->dns_name);
4657 if (dst->dns_name == NULL) {
4662 sid_copy(&dst->sid, &src->sid);
4663 dst->trust_flags = src->trust_flags;
4664 dst->trust_type = src->trust_type;
4665 dst->trust_attribs = src->trust_attribs;
4672 /*********************************************************************
4673 ********************************************************************/
4675 struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
4677 struct winbindd_tdc_domain *dom_list = NULL;
4678 size_t num_domains = 0;
4680 struct winbindd_tdc_domain *d = NULL;
4682 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
4684 if ( !init_wcache() ) {
4688 /* fetch the list */
4690 wcache_tdc_fetch_list( &dom_list, &num_domains );
4692 for ( i=0; i<num_domains; i++ ) {
4693 if ( strequal(name, dom_list[i].domain_name) ||
4694 strequal(name, dom_list[i].dns_name) )
4696 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4699 d = wcache_tdc_dup_domain(ctx, &dom_list[i]);
4704 TALLOC_FREE( dom_list );
4709 /*********************************************************************
4710 ********************************************************************/
4712 void wcache_tdc_clear( void )
4714 if ( !init_wcache() )
4717 wcache_tdc_store_list( NULL, 0 );
4722 static bool wcache_ndr_key(TALLOC_CTX *mem_ctx, const char *domain_name,
4723 uint32_t opnum, const DATA_BLOB *req,
4729 key = talloc_asprintf(mem_ctx, "NDR/%s/%d/", domain_name, (int)opnum);
4733 keylen = talloc_get_size(key) - 1;
4735 key = talloc_realloc(mem_ctx, key, char, keylen + req->length);
4739 memcpy(key + keylen, req->data, req->length);
4741 pkey->dptr = (uint8_t *)key;
4742 pkey->dsize = talloc_get_size(key);
4746 static bool wcache_opnum_cacheable(uint32_t opnum)
4749 case NDR_WBINT_PING:
4750 case NDR_WBINT_QUERYSEQUENCENUMBER:
4751 case NDR_WBINT_ALLOCATEUID:
4752 case NDR_WBINT_ALLOCATEGID:
4753 case NDR_WBINT_CHECKMACHINEACCOUNT:
4754 case NDR_WBINT_CHANGEMACHINEACCOUNT:
4755 case NDR_WBINT_PINGDC:
4761 bool wcache_fetch_ndr(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
4762 uint32_t opnum, const DATA_BLOB *req, DATA_BLOB *resp)
4767 if (!wcache_opnum_cacheable(opnum) ||
4768 is_my_own_sam_domain(domain) ||
4769 is_builtin_domain(domain)) {
4773 if (wcache->tdb == NULL) {
4777 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4780 data = tdb_fetch(wcache->tdb, key);
4781 TALLOC_FREE(key.dptr);
4783 if (data.dptr == NULL) {
4786 if (data.dsize < 12) {
4790 if (is_domain_online(domain)) {
4791 uint32_t entry_seqnum, dom_seqnum, last_check;
4792 uint64_t entry_timeout;
4794 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum,
4798 entry_seqnum = IVAL(data.dptr, 0);
4799 if (entry_seqnum != dom_seqnum) {
4800 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4801 (int)entry_seqnum));
4804 entry_timeout = BVAL(data.dptr, 4);
4805 if (time(NULL) > (time_t)entry_timeout) {
4806 DEBUG(10, ("Entry has timed out\n"));
4811 resp->data = (uint8_t *)talloc_memdup(mem_ctx, data.dptr + 12,
4813 if (resp->data == NULL) {
4814 DEBUG(10, ("talloc failed\n"));
4817 resp->length = data.dsize - 12;
4821 SAFE_FREE(data.dptr);
4825 void wcache_store_ndr(struct winbindd_domain *domain, uint32_t opnum,
4826 const DATA_BLOB *req, const DATA_BLOB *resp)
4829 uint32_t dom_seqnum, last_check;
4832 if (!wcache_opnum_cacheable(opnum) ||
4833 is_my_own_sam_domain(domain) ||
4834 is_builtin_domain(domain)) {
4838 if (wcache->tdb == NULL) {
4842 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum, &last_check)) {
4843 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4848 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4852 timeout = time(NULL) + lp_winbind_cache_time();
4854 data.dsize = resp->length + 12;
4855 data.dptr = talloc_array(key.dptr, uint8_t, data.dsize);
4856 if (data.dptr == NULL) {
4860 SIVAL(data.dptr, 0, dom_seqnum);
4861 SBVAL(data.dptr, 4, timeout);
4862 memcpy(data.dptr + 12, resp->data, resp->length);
4864 tdb_store(wcache->tdb, key, data, 0);
4867 TALLOC_FREE(key.dptr);