2 Unix SMB/CIFS implementation.
4 Winbind cache backend functions
6 Copyright (C) Andrew Tridgell 2001
7 Copyright (C) Gerald Carter 2003-2007
8 Copyright (C) Volker Lendecke 2005
9 Copyright (C) Guenther Deschner 2005
10 Copyright (C) Michael Adam 2007
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include "system/filesys.h"
29 #include "tdb_validate.h"
30 #include "../libcli/auth/libcli_auth.h"
31 #include "../librpc/gen_ndr/ndr_winbind.h"
34 #include "../libcli/security/security.h"
35 #include "passdb/machine_sid.h"
37 #include "libsmb/samlogon_cache.h"
40 #define DBGC_CLASS DBGC_WINBIND
42 #define WINBINDD_CACHE_VER1 1 /* initial db version */
43 #define WINBINDD_CACHE_VER2 2 /* second version with timeouts for NDR entries */
45 #define WINBINDD_CACHE_VERSION WINBINDD_CACHE_VER2
46 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
48 extern struct winbindd_methods reconnect_methods;
50 extern struct winbindd_methods reconnect_ads_methods;
52 extern struct winbindd_methods builtin_passdb_methods;
53 extern struct winbindd_methods sam_passdb_methods;
56 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
57 * Here are the list of entry types that are *not* stored
58 * as form struct cache_entry in the cache.
61 static const char *non_centry_keys[] = {
64 WINBINDD_CACHE_VERSION_KEYSTR,
68 /************************************************************************
69 Is this key a non-centry type ?
70 ************************************************************************/
72 static bool is_non_centry_key(TDB_DATA kbuf)
76 if (kbuf.dptr == NULL || kbuf.dsize == 0) {
79 for (i = 0; non_centry_keys[i] != NULL; i++) {
80 size_t namelen = strlen(non_centry_keys[i]);
81 if (kbuf.dsize < namelen) {
84 if (strncmp(non_centry_keys[i], (const char *)kbuf.dptr, namelen) == 0) {
91 /* Global online/offline state - False when online. winbindd starts up online
92 and sets this to true if the first query fails and there's an entry in
93 the cache tdb telling us to stay offline. */
95 static bool global_winbindd_offline_state;
97 struct winbind_cache {
103 uint32_t sequence_number;
109 void (*smb_panic_fn)(const char *const why) = smb_panic;
111 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
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)) {
141 domain->backend = &sam_passdb_methods;
144 if ( !domain->initialized ) {
145 /* We do not need a connection to an RW DC for cache operation */
146 init_dc_connection(domain, false);
150 OK. Listen up because I'm only going to say this once.
151 We have the following scenarios to consider
152 (a) trusted AD domains on a Samba DC,
153 (b) trusted AD domains and we are joined to a non-kerberos domain
154 (c) trusted AD domains and we are joined to a kerberos (AD) domain
156 For (a) we can always contact the trusted domain using krb5
157 since we have the domain trust account password
159 For (b) we can only use RPC since we have no way of
160 getting a krb5 ticket in our own domain
162 For (c) we can always use krb5 since we have a kerberos trust
167 if (!domain->backend) {
169 struct winbindd_domain *our_domain = domain;
171 /* find our domain first so we can figure out if we
172 are joined to a kerberized domain */
174 if ( !domain->primary )
175 our_domain = find_our_domain();
177 if ((our_domain->active_directory || IS_DC)
178 && domain->active_directory
179 && !lp_winbind_rpc_only()) {
180 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain->name));
181 domain->backend = &reconnect_ads_methods;
183 #endif /* HAVE_ADS */
184 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain->name));
185 domain->backend = &reconnect_methods;
188 #endif /* HAVE_ADS */
194 ret = SMB_XMALLOC_P(struct winbind_cache);
198 wcache_flush_cache();
204 free a centry structure
206 static void centry_free(struct cache_entry *centry)
210 SAFE_FREE(centry->data);
214 static bool centry_check_bytes(struct cache_entry *centry, size_t nbytes)
216 if (centry->len - centry->ofs < nbytes) {
217 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
218 (unsigned int)nbytes,
219 centry->len - centry->ofs));
226 pull a uint64_t from a cache entry
228 static uint64_t centry_uint64_t(struct cache_entry *centry)
232 if (!centry_check_bytes(centry, 8)) {
233 smb_panic_fn("centry_uint64_t");
235 ret = BVAL(centry->data, centry->ofs);
241 pull a uint32_t from a cache entry
243 static uint32_t centry_uint32(struct cache_entry *centry)
247 if (!centry_check_bytes(centry, 4)) {
248 smb_panic_fn("centry_uint32");
250 ret = IVAL(centry->data, centry->ofs);
256 pull a uint16_t from a cache entry
258 static uint16_t centry_uint16(struct cache_entry *centry)
261 if (!centry_check_bytes(centry, 2)) {
262 smb_panic_fn("centry_uint16");
264 ret = SVAL(centry->data, centry->ofs);
270 pull a uint8_t from a cache entry
272 static uint8_t centry_uint8(struct cache_entry *centry)
275 if (!centry_check_bytes(centry, 1)) {
276 smb_panic_fn("centry_uint8");
278 ret = CVAL(centry->data, centry->ofs);
284 pull a NTTIME from a cache entry
286 static NTTIME centry_nttime(struct cache_entry *centry)
289 if (!centry_check_bytes(centry, 8)) {
290 smb_panic_fn("centry_nttime");
292 ret = IVAL(centry->data, centry->ofs);
294 ret += (uint64_t)IVAL(centry->data, centry->ofs) << 32;
300 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
302 static time_t centry_time(struct cache_entry *centry)
304 return (time_t)centry_nttime(centry);
307 /* pull a string from a cache entry, using the supplied
310 static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
315 len = centry_uint8(centry);
318 /* a deliberate NULL string */
322 if (!centry_check_bytes(centry, (size_t)len)) {
323 smb_panic_fn("centry_string");
326 ret = talloc_array(mem_ctx, char, len+1);
328 smb_panic_fn("centry_string out of memory\n");
330 memcpy(ret,centry->data + centry->ofs, len);
336 /* pull a hash16 from a cache entry, using the supplied
339 static char *centry_hash16(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
344 len = centry_uint8(centry);
347 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
352 if (!centry_check_bytes(centry, 16)) {
356 ret = talloc_array(mem_ctx, char, 16);
358 smb_panic_fn("centry_hash out of memory\n");
360 memcpy(ret,centry->data + centry->ofs, 16);
365 /* pull a sid from a cache entry, using the supplied
368 static bool centry_sid(struct cache_entry *centry, struct dom_sid *sid)
373 sid_string = centry_string(centry, talloc_tos());
374 if (sid_string == NULL) {
377 ret = string_to_sid(sid, sid_string);
378 TALLOC_FREE(sid_string);
384 pull a NTSTATUS from a cache entry
386 static NTSTATUS centry_ntstatus(struct cache_entry *centry)
390 status = NT_STATUS(centry_uint32(centry));
395 /* the server is considered down if it can't give us a sequence number */
396 static bool wcache_server_down(struct winbindd_domain *domain)
403 ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
406 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
411 struct wcache_seqnum_state {
413 uint32_t *last_seq_check;
416 static int wcache_seqnum_parser(TDB_DATA key, TDB_DATA data,
419 struct wcache_seqnum_state *state = private_data;
421 if (data.dsize != 8) {
422 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
427 *state->seqnum = IVAL(data.dptr, 0);
428 *state->last_seq_check = IVAL(data.dptr, 4);
432 static bool wcache_fetch_seqnum(const char *domain_name, uint32_t *seqnum,
433 uint32_t *last_seq_check)
435 struct wcache_seqnum_state state = {
436 .seqnum = seqnum, .last_seq_check = last_seq_check
438 size_t len = strlen(domain_name);
440 TDB_DATA key = { .dptr = (uint8_t *)keystr, .dsize = sizeof(keystr) };
443 if (wcache->tdb == NULL) {
444 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
448 snprintf(keystr, sizeof(keystr), "SEQNUM/%s", domain_name);
450 ret = tdb_parse_record(wcache->tdb, key, wcache_seqnum_parser,
455 static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
457 uint32_t last_check, time_diff;
459 if (!wcache_fetch_seqnum(domain->name, &domain->sequence_number,
461 return NT_STATUS_UNSUCCESSFUL;
463 domain->last_seq_check = last_check;
465 /* have we expired? */
467 time_diff = now - domain->last_seq_check;
468 if ( time_diff > lp_winbind_cache_time() ) {
469 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
470 domain->name, domain->sequence_number,
471 (uint32_t)domain->last_seq_check));
472 return NT_STATUS_UNSUCCESSFUL;
475 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
476 domain->name, domain->sequence_number,
477 (uint32_t)domain->last_seq_check));
482 bool wcache_store_seqnum(const char *domain_name, uint32_t seqnum,
483 time_t last_seq_check)
485 size_t len = strlen(domain_name);
487 TDB_DATA key = { .dptr = (uint8_t *)keystr, .dsize = sizeof(keystr) };
491 if (wcache->tdb == NULL) {
492 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
496 snprintf(keystr, sizeof(keystr), "SEQNUM/%s", domain_name);
498 SIVAL(buf, 0, seqnum);
499 SIVAL(buf, 4, last_seq_check);
501 ret = tdb_store(wcache->tdb, key, make_tdb_data(buf, sizeof(buf)),
504 DEBUG(10, ("tdb_store_bystring failed: %s\n",
505 tdb_errorstr(wcache->tdb)));
509 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
510 domain_name, seqnum, (unsigned)last_seq_check));
515 static bool store_cache_seqnum( struct winbindd_domain *domain )
517 return wcache_store_seqnum(domain->name, domain->sequence_number,
518 domain->last_seq_check);
522 refresh the domain sequence number on timeout.
525 static void refresh_sequence_number(struct winbindd_domain *domain)
529 time_t t = time(NULL);
530 unsigned cache_time = lp_winbind_cache_time();
532 if (is_domain_offline(domain)) {
538 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
539 /* trying to reconnect is expensive, don't do it too often */
540 if (domain->sequence_number == DOM_SEQUENCE_NONE) {
545 time_diff = t - domain->last_seq_check;
547 /* see if we have to refetch the domain sequence number */
548 if ((time_diff < cache_time) &&
549 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
550 NT_STATUS_IS_OK(domain->last_status)) {
551 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
555 /* try to get the sequence number from the tdb cache first */
556 /* this will update the timestamp as well */
558 status = fetch_cache_seqnum( domain, t );
559 if (NT_STATUS_IS_OK(status) &&
560 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
561 NT_STATUS_IS_OK(domain->last_status)) {
565 /* important! make sure that we know if this is a native
566 mode domain or not. And that we can contact it. */
568 if ( winbindd_can_contact_domain( domain ) ) {
569 status = domain->backend->sequence_number(domain,
570 &domain->sequence_number);
572 /* just use the current time */
573 status = NT_STATUS_OK;
574 domain->sequence_number = time(NULL);
578 /* the above call could have set our domain->backend to NULL when
579 * coming from offline to online mode, make sure to reinitialize the
580 * backend - Guenther */
583 if (!NT_STATUS_IS_OK(status)) {
584 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status)));
585 domain->sequence_number = DOM_SEQUENCE_NONE;
588 domain->last_status = status;
589 domain->last_seq_check = time(NULL);
591 /* save the new sequence number in the cache */
592 store_cache_seqnum( domain );
595 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
596 domain->name, domain->sequence_number));
602 decide if a cache entry has expired
604 static bool centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
606 /* If we've been told to be offline - stay in that state... */
607 if (lp_winbind_offline_logon() && global_winbindd_offline_state) {
608 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
609 keystr, domain->name ));
613 /* when the domain is offline return the cached entry.
614 * This deals with transient offline states... */
616 if (!domain->online) {
617 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
618 keystr, domain->name ));
622 /* if the server is OK and our cache entry came from when it was down then
623 the entry is invalid */
624 if ((domain->sequence_number != DOM_SEQUENCE_NONE) &&
625 (centry->sequence_number == DOM_SEQUENCE_NONE)) {
626 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
627 keystr, domain->name ));
631 /* if the server is down or the cache entry is not older than the
632 current sequence number or it did not timeout then it is OK */
633 if (wcache_server_down(domain)
634 || ((centry->sequence_number == domain->sequence_number)
635 && (centry->timeout > time(NULL)))) {
636 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
637 keystr, domain->name ));
641 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
642 keystr, domain->name ));
648 static struct cache_entry *wcache_fetch_raw(char *kstr)
651 struct cache_entry *centry;
654 key = string_tdb_data(kstr);
655 data = tdb_fetch(wcache->tdb, key);
661 centry = SMB_XMALLOC_P(struct cache_entry);
662 centry->data = (unsigned char *)data.dptr;
663 centry->len = data.dsize;
666 if (centry->len < 16) {
667 /* huh? corrupt cache? */
668 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s "
669 "(len < 16)?\n", kstr));
674 centry->status = centry_ntstatus(centry);
675 centry->sequence_number = centry_uint32(centry);
676 centry->timeout = centry_uint64_t(centry);
681 static bool is_my_own_sam_domain(struct winbindd_domain *domain)
683 if (strequal(domain->name, get_global_sam_name()) &&
684 sid_check_is_our_sam(&domain->sid)) {
691 static bool is_builtin_domain(struct winbindd_domain *domain)
693 if (strequal(domain->name, "BUILTIN") &&
694 sid_check_is_builtin(&domain->sid)) {
702 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
703 number and return status
705 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
706 struct winbindd_domain *domain,
707 const char *format, ...) PRINTF_ATTRIBUTE(3,4);
708 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
709 struct winbindd_domain *domain,
710 const char *format, ...)
714 struct cache_entry *centry;
716 if (!winbindd_use_cache() ||
717 is_my_own_sam_domain(domain) ||
718 is_builtin_domain(domain)) {
722 refresh_sequence_number(domain);
724 va_start(ap, format);
725 smb_xvasprintf(&kstr, format, ap);
728 centry = wcache_fetch_raw(kstr);
729 if (centry == NULL) {
734 if (centry_expired(domain, kstr, centry)) {
736 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
737 kstr, domain->name ));
744 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
745 kstr, domain->name ));
751 static void wcache_delete(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
752 static void wcache_delete(const char *format, ...)
758 va_start(ap, format);
759 smb_xvasprintf(&kstr, format, ap);
762 key = string_tdb_data(kstr);
764 tdb_delete(wcache->tdb, key);
769 make sure we have at least len bytes available in a centry
771 static void centry_expand(struct cache_entry *centry, uint32_t len)
773 if (centry->len - centry->ofs >= len)
776 centry->data = SMB_REALLOC_ARRAY(centry->data, unsigned char,
779 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
780 smb_panic_fn("out of memory in centry_expand");
785 push a uint64_t into a centry
787 static void centry_put_uint64_t(struct cache_entry *centry, uint64_t v)
789 centry_expand(centry, 8);
790 SBVAL(centry->data, centry->ofs, v);
795 push a uint32_t into a centry
797 static void centry_put_uint32(struct cache_entry *centry, uint32_t v)
799 centry_expand(centry, 4);
800 SIVAL(centry->data, centry->ofs, v);
805 push a uint16_t into a centry
807 static void centry_put_uint16(struct cache_entry *centry, uint16_t v)
809 centry_expand(centry, 2);
810 SSVAL(centry->data, centry->ofs, v);
815 push a uint8_t into a centry
817 static void centry_put_uint8(struct cache_entry *centry, uint8_t v)
819 centry_expand(centry, 1);
820 SCVAL(centry->data, centry->ofs, v);
825 push a string into a centry
827 static void centry_put_string(struct cache_entry *centry, const char *s)
832 /* null strings are marked as len 0xFFFF */
833 centry_put_uint8(centry, 0xFF);
838 /* can't handle more than 254 char strings. Truncating is probably best */
840 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len));
843 centry_put_uint8(centry, len);
844 centry_expand(centry, len);
845 memcpy(centry->data + centry->ofs, s, len);
850 push a 16 byte hash into a centry - treat as 16 byte string.
852 static void centry_put_hash16(struct cache_entry *centry, const uint8_t val[16])
854 centry_put_uint8(centry, 16);
855 centry_expand(centry, 16);
856 memcpy(centry->data + centry->ofs, val, 16);
860 static void centry_put_sid(struct cache_entry *centry, const struct dom_sid *sid)
863 centry_put_string(centry, sid_to_fstring(sid_string, sid));
868 put NTSTATUS into a centry
870 static void centry_put_ntstatus(struct cache_entry *centry, NTSTATUS status)
872 uint32_t status_value = NT_STATUS_V(status);
873 centry_put_uint32(centry, status_value);
878 push a NTTIME into a centry
880 static void centry_put_nttime(struct cache_entry *centry, NTTIME nt)
882 centry_expand(centry, 8);
883 SIVAL(centry->data, centry->ofs, nt & 0xFFFFFFFF);
885 SIVAL(centry->data, centry->ofs, nt >> 32);
890 push a time_t into a centry - use a 64 bit size.
891 NTTIME here is being used as a convenient 64-bit size.
893 static void centry_put_time(struct cache_entry *centry, time_t t)
895 NTTIME nt = (NTTIME)t;
896 centry_put_nttime(centry, nt);
900 start a centry for output. When finished, call centry_end()
902 static struct cache_entry *centry_start(struct winbindd_domain *domain,
905 struct cache_entry *centry;
910 centry = SMB_XMALLOC_P(struct cache_entry);
912 centry->len = 8192; /* reasonable default */
913 centry->data = SMB_XMALLOC_ARRAY(uint8_t, centry->len);
915 centry->sequence_number = domain->sequence_number;
916 centry->timeout = lp_winbind_cache_time() + time(NULL);
917 centry_put_ntstatus(centry, status);
918 centry_put_uint32(centry, centry->sequence_number);
919 centry_put_uint64_t(centry, centry->timeout);
924 finish a centry and write it to the tdb
926 static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
927 static void centry_end(struct cache_entry *centry, const char *format, ...)
933 if (!winbindd_use_cache()) {
937 va_start(ap, format);
938 smb_xvasprintf(&kstr, format, ap);
941 key = string_tdb_data(kstr);
942 data.dptr = centry->data;
943 data.dsize = centry->ofs;
945 tdb_store(wcache->tdb, key, data, TDB_REPLACE);
949 static void wcache_save_name_to_sid(struct winbindd_domain *domain,
950 NTSTATUS status, const char *domain_name,
951 const char *name, const struct dom_sid *sid,
952 enum lsa_SidType type)
954 struct cache_entry *centry;
957 centry = centry_start(domain, status);
961 if ((domain_name == NULL) || (domain_name[0] == '\0')) {
962 struct winbindd_domain *mydomain =
963 find_domain_from_sid_noinit(sid);
964 if (mydomain != NULL) {
965 domain_name = mydomain->name;
969 centry_put_uint32(centry, type);
970 centry_put_sid(centry, sid);
971 fstrcpy(uname, name);
972 (void)strupper_m(uname);
973 centry_end(centry, "NS/%s/%s", domain_name, uname);
974 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name,
975 uname, sid_string_dbg(sid), nt_errstr(status)));
979 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
980 const struct dom_sid *sid, const char *domain_name, const char *name, enum lsa_SidType type)
982 struct cache_entry *centry;
985 centry = centry_start(domain, status);
989 if ((domain_name == NULL) || (domain_name[0] == '\0')) {
990 struct winbindd_domain *mydomain =
991 find_domain_from_sid_noinit(sid);
992 if (mydomain != NULL) {
993 domain_name = mydomain->name;
997 if (NT_STATUS_IS_OK(status)) {
998 centry_put_uint32(centry, type);
999 centry_put_string(centry, domain_name);
1000 centry_put_string(centry, name);
1003 centry_end(centry, "SN/%s", sid_to_fstring(sid_string, sid));
1004 DEBUG(10,("wcache_save_sid_to_name: %s -> %s\\%s (%s)\n", sid_string,
1005 domain_name, name, nt_errstr(status)));
1006 centry_free(centry);
1010 static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status,
1011 struct wbint_userinfo *info)
1013 struct cache_entry *centry;
1016 if (is_null_sid(&info->user_sid)) {
1020 centry = centry_start(domain, status);
1023 centry_put_string(centry, info->domain_name);
1024 centry_put_string(centry, info->acct_name);
1025 centry_put_string(centry, info->full_name);
1026 centry_put_string(centry, info->homedir);
1027 centry_put_string(centry, info->shell);
1028 centry_put_uint32(centry, info->uid);
1029 centry_put_uint32(centry, info->primary_gid);
1030 centry_put_string(centry, info->primary_group_name);
1031 centry_put_sid(centry, &info->user_sid);
1032 centry_put_sid(centry, &info->group_sid);
1033 centry_end(centry, "U/%s", sid_to_fstring(sid_string,
1035 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
1036 centry_free(centry);
1039 static void wcache_save_lockout_policy(struct winbindd_domain *domain,
1041 struct samr_DomInfo12 *lockout_policy)
1043 struct cache_entry *centry;
1045 centry = centry_start(domain, status);
1049 centry_put_nttime(centry, lockout_policy->lockout_duration);
1050 centry_put_nttime(centry, lockout_policy->lockout_window);
1051 centry_put_uint16(centry, lockout_policy->lockout_threshold);
1053 centry_end(centry, "LOC_POL/%s", domain->name);
1055 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
1057 centry_free(centry);
1062 static void wcache_save_password_policy(struct winbindd_domain *domain,
1064 struct samr_DomInfo1 *policy)
1066 struct cache_entry *centry;
1068 centry = centry_start(domain, status);
1072 centry_put_uint16(centry, policy->min_password_length);
1073 centry_put_uint16(centry, policy->password_history_length);
1074 centry_put_uint32(centry, policy->password_properties);
1075 centry_put_nttime(centry, policy->max_password_age);
1076 centry_put_nttime(centry, policy->min_password_age);
1078 centry_end(centry, "PWD_POL/%s", domain->name);
1080 DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
1082 centry_free(centry);
1085 /***************************************************************************
1086 ***************************************************************************/
1088 static void wcache_save_username_alias(struct winbindd_domain *domain,
1090 const char *name, const char *alias)
1092 struct cache_entry *centry;
1095 if ( (centry = centry_start(domain, status)) == NULL )
1098 centry_put_string( centry, alias );
1100 fstrcpy(uname, name);
1101 (void)strupper_m(uname);
1102 centry_end(centry, "NSS/NA/%s", uname);
1104 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name, alias ));
1106 centry_free(centry);
1109 static void wcache_save_alias_username(struct winbindd_domain *domain,
1111 const char *alias, const char *name)
1113 struct cache_entry *centry;
1116 if ( (centry = centry_start(domain, status)) == NULL )
1119 centry_put_string( centry, name );
1121 fstrcpy(uname, alias);
1122 (void)strupper_m(uname);
1123 centry_end(centry, "NSS/AN/%s", uname);
1125 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias, name ));
1127 centry_free(centry);
1130 /***************************************************************************
1131 ***************************************************************************/
1133 NTSTATUS resolve_username_to_alias( TALLOC_CTX *mem_ctx,
1134 struct winbindd_domain *domain,
1135 const char *name, char **alias )
1137 struct winbind_cache *cache = get_cache(domain);
1138 struct cache_entry *centry = NULL;
1142 if ( domain->internal )
1143 return NT_STATUS_NOT_SUPPORTED;
1148 upper_name = talloc_strdup(mem_ctx, name);
1149 if (upper_name == NULL) {
1150 return NT_STATUS_NO_MEMORY;
1152 if (!strupper_m(upper_name)) {
1153 talloc_free(upper_name);
1154 return NT_STATUS_INVALID_PARAMETER;
1157 centry = wcache_fetch(cache, domain, "NSS/NA/%s", upper_name);
1159 talloc_free(upper_name);
1164 status = centry->status;
1166 if (!NT_STATUS_IS_OK(status)) {
1167 centry_free(centry);
1171 *alias = centry_string( centry, mem_ctx );
1173 centry_free(centry);
1175 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1176 name, *alias ? *alias : "(none)"));
1178 return (*alias) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1182 /* If its not in cache and we are offline, then fail */
1184 if ( get_global_winbindd_state_offline() || !domain->online ) {
1185 DEBUG(8,("resolve_username_to_alias: rejecting query "
1186 "in offline mode\n"));
1187 return NT_STATUS_NOT_FOUND;
1190 status = nss_map_to_alias( mem_ctx, domain->name, name, alias );
1192 if ( NT_STATUS_IS_OK( status ) ) {
1193 wcache_save_username_alias(domain, status, name, *alias);
1196 if ( NT_STATUS_EQUAL( status, NT_STATUS_NONE_MAPPED ) ) {
1197 wcache_save_username_alias(domain, status, name, "(NULL)");
1200 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1201 nt_errstr(status)));
1203 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1204 set_domain_offline( domain );
1210 /***************************************************************************
1211 ***************************************************************************/
1213 NTSTATUS resolve_alias_to_username( TALLOC_CTX *mem_ctx,
1214 struct winbindd_domain *domain,
1215 const char *alias, char **name )
1217 struct winbind_cache *cache = get_cache(domain);
1218 struct cache_entry *centry = NULL;
1222 if ( domain->internal )
1223 return NT_STATUS_NOT_SUPPORTED;
1228 upper_name = talloc_strdup(mem_ctx, alias);
1229 if (upper_name == NULL) {
1230 return NT_STATUS_NO_MEMORY;
1232 if (!strupper_m(upper_name)) {
1233 talloc_free(upper_name);
1234 return NT_STATUS_INVALID_PARAMETER;
1237 centry = wcache_fetch(cache, domain, "NSS/AN/%s", upper_name);
1239 talloc_free(upper_name);
1244 status = centry->status;
1246 if (!NT_STATUS_IS_OK(status)) {
1247 centry_free(centry);
1251 *name = centry_string( centry, mem_ctx );
1253 centry_free(centry);
1255 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1256 alias, *name ? *name : "(none)"));
1258 return (*name) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1262 /* If its not in cache and we are offline, then fail */
1264 if ( get_global_winbindd_state_offline() || !domain->online ) {
1265 DEBUG(8,("resolve_alias_to_username: rejecting query "
1266 "in offline mode\n"));
1267 return NT_STATUS_NOT_FOUND;
1270 /* an alias cannot contain a domain prefix or '@' */
1272 if (strchr(alias, '\\') || strchr(alias, '@')) {
1273 DEBUG(10,("resolve_alias_to_username: skipping fully "
1274 "qualified name %s\n", alias));
1275 return NT_STATUS_OBJECT_NAME_INVALID;
1278 status = nss_map_from_alias( mem_ctx, domain->name, alias, name );
1280 if ( NT_STATUS_IS_OK( status ) ) {
1281 wcache_save_alias_username( domain, status, alias, *name );
1284 if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1285 wcache_save_alias_username(domain, status, alias, "(NULL)");
1288 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1289 nt_errstr(status)));
1291 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1292 set_domain_offline( domain );
1298 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const struct dom_sid *sid)
1300 struct winbind_cache *cache = get_cache(domain);
1302 fstring key_str, tmp;
1306 return NT_STATUS_INTERNAL_DB_ERROR;
1309 if (is_null_sid(sid)) {
1310 return NT_STATUS_INVALID_SID;
1313 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1314 return NT_STATUS_INVALID_SID;
1317 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
1319 data = tdb_fetch(cache->tdb, string_tdb_data(key_str));
1321 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1324 SAFE_FREE(data.dptr);
1325 return NT_STATUS_OK;
1328 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1329 as new salted ones. */
1331 NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
1332 TALLOC_CTX *mem_ctx,
1333 const struct dom_sid *sid,
1334 const uint8_t **cached_nt_pass,
1335 const uint8_t **cached_salt)
1337 struct winbind_cache *cache = get_cache(domain);
1338 struct cache_entry *centry = NULL;
1344 return NT_STATUS_INTERNAL_DB_ERROR;
1347 if (is_null_sid(sid)) {
1348 return NT_STATUS_INVALID_SID;
1351 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1352 return NT_STATUS_INVALID_SID;
1355 /* Try and get a salted cred first. If we can't
1356 fall back to an unsalted cred. */
1358 centry = wcache_fetch(cache, domain, "CRED/%s",
1359 sid_to_fstring(tmp, sid));
1361 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1362 sid_string_dbg(sid)));
1363 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1367 * We don't use the time element at this moment,
1368 * but we have to consume it, so that we don't
1369 * neet to change the disk format of the cache.
1371 (void)centry_time(centry);
1373 /* In the salted case this isn't actually the nt_hash itself,
1374 but the MD5 of the salt + nt_hash. Let the caller
1375 sort this out. It can tell as we only return the cached_salt
1376 if we are returning a salted cred. */
1378 *cached_nt_pass = (const uint8_t *)centry_hash16(centry, mem_ctx);
1379 if (*cached_nt_pass == NULL) {
1382 sid_to_fstring(sidstr, sid);
1384 /* Bad (old) cred cache. Delete and pretend we
1386 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1388 wcache_delete("CRED/%s", sidstr);
1389 centry_free(centry);
1390 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1393 /* We only have 17 bytes more data in the salted cred case. */
1394 if (centry->len - centry->ofs == 17) {
1395 *cached_salt = (const uint8_t *)centry_hash16(centry, mem_ctx);
1397 *cached_salt = NULL;
1400 dump_data_pw("cached_nt_pass", *cached_nt_pass, NT_HASH_LEN);
1402 dump_data_pw("cached_salt", *cached_salt, NT_HASH_LEN);
1405 status = centry->status;
1407 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1408 sid_string_dbg(sid), nt_errstr(status) ));
1410 centry_free(centry);
1414 /* Store creds for a SID - only writes out new salted ones. */
1416 NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
1417 const struct dom_sid *sid,
1418 const uint8_t nt_pass[NT_HASH_LEN])
1420 struct cache_entry *centry;
1423 uint8_t cred_salt[NT_HASH_LEN];
1424 uint8_t salted_hash[NT_HASH_LEN];
1426 if (is_null_sid(sid)) {
1427 return NT_STATUS_INVALID_SID;
1430 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1431 return NT_STATUS_INVALID_SID;
1434 centry = centry_start(domain, NT_STATUS_OK);
1436 return NT_STATUS_INTERNAL_DB_ERROR;
1439 dump_data_pw("nt_pass", nt_pass, NT_HASH_LEN);
1441 centry_put_time(centry, time(NULL));
1443 /* Create a salt and then salt the hash. */
1444 generate_random_buffer(cred_salt, NT_HASH_LEN);
1445 E_md5hash(cred_salt, nt_pass, salted_hash);
1447 centry_put_hash16(centry, salted_hash);
1448 centry_put_hash16(centry, cred_salt);
1449 centry_end(centry, "CRED/%s", sid_to_fstring(sid_string, sid));
1451 DEBUG(10,("wcache_save_creds: %s\n", sid_string));
1453 centry_free(centry);
1455 return NT_STATUS_OK;
1459 /* Query display info. This is the basic user list fn */
1460 NTSTATUS wb_cache_query_user_list(struct winbindd_domain *domain,
1461 TALLOC_CTX *mem_ctx,
1462 uint32_t *num_entries,
1463 struct wbint_userinfo **info)
1465 struct winbind_cache *cache = get_cache(domain);
1466 struct cache_entry *centry = NULL;
1468 unsigned int i, retry;
1469 bool old_status = domain->online;
1474 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1479 *num_entries = centry_uint32(centry);
1481 if (*num_entries == 0)
1484 (*info) = talloc_array(mem_ctx, struct wbint_userinfo, *num_entries);
1486 smb_panic_fn("query_user_list out of memory");
1488 for (i=0; i<(*num_entries); i++) {
1489 (*info)[i].domain_name = centry_string(centry, mem_ctx);
1490 (*info)[i].acct_name = centry_string(centry, mem_ctx);
1491 (*info)[i].full_name = centry_string(centry, mem_ctx);
1492 (*info)[i].homedir = centry_string(centry, mem_ctx);
1493 (*info)[i].shell = centry_string(centry, mem_ctx);
1494 (*info)[i].uid = centry_uint32(centry);
1495 (*info)[i].primary_gid = centry_uint32(centry);
1496 (*info)[i].primary_group_name = centry_string(centry, mem_ctx);
1497 centry_sid(centry, &(*info)[i].user_sid);
1498 centry_sid(centry, &(*info)[i].group_sid);
1502 status = centry->status;
1504 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1505 domain->name, nt_errstr(status) ));
1507 centry_free(centry);
1514 /* Return status value returned by seq number check */
1516 if (!NT_STATUS_IS_OK(domain->last_status))
1517 return domain->last_status;
1519 /* Put the query_user_list() in a retry loop. There appears to be
1520 * some bug either with Windows 2000 or Samba's handling of large
1521 * rpc replies. This manifests itself as sudden disconnection
1522 * at a random point in the enumeration of a large (60k) user list.
1523 * The retry loop simply tries the operation again. )-: It's not
1524 * pretty but an acceptable workaround until we work out what the
1525 * real problem is. */
1530 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1533 status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
1534 if (!NT_STATUS_IS_OK(status)) {
1535 DEBUG(3, ("query_user_list: returned 0x%08x, "
1536 "retrying\n", NT_STATUS_V(status)));
1538 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1539 DEBUG(3, ("query_user_list: flushing "
1540 "connection cache\n"));
1541 invalidate_cm_connection(domain);
1543 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1544 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1545 if (!domain->internal && old_status) {
1546 set_domain_offline(domain);
1548 /* store partial response. */
1549 if (*num_entries > 0) {
1551 * humm, what about the status used for cache?
1552 * Should it be NT_STATUS_OK?
1557 * domain is offline now, and there is no user entries,
1558 * try to fetch from cache again.
1560 if (cache->tdb && !domain->online && !domain->internal && old_status) {
1561 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1562 /* partial response... */
1566 goto do_fetch_cache;
1573 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
1577 refresh_sequence_number(domain);
1578 if (!NT_STATUS_IS_OK(status)) {
1581 centry = centry_start(domain, status);
1584 centry_put_uint32(centry, *num_entries);
1585 for (i=0; i<(*num_entries); i++) {
1586 centry_put_string(centry, (*info)[i].domain_name);
1587 centry_put_string(centry, (*info)[i].acct_name);
1588 centry_put_string(centry, (*info)[i].full_name);
1589 centry_put_string(centry, (*info)[i].homedir);
1590 centry_put_string(centry, (*info)[i].shell);
1591 centry_put_uint32(centry, (*info)[i].uid);
1592 centry_put_uint32(centry, (*info)[i].primary_gid);
1593 centry_put_string(centry, (*info)[i].primary_group_name);
1594 centry_put_sid(centry, &(*info)[i].user_sid);
1595 centry_put_sid(centry, &(*info)[i].group_sid);
1596 if (domain->backend && domain->backend->consistent) {
1597 /* when the backend is consistent we can pre-prime some mappings */
1598 wcache_save_name_to_sid(domain, NT_STATUS_OK,
1600 (*info)[i].acct_name,
1601 &(*info)[i].user_sid,
1603 wcache_save_sid_to_name(domain, NT_STATUS_OK,
1604 &(*info)[i].user_sid,
1606 (*info)[i].acct_name,
1608 wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
1611 centry_end(centry, "UL/%s", domain->name);
1612 centry_free(centry);
1618 /* list all domain groups */
1619 NTSTATUS wb_cache_enum_dom_groups(struct winbindd_domain *domain,
1620 TALLOC_CTX *mem_ctx,
1621 uint32_t *num_entries,
1622 struct wb_acct_info **info)
1624 struct winbind_cache *cache = get_cache(domain);
1625 struct cache_entry *centry = NULL;
1630 old_status = domain->online;
1634 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1639 *num_entries = centry_uint32(centry);
1641 if (*num_entries == 0)
1644 (*info) = talloc_array(mem_ctx, struct wb_acct_info, *num_entries);
1646 smb_panic_fn("enum_dom_groups out of memory");
1648 for (i=0; i<(*num_entries); i++) {
1649 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1650 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1651 (*info)[i].rid = centry_uint32(centry);
1655 status = centry->status;
1657 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1658 domain->name, nt_errstr(status) ));
1660 centry_free(centry);
1667 /* Return status value returned by seq number check */
1669 if (!NT_STATUS_IS_OK(domain->last_status))
1670 return domain->last_status;
1672 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1675 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1677 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1678 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1679 if (!domain->internal && old_status) {
1680 set_domain_offline(domain);
1684 !domain->internal &&
1686 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1688 goto do_fetch_cache;
1693 refresh_sequence_number(domain);
1694 if (!NT_STATUS_IS_OK(status)) {
1697 centry = centry_start(domain, status);
1700 centry_put_uint32(centry, *num_entries);
1701 for (i=0; i<(*num_entries); i++) {
1702 centry_put_string(centry, (*info)[i].acct_name);
1703 centry_put_string(centry, (*info)[i].acct_desc);
1704 centry_put_uint32(centry, (*info)[i].rid);
1706 centry_end(centry, "GL/%s/domain", domain->name);
1707 centry_free(centry);
1713 /* list all domain groups */
1714 NTSTATUS wb_cache_enum_local_groups(struct winbindd_domain *domain,
1715 TALLOC_CTX *mem_ctx,
1716 uint32_t *num_entries,
1717 struct wb_acct_info **info)
1719 struct winbind_cache *cache = get_cache(domain);
1720 struct cache_entry *centry = NULL;
1725 old_status = domain->online;
1729 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1734 *num_entries = centry_uint32(centry);
1736 if (*num_entries == 0)
1739 (*info) = talloc_array(mem_ctx, struct wb_acct_info, *num_entries);
1741 smb_panic_fn("enum_dom_groups out of memory");
1743 for (i=0; i<(*num_entries); i++) {
1744 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1745 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1746 (*info)[i].rid = centry_uint32(centry);
1751 /* If we are returning cached data and the domain controller
1752 is down then we don't know whether the data is up to date
1753 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1756 if (wcache_server_down(domain)) {
1757 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1758 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1760 status = centry->status;
1762 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1763 domain->name, nt_errstr(status) ));
1765 centry_free(centry);
1772 /* Return status value returned by seq number check */
1774 if (!NT_STATUS_IS_OK(domain->last_status))
1775 return domain->last_status;
1777 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1780 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1782 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1783 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1784 if (!domain->internal && old_status) {
1785 set_domain_offline(domain);
1788 !domain->internal &&
1791 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1793 goto do_fetch_cache;
1798 refresh_sequence_number(domain);
1799 if (!NT_STATUS_IS_OK(status)) {
1802 centry = centry_start(domain, status);
1805 centry_put_uint32(centry, *num_entries);
1806 for (i=0; i<(*num_entries); i++) {
1807 centry_put_string(centry, (*info)[i].acct_name);
1808 centry_put_string(centry, (*info)[i].acct_desc);
1809 centry_put_uint32(centry, (*info)[i].rid);
1811 centry_end(centry, "GL/%s/local", domain->name);
1812 centry_free(centry);
1818 NTSTATUS wcache_name_to_sid(struct winbindd_domain *domain,
1819 const char *domain_name,
1821 struct dom_sid *sid,
1822 enum lsa_SidType *type)
1824 struct winbind_cache *cache = get_cache(domain);
1825 struct cache_entry *centry;
1829 if (cache->tdb == NULL) {
1830 return NT_STATUS_NOT_FOUND;
1833 uname = talloc_strdup_upper(talloc_tos(), name);
1834 if (uname == NULL) {
1835 return NT_STATUS_NO_MEMORY;
1838 if ((domain_name == NULL) || (domain_name[0] == '\0')) {
1839 domain_name = domain->name;
1842 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1844 if (centry == NULL) {
1845 return NT_STATUS_NOT_FOUND;
1848 status = centry->status;
1849 if (NT_STATUS_IS_OK(status)) {
1850 *type = (enum lsa_SidType)centry_uint32(centry);
1851 centry_sid(centry, sid);
1854 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1855 "%s\n", domain->name, nt_errstr(status) ));
1857 centry_free(centry);
1861 /* convert a single name to a sid in a domain */
1862 NTSTATUS wb_cache_name_to_sid(struct winbindd_domain *domain,
1863 TALLOC_CTX *mem_ctx,
1864 const char *domain_name,
1867 struct dom_sid *sid,
1868 enum lsa_SidType *type)
1873 old_status = domain->online;
1875 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1876 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1882 /* If the seq number check indicated that there is a problem
1883 * with this DC, then return that status... except for
1884 * access_denied. This is special because the dc may be in
1885 * "restrict anonymous = 1" mode, in which case it will deny
1886 * most unauthenticated operations, but *will* allow the LSA
1887 * name-to-sid that we try as a fallback. */
1889 if (!(NT_STATUS_IS_OK(domain->last_status)
1890 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1891 return domain->last_status;
1893 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1896 status = domain->backend->name_to_sid(domain, mem_ctx, domain_name,
1897 name, flags, sid, type);
1899 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1900 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1901 if (!domain->internal && old_status) {
1902 set_domain_offline(domain);
1904 if (!domain->internal &&
1907 NTSTATUS cache_status;
1908 cache_status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1909 return cache_status;
1913 refresh_sequence_number(domain);
1915 if (domain->online &&
1916 (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
1917 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1919 /* Only save the reverse mapping if this was not a UPN */
1920 if (!strchr(name, '@')) {
1921 if (!strupper_m(discard_const_p(char, domain_name))) {
1922 return NT_STATUS_INVALID_PARAMETER;
1924 (void)strlower_m(discard_const_p(char, name));
1925 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1932 static NTSTATUS wcache_sid_to_name(struct winbindd_domain *domain,
1933 const struct dom_sid *sid,
1934 TALLOC_CTX *mem_ctx,
1937 enum lsa_SidType *type)
1939 struct winbind_cache *cache = get_cache(domain);
1940 struct cache_entry *centry;
1944 if (cache->tdb == NULL) {
1945 return NT_STATUS_NOT_FOUND;
1948 sid_string = sid_string_tos(sid);
1949 if (sid_string == NULL) {
1950 return NT_STATUS_NO_MEMORY;
1953 centry = wcache_fetch(cache, domain, "SN/%s", sid_string);
1954 TALLOC_FREE(sid_string);
1955 if (centry == NULL) {
1956 return NT_STATUS_NOT_FOUND;
1959 if (NT_STATUS_IS_OK(centry->status)) {
1960 *type = (enum lsa_SidType)centry_uint32(centry);
1961 *domain_name = centry_string(centry, mem_ctx);
1962 *name = centry_string(centry, mem_ctx);
1965 status = centry->status;
1966 centry_free(centry);
1968 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1969 "%s\n", domain->name, nt_errstr(status) ));
1974 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1976 NTSTATUS wb_cache_sid_to_name(struct winbindd_domain *domain,
1977 TALLOC_CTX *mem_ctx,
1978 const struct dom_sid *sid,
1981 enum lsa_SidType *type)
1986 old_status = domain->online;
1987 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
1989 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1994 *domain_name = NULL;
1996 /* If the seq number check indicated that there is a problem
1997 * with this DC, then return that status... except for
1998 * access_denied. This is special because the dc may be in
1999 * "restrict anonymous = 1" mode, in which case it will deny
2000 * most unauthenticated operations, but *will* allow the LSA
2001 * sid-to-name that we try as a fallback. */
2003 if (!(NT_STATUS_IS_OK(domain->last_status)
2004 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
2005 return domain->last_status;
2007 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
2010 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
2012 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2013 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2014 if (!domain->internal && old_status) {
2015 set_domain_offline(domain);
2017 if (!domain->internal &&
2020 NTSTATUS cache_status;
2021 cache_status = wcache_sid_to_name(domain, sid, mem_ctx,
2022 domain_name, name, type);
2023 return cache_status;
2027 refresh_sequence_number(domain);
2028 if (!NT_STATUS_IS_OK(status)) {
2031 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
2033 /* We can't save the name to sid mapping here, as with sid history a
2034 * later name2sid would give the wrong sid. */
2039 NTSTATUS wb_cache_rids_to_names(struct winbindd_domain *domain,
2040 TALLOC_CTX *mem_ctx,
2041 const struct dom_sid *domain_sid,
2046 enum lsa_SidType **types)
2048 struct winbind_cache *cache = get_cache(domain);
2050 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
2055 old_status = domain->online;
2056 *domain_name = NULL;
2064 if (num_rids == 0) {
2065 return NT_STATUS_OK;
2068 *names = talloc_array(mem_ctx, char *, num_rids);
2069 *types = talloc_array(mem_ctx, enum lsa_SidType, num_rids);
2071 if ((*names == NULL) || (*types == NULL)) {
2072 result = NT_STATUS_NO_MEMORY;
2076 have_mapped = have_unmapped = false;
2078 for (i=0; i<num_rids; i++) {
2080 struct cache_entry *centry;
2083 if (!sid_compose(&sid, domain_sid, rids[i])) {
2084 result = NT_STATUS_INTERNAL_ERROR;
2088 centry = wcache_fetch(cache, domain, "SN/%s",
2089 sid_to_fstring(tmp, &sid));
2094 (*types)[i] = SID_NAME_UNKNOWN;
2095 (*names)[i] = talloc_strdup(*names, "");
2097 if (NT_STATUS_IS_OK(centry->status)) {
2100 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
2102 dom = centry_string(centry, mem_ctx);
2103 if (*domain_name == NULL) {
2109 (*names)[i] = centry_string(centry, *names);
2111 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)
2112 || NT_STATUS_EQUAL(centry->status, STATUS_SOME_UNMAPPED)) {
2113 have_unmapped = true;
2116 /* something's definitely wrong */
2117 result = centry->status;
2118 centry_free(centry);
2122 centry_free(centry);
2126 return NT_STATUS_NONE_MAPPED;
2128 if (!have_unmapped) {
2129 return NT_STATUS_OK;
2131 return STATUS_SOME_UNMAPPED;
2135 TALLOC_FREE(*names);
2136 TALLOC_FREE(*types);
2138 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
2139 rids, num_rids, domain_name,
2142 if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
2143 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2144 if (!domain->internal && old_status) {
2145 set_domain_offline(domain);
2148 !domain->internal &&
2151 have_mapped = have_unmapped = false;
2153 *names = talloc_array(mem_ctx, char *, num_rids);
2154 if (*names == NULL) {
2155 result = NT_STATUS_NO_MEMORY;
2159 *types = talloc_array(mem_ctx, enum lsa_SidType,
2161 if (*types == NULL) {
2162 result = NT_STATUS_NO_MEMORY;
2166 for (i=0; i<num_rids; i++) {
2168 struct cache_entry *centry;
2171 if (!sid_compose(&sid, domain_sid, rids[i])) {
2172 result = NT_STATUS_INTERNAL_ERROR;
2176 centry = wcache_fetch(cache, domain, "SN/%s",
2177 sid_to_fstring(tmp, &sid));
2179 (*types)[i] = SID_NAME_UNKNOWN;
2180 (*names)[i] = talloc_strdup(*names, "");
2184 (*types)[i] = SID_NAME_UNKNOWN;
2185 (*names)[i] = talloc_strdup(*names, "");
2187 if (NT_STATUS_IS_OK(centry->status)) {
2190 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
2192 dom = centry_string(centry, mem_ctx);
2193 if (*domain_name == NULL) {
2199 (*names)[i] = centry_string(centry, *names);
2201 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
2202 have_unmapped = true;
2205 /* something's definitely wrong */
2206 result = centry->status;
2207 centry_free(centry);
2211 centry_free(centry);
2215 return NT_STATUS_NONE_MAPPED;
2217 if (!have_unmapped) {
2218 return NT_STATUS_OK;
2220 return STATUS_SOME_UNMAPPED;
2224 None of the queried rids has been found so save all negative entries
2226 if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
2227 for (i = 0; i < num_rids; i++) {
2229 const char *name = "";
2230 const enum lsa_SidType type = SID_NAME_UNKNOWN;
2231 NTSTATUS status = NT_STATUS_NONE_MAPPED;
2233 if (!sid_compose(&sid, domain_sid, rids[i])) {
2234 return NT_STATUS_INTERNAL_ERROR;
2237 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2245 Some or all of the queried rids have been found.
2247 if (!NT_STATUS_IS_OK(result) &&
2248 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
2252 refresh_sequence_number(domain);
2254 for (i=0; i<num_rids; i++) {
2258 if (!sid_compose(&sid, domain_sid, rids[i])) {
2259 result = NT_STATUS_INTERNAL_ERROR;
2263 status = (*types)[i] == SID_NAME_UNKNOWN ?
2264 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
2266 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2267 (*names)[i], (*types)[i]);
2273 TALLOC_FREE(*names);
2274 TALLOC_FREE(*types);
2278 NTSTATUS wcache_query_user(struct winbindd_domain *domain,
2279 TALLOC_CTX *mem_ctx,
2280 const struct dom_sid *user_sid,
2281 struct wbint_userinfo *info)
2283 struct winbind_cache *cache = get_cache(domain);
2284 struct cache_entry *centry = NULL;
2288 if (cache->tdb == NULL) {
2289 return NT_STATUS_NOT_FOUND;
2292 sid_string = sid_string_tos(user_sid);
2293 if (sid_string == NULL) {
2294 return NT_STATUS_NO_MEMORY;
2297 centry = wcache_fetch(cache, domain, "U/%s", sid_string);
2298 TALLOC_FREE(sid_string);
2299 if (centry == NULL) {
2300 return NT_STATUS_NOT_FOUND;
2304 * If we have an access denied cache entry and a cached info3
2305 * in the samlogon cache then do a query. This will force the
2306 * rpc back end to return the info3 data.
2309 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED) &&
2310 netsamlogon_cache_have(user_sid)) {
2311 DEBUG(10, ("query_user: cached access denied and have cached "
2313 domain->last_status = NT_STATUS_OK;
2314 centry_free(centry);
2315 return NT_STATUS_NOT_FOUND;
2318 /* if status is not ok then this is a negative hit
2319 and the rest of the data doesn't matter */
2320 status = centry->status;
2321 if (NT_STATUS_IS_OK(status)) {
2322 info->domain_name = centry_string(centry, mem_ctx);
2323 info->acct_name = centry_string(centry, mem_ctx);
2324 info->full_name = centry_string(centry, mem_ctx);
2325 info->homedir = centry_string(centry, mem_ctx);
2326 info->shell = centry_string(centry, mem_ctx);
2327 info->uid = centry_uint32(centry);
2328 info->primary_gid = centry_uint32(centry);
2329 info->primary_group_name = centry_string(centry, mem_ctx);
2330 centry_sid(centry, &info->user_sid);
2331 centry_sid(centry, &info->group_sid);
2334 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2335 "%s\n", domain->name, nt_errstr(status) ));
2337 centry_free(centry);
2343 * @brief Query a fullname from the username cache (for further gecos processing)
2345 * @param domain A pointer to the winbindd_domain struct.
2346 * @param mem_ctx The talloc context.
2347 * @param user_sid The user sid.
2348 * @param full_name A pointer to the full_name string.
2350 * @return NTSTATUS code
2352 NTSTATUS wcache_query_user_fullname(struct winbindd_domain *domain,
2353 TALLOC_CTX *mem_ctx,
2354 const struct dom_sid *user_sid,
2355 const char **full_name)
2358 struct wbint_userinfo info;
2360 status = wcache_query_user(domain, mem_ctx, user_sid, &info);
2361 if (!NT_STATUS_IS_OK(status)) {
2365 if (info.full_name != NULL) {
2366 *full_name = talloc_strdup(mem_ctx, info.full_name);
2367 if (*full_name == NULL) {
2368 return NT_STATUS_NO_MEMORY;
2372 return NT_STATUS_OK;
2375 static char *wcache_make_sidlist(TALLOC_CTX *mem_ctx, uint32_t num_sids,
2376 const struct dom_sid *sids)
2381 sidlist = talloc_strdup(mem_ctx, "");
2382 if (sidlist == NULL) {
2385 for (i=0; i<num_sids; i++) {
2387 sidlist = talloc_asprintf_append_buffer(
2388 sidlist, "/%s", sid_to_fstring(tmp, &sids[i]));
2389 if (sidlist == NULL) {
2396 NTSTATUS wcache_lookup_useraliases(struct winbindd_domain *domain,
2397 TALLOC_CTX *mem_ctx, uint32_t num_sids,
2398 const struct dom_sid *sids,
2399 uint32_t *pnum_aliases, uint32_t **paliases)
2401 struct winbind_cache *cache = get_cache(domain);
2402 struct cache_entry *centry = NULL;
2403 uint32_t num_aliases;
2409 if (cache->tdb == NULL) {
2410 return NT_STATUS_NOT_FOUND;
2413 if (num_sids == 0) {
2416 return NT_STATUS_OK;
2419 /* We need to cache indexed by the whole list of SIDs, the aliases
2420 * resulting might come from any of the SIDs. */
2422 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2423 if (sidlist == NULL) {
2424 return NT_STATUS_NO_MEMORY;
2427 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
2428 TALLOC_FREE(sidlist);
2429 if (centry == NULL) {
2430 return NT_STATUS_NOT_FOUND;
2433 num_aliases = centry_uint32(centry);
2434 aliases = talloc_array(mem_ctx, uint32_t, num_aliases);
2435 if (aliases == NULL) {
2436 centry_free(centry);
2437 return NT_STATUS_NO_MEMORY;
2440 for (i=0; i<num_aliases; i++) {
2441 aliases[i] = centry_uint32(centry);
2444 status = centry->status;
2446 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2447 "status %s\n", domain->name, nt_errstr(status)));
2449 centry_free(centry);
2451 *pnum_aliases = num_aliases;
2452 *paliases = aliases;
2457 NTSTATUS wb_cache_lookup_useraliases(struct winbindd_domain *domain,
2458 TALLOC_CTX *mem_ctx,
2460 const struct dom_sid *sids,
2461 uint32_t *num_aliases,
2462 uint32_t **alias_rids)
2464 struct cache_entry *centry = NULL;
2470 old_status = domain->online;
2471 status = wcache_lookup_useraliases(domain, mem_ctx, num_sids, sids,
2472 num_aliases, alias_rids);
2473 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2478 (*alias_rids) = NULL;
2480 if (!NT_STATUS_IS_OK(domain->last_status))
2481 return domain->last_status;
2483 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2484 "for domain %s\n", domain->name ));
2486 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2487 if (sidlist == NULL) {
2488 return NT_STATUS_NO_MEMORY;
2491 status = domain->backend->lookup_useraliases(domain, mem_ctx,
2493 num_aliases, alias_rids);
2495 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2496 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2497 if (!domain->internal && old_status) {
2498 set_domain_offline(domain);
2500 if (!domain->internal &&
2503 NTSTATUS cache_status;
2504 cache_status = wcache_lookup_useraliases(domain, mem_ctx, num_sids,
2505 sids, num_aliases, alias_rids);
2506 return cache_status;
2510 refresh_sequence_number(domain);
2511 if (!NT_STATUS_IS_OK(status)) {
2514 centry = centry_start(domain, status);
2517 centry_put_uint32(centry, *num_aliases);
2518 for (i=0; i<(*num_aliases); i++)
2519 centry_put_uint32(centry, (*alias_rids)[i]);
2520 centry_end(centry, "UA%s", sidlist);
2521 centry_free(centry);
2527 NTSTATUS wcache_lookup_groupmem(struct winbindd_domain *domain,
2528 TALLOC_CTX *mem_ctx,
2529 const struct dom_sid *group_sid,
2530 uint32_t *num_names,
2531 struct dom_sid **sid_mem, char ***names,
2532 uint32_t **name_types)
2534 struct winbind_cache *cache = get_cache(domain);
2535 struct cache_entry *centry = NULL;
2540 if (cache->tdb == NULL) {
2541 return NT_STATUS_NOT_FOUND;
2544 sid_string = sid_string_tos(group_sid);
2545 if (sid_string == NULL) {
2546 return NT_STATUS_NO_MEMORY;
2549 centry = wcache_fetch(cache, domain, "GM/%s", sid_string);
2550 TALLOC_FREE(sid_string);
2551 if (centry == NULL) {
2552 return NT_STATUS_NOT_FOUND;
2559 *num_names = centry_uint32(centry);
2560 if (*num_names == 0) {
2561 centry_free(centry);
2562 return NT_STATUS_OK;
2565 *sid_mem = talloc_array(mem_ctx, struct dom_sid, *num_names);
2566 *names = talloc_array(mem_ctx, char *, *num_names);
2567 *name_types = talloc_array(mem_ctx, uint32_t, *num_names);
2569 if ((*sid_mem == NULL) || (*names == NULL) || (*name_types == NULL)) {
2570 TALLOC_FREE(*sid_mem);
2571 TALLOC_FREE(*names);
2572 TALLOC_FREE(*name_types);
2573 centry_free(centry);
2574 return NT_STATUS_NO_MEMORY;
2577 for (i=0; i<(*num_names); i++) {
2578 centry_sid(centry, &(*sid_mem)[i]);
2579 (*names)[i] = centry_string(centry, mem_ctx);
2580 (*name_types)[i] = centry_uint32(centry);
2583 status = centry->status;
2585 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2586 "status: %s\n", domain->name, nt_errstr(status)));
2588 centry_free(centry);
2592 NTSTATUS wb_cache_lookup_groupmem(struct winbindd_domain *domain,
2593 TALLOC_CTX *mem_ctx,
2594 const struct dom_sid *group_sid,
2595 enum lsa_SidType type,
2596 uint32_t *num_names,
2597 struct dom_sid **sid_mem,
2599 uint32_t **name_types)
2601 struct cache_entry *centry = NULL;
2607 old_status = domain->online;
2608 status = wcache_lookup_groupmem(domain, mem_ctx, group_sid, num_names,
2609 sid_mem, names, name_types);
2610 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2617 (*name_types) = NULL;
2619 /* Return status value returned by seq number check */
2621 if (!NT_STATUS_IS_OK(domain->last_status))
2622 return domain->last_status;
2624 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2627 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid,
2629 sid_mem, names, name_types);
2631 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2632 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2633 if (!domain->internal && old_status) {
2634 set_domain_offline(domain);
2636 if (!domain->internal &&
2639 NTSTATUS cache_status;
2640 cache_status = wcache_lookup_groupmem(domain, mem_ctx, group_sid,
2641 num_names, sid_mem, names,
2643 return cache_status;
2647 refresh_sequence_number(domain);
2648 if (!NT_STATUS_IS_OK(status)) {
2651 centry = centry_start(domain, status);
2654 centry_put_uint32(centry, *num_names);
2655 for (i=0; i<(*num_names); i++) {
2656 centry_put_sid(centry, &(*sid_mem)[i]);
2657 centry_put_string(centry, (*names)[i]);
2658 centry_put_uint32(centry, (*name_types)[i]);
2660 centry_end(centry, "GM/%s", sid_to_fstring(sid_string, group_sid));
2661 centry_free(centry);
2667 /* find the sequence number for a domain */
2668 NTSTATUS wb_cache_sequence_number(struct winbindd_domain *domain,
2671 refresh_sequence_number(domain);
2673 *seq = domain->sequence_number;
2675 return NT_STATUS_OK;
2678 /* enumerate trusted domains
2679 * (we need to have the list of trustdoms in the cache when we go offline) -
2681 NTSTATUS wb_cache_trusted_domains(struct winbindd_domain *domain,
2682 TALLOC_CTX *mem_ctx,
2683 struct netr_DomainTrustList *trusts)
2686 struct winbind_cache *cache;
2687 struct winbindd_tdc_domain *dom_list = NULL;
2688 size_t num_domains = 0;
2689 bool retval = false;
2693 old_status = domain->online;
2695 trusts->array = NULL;
2697 cache = get_cache(domain);
2698 if (!cache || !cache->tdb) {
2702 if (domain->online) {
2706 retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2707 if (!retval || !num_domains || !dom_list) {
2708 TALLOC_FREE(dom_list);
2713 trusts->array = talloc_zero_array(mem_ctx, struct netr_DomainTrust, num_domains);
2714 if (!trusts->array) {
2715 TALLOC_FREE(dom_list);
2716 return NT_STATUS_NO_MEMORY;
2719 for (i = 0; i < num_domains; i++) {
2720 struct netr_DomainTrust *trust;
2721 struct dom_sid *sid;
2722 struct winbindd_domain *dom;
2724 dom = find_domain_from_name_noinit(dom_list[i].domain_name);
2725 if (dom && dom->internal) {
2729 trust = &trusts->array[trusts->count];
2730 trust->netbios_name = talloc_strdup(trusts->array, dom_list[i].domain_name);
2731 trust->dns_name = talloc_strdup(trusts->array, dom_list[i].dns_name);
2732 sid = talloc(trusts->array, struct dom_sid);
2733 if (!trust->netbios_name || !trust->dns_name ||
2735 TALLOC_FREE(dom_list);
2736 TALLOC_FREE(trusts->array);
2737 return NT_STATUS_NO_MEMORY;
2740 trust->trust_flags = dom_list[i].trust_flags;
2741 trust->trust_attributes = dom_list[i].trust_attribs;
2742 trust->trust_type = dom_list[i].trust_type;
2743 sid_copy(sid, &dom_list[i].sid);
2748 TALLOC_FREE(dom_list);
2749 return NT_STATUS_OK;
2752 /* Return status value returned by seq number check */
2754 if (!NT_STATUS_IS_OK(domain->last_status))
2755 return domain->last_status;
2757 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2760 status = domain->backend->trusted_domains(domain, mem_ctx, trusts);
2762 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2763 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2764 if (!domain->internal && old_status) {
2765 set_domain_offline(domain);
2767 if (!domain->internal &&
2770 retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2771 if (retval && num_domains && dom_list) {
2772 TALLOC_FREE(trusts->array);
2774 goto do_fetch_cache;
2778 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2779 * so that the generic centry handling still applies correctly -
2782 if (!NT_STATUS_IS_ERR(status)) {
2783 status = NT_STATUS_OK;
2788 /* get lockout policy */
2789 NTSTATUS wb_cache_lockout_policy(struct winbindd_domain *domain,
2790 TALLOC_CTX *mem_ctx,
2791 struct samr_DomInfo12 *policy)
2793 struct winbind_cache *cache = get_cache(domain);
2794 struct cache_entry *centry = NULL;
2798 old_status = domain->online;
2802 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2808 policy->lockout_duration = centry_nttime(centry);
2809 policy->lockout_window = centry_nttime(centry);
2810 policy->lockout_threshold = centry_uint16(centry);
2812 status = centry->status;
2814 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2815 domain->name, nt_errstr(status) ));
2817 centry_free(centry);
2821 ZERO_STRUCTP(policy);
2823 /* Return status value returned by seq number check */
2825 if (!NT_STATUS_IS_OK(domain->last_status))
2826 return domain->last_status;
2828 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2831 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2833 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2834 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2835 if (!domain->internal && old_status) {
2836 set_domain_offline(domain);
2839 !domain->internal &&
2842 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2844 goto do_fetch_cache;
2849 refresh_sequence_number(domain);
2850 if (!NT_STATUS_IS_OK(status)) {
2853 wcache_save_lockout_policy(domain, status, policy);
2858 /* get password policy */
2859 NTSTATUS wb_cache_password_policy(struct winbindd_domain *domain,
2860 TALLOC_CTX *mem_ctx,
2861 struct samr_DomInfo1 *policy)
2863 struct winbind_cache *cache = get_cache(domain);
2864 struct cache_entry *centry = NULL;
2868 old_status = domain->online;
2872 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2878 policy->min_password_length = centry_uint16(centry);
2879 policy->password_history_length = centry_uint16(centry);
2880 policy->password_properties = centry_uint32(centry);
2881 policy->max_password_age = centry_nttime(centry);
2882 policy->min_password_age = centry_nttime(centry);
2884 status = centry->status;
2886 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2887 domain->name, nt_errstr(status) ));
2889 centry_free(centry);
2893 ZERO_STRUCTP(policy);
2895 /* Return status value returned by seq number check */
2897 if (!NT_STATUS_IS_OK(domain->last_status))
2898 return domain->last_status;
2900 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2903 status = domain->backend->password_policy(domain, mem_ctx, policy);
2905 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2906 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2907 if (!domain->internal && old_status) {
2908 set_domain_offline(domain);
2911 !domain->internal &&
2914 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2916 goto do_fetch_cache;
2921 refresh_sequence_number(domain);
2922 if (!NT_STATUS_IS_OK(status)) {
2925 wcache_save_password_policy(domain, status, policy);
2931 /* Invalidate cached user and group lists coherently */
2933 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2936 if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
2937 strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
2938 tdb_delete(the_tdb, kbuf);
2943 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2945 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
2946 const struct dom_sid *sid)
2948 fstring key_str, sid_string;
2949 struct winbind_cache *cache;
2951 /* don't clear cached U/SID and UG/SID entries when we want to logon
2954 if (lp_winbind_offline_logon()) {
2961 cache = get_cache(domain);
2967 /* Clear U/SID cache entry */
2968 fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, sid));
2969 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
2970 tdb_delete(cache->tdb, string_tdb_data(key_str));
2972 /* Samba/winbindd never needs this. */
2973 netsamlogon_clear_cached_user(sid);
2976 bool wcache_invalidate_cache(void)
2978 struct winbindd_domain *domain;
2980 for (domain = domain_list(); domain; domain = domain->next) {
2981 struct winbind_cache *cache = get_cache(domain);
2983 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2984 "entries for %s\n", domain->name));
2987 tdb_traverse(cache->tdb, traverse_fn, NULL);
2996 bool wcache_invalidate_cache_noinit(void)
2998 struct winbindd_domain *domain;
3000 for (domain = domain_list(); domain; domain = domain->next) {
3001 struct winbind_cache *cache;
3003 /* Skip uninitialized domains. */
3004 if (!domain->initialized && !domain->internal) {
3008 cache = get_cache(domain);
3010 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3011 "entries for %s\n", domain->name));
3014 tdb_traverse(cache->tdb, traverse_fn, NULL);
3016 * Flushing cache has nothing to with domains.
3017 * return here if we successfully flushed once.
3018 * To avoid unnecessary traversing the cache.
3029 bool init_wcache(void)
3033 if (wcache == NULL) {
3034 wcache = SMB_XMALLOC_P(struct winbind_cache);
3035 ZERO_STRUCTP(wcache);
3038 if (wcache->tdb != NULL)
3041 db_path = wcache_path();
3042 if (db_path == NULL) {
3046 /* when working offline we must not clear the cache on restart */
3047 wcache->tdb = tdb_open_log(db_path,
3048 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3049 TDB_INCOMPATIBLE_HASH |
3050 (lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
3051 O_RDWR|O_CREAT, 0600);
3052 TALLOC_FREE(db_path);
3053 if (wcache->tdb == NULL) {
3054 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3061 /************************************************************************
3062 This is called by the parent to initialize the cache file.
3063 We don't need sophisticated locking here as we know we're the
3065 ************************************************************************/
3067 bool initialize_winbindd_cache(void)
3069 bool cache_bad = true;
3072 if (!init_wcache()) {
3073 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3077 /* Check version number. */
3078 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
3079 vers == WINBINDD_CACHE_VERSION) {
3086 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3087 "and re-creating with version number %d\n",
3088 WINBINDD_CACHE_VERSION ));
3090 tdb_close(wcache->tdb);
3093 db_path = wcache_path();
3094 if (db_path == NULL) {
3098 if (unlink(db_path) == -1) {
3099 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3102 TALLOC_FREE(db_path);
3105 TALLOC_FREE(db_path);
3106 if (!init_wcache()) {
3107 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3108 "init_wcache failed.\n"));
3112 /* Write the version. */
3113 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
3114 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3115 tdb_errorstr(wcache->tdb) ));
3120 tdb_close(wcache->tdb);
3125 void close_winbindd_cache(void)
3131 tdb_close(wcache->tdb);
3136 bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
3137 char **domain_name, char **name,
3138 enum lsa_SidType *type)
3140 struct winbindd_domain *domain;
3143 domain = find_lookup_domain_from_sid(sid);
3144 if (domain == NULL) {
3147 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
3149 return NT_STATUS_IS_OK(status);
3152 bool lookup_cached_name(const char *domain_name,
3154 struct dom_sid *sid,
3155 enum lsa_SidType *type)
3157 struct winbindd_domain *domain;
3159 bool original_online_state;
3161 domain = find_lookup_domain_from_name(domain_name);
3162 if (domain == NULL) {
3166 /* If we are doing a cached logon, temporarily set the domain
3167 offline so the cache won't expire the entry */
3169 original_online_state = domain->online;
3170 domain->online = false;
3171 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
3172 domain->online = original_online_state;
3174 return NT_STATUS_IS_OK(status);
3178 * Cache a name to sid without checking the sequence number.
3179 * Used when caching from a trusted PAC.
3182 void cache_name2sid_trusted(struct winbindd_domain *domain,
3183 const char *domain_name,
3185 enum lsa_SidType type,
3186 const struct dom_sid *sid)
3189 * Ensure we store the mapping with the
3190 * existing sequence number from the cache.
3193 (void)fetch_cache_seqnum(domain, time(NULL));
3194 wcache_save_name_to_sid(domain,
3202 void cache_name2sid(struct winbindd_domain *domain,
3203 const char *domain_name, const char *name,
3204 enum lsa_SidType type, const struct dom_sid *sid)
3206 refresh_sequence_number(domain);
3207 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
3212 * The original idea that this cache only contains centries has
3213 * been blurred - now other stuff gets put in here. Ensure we
3214 * ignore these things on cleanup.
3217 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
3218 TDB_DATA dbuf, void *state)
3220 struct cache_entry *centry;
3222 if (is_non_centry_key(kbuf)) {
3226 centry = wcache_fetch_raw((char *)kbuf.dptr);
3231 if (!NT_STATUS_IS_OK(centry->status)) {
3232 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
3233 tdb_delete(the_tdb, kbuf);
3236 centry_free(centry);
3240 /* flush the cache */
3241 void wcache_flush_cache(void)
3248 tdb_close(wcache->tdb);
3251 if (!winbindd_use_cache()) {
3255 db_path = wcache_path();
3256 if (db_path == NULL) {
3260 /* when working offline we must not clear the cache on restart */
3261 wcache->tdb = tdb_open_log(db_path,
3262 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3263 TDB_INCOMPATIBLE_HASH |
3264 (lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
3265 O_RDWR|O_CREAT, 0600);
3266 TALLOC_FREE(db_path);
3268 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3272 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
3274 DEBUG(10,("wcache_flush_cache success\n"));
3277 /* Count cached creds */
3279 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3282 int *cred_count = (int*)state;
3284 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3290 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
3292 struct winbind_cache *cache = get_cache(domain);
3297 return NT_STATUS_INTERNAL_DB_ERROR;
3300 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
3302 return NT_STATUS_OK;
3306 struct cred_list *prev, *next;
3311 static struct cred_list *wcache_cred_list;
3313 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3316 struct cred_list *cred;
3318 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3320 cred = SMB_MALLOC_P(struct cred_list);
3322 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3328 /* save a copy of the key */
3330 fstrcpy(cred->name, (const char *)kbuf.dptr);
3331 DLIST_ADD(wcache_cred_list, cred);
3337 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const struct dom_sid *sid)
3339 struct winbind_cache *cache = get_cache(domain);
3342 struct cred_list *cred, *next, *oldest = NULL;
3345 return NT_STATUS_INTERNAL_DB_ERROR;
3348 /* we possibly already have an entry */
3349 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
3351 fstring key_str, tmp;
3353 DEBUG(11,("we already have an entry, deleting that\n"));
3355 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
3357 tdb_delete(cache->tdb, string_tdb_data(key_str));
3359 return NT_STATUS_OK;
3362 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
3364 return NT_STATUS_OK;
3365 } else if ((ret < 0) || (wcache_cred_list == NULL)) {
3366 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3369 ZERO_STRUCTP(oldest);
3371 for (cred = wcache_cred_list; cred; cred = cred->next) {
3376 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
3378 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3380 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
3384 t = IVAL(data.dptr, 0);
3385 SAFE_FREE(data.dptr);
3388 oldest = SMB_MALLOC_P(struct cred_list);
3389 if (oldest == NULL) {
3390 status = NT_STATUS_NO_MEMORY;
3394 fstrcpy(oldest->name, cred->name);
3395 oldest->created = t;
3399 if (t < oldest->created) {
3400 fstrcpy(oldest->name, cred->name);
3401 oldest->created = t;
3405 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
3406 status = NT_STATUS_OK;
3408 status = NT_STATUS_UNSUCCESSFUL;
3411 for (cred = wcache_cred_list; cred; cred = next) {
3413 DLIST_REMOVE(wcache_cred_list, cred);
3421 /* Change the global online/offline state. */
3422 bool set_global_winbindd_state_offline(void)
3426 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3428 /* Only go offline if someone has created
3429 the key "WINBINDD_OFFLINE" in the cache tdb. */
3431 if (wcache == NULL || wcache->tdb == NULL) {
3432 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3436 if (!lp_winbind_offline_logon()) {
3437 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3441 if (global_winbindd_offline_state) {
3442 /* Already offline. */
3446 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
3448 if (!data.dptr || data.dsize != 4) {
3449 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3450 SAFE_FREE(data.dptr);
3453 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3454 global_winbindd_offline_state = true;
3455 SAFE_FREE(data.dptr);
3460 void set_global_winbindd_state_online(void)
3462 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3464 if (!lp_winbind_offline_logon()) {
3465 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3469 if (!global_winbindd_offline_state) {
3470 /* Already online. */
3473 global_winbindd_offline_state = false;
3479 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3480 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
3483 bool get_global_winbindd_state_offline(void)
3485 return global_winbindd_offline_state;
3488 /***********************************************************************
3489 Validate functions for all possible cache tdb keys.
3490 ***********************************************************************/
3492 static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
3493 struct tdb_validation_status *state)
3495 struct cache_entry *centry;
3497 centry = SMB_XMALLOC_P(struct cache_entry);
3498 centry->data = (unsigned char *)smb_memdup(data.dptr, data.dsize);
3499 if (!centry->data) {
3503 centry->len = data.dsize;
3506 if (centry->len < 16) {
3507 /* huh? corrupt cache? */
3508 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3509 "(len < 16) ?\n", kstr));
3510 centry_free(centry);
3511 state->bad_entry = true;
3512 state->success = false;
3516 centry->status = NT_STATUS(centry_uint32(centry));
3517 centry->sequence_number = centry_uint32(centry);
3518 centry->timeout = centry_uint64_t(centry);
3522 static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3523 struct tdb_validation_status *state)
3525 if (dbuf.dsize != 8) {
3526 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3527 keystr, (unsigned int)dbuf.dsize ));
3528 state->bad_entry = true;
3534 static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3535 struct tdb_validation_status *state)
3537 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3542 (void)centry_uint32(centry);
3543 if (NT_STATUS_IS_OK(centry->status)) {
3545 (void)centry_sid(centry, &sid);
3548 centry_free(centry);
3550 if (!(state->success)) {
3553 DEBUG(10,("validate_ns: %s ok\n", keystr));
3557 static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3558 struct tdb_validation_status *state)
3560 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3565 if (NT_STATUS_IS_OK(centry->status)) {
3566 (void)centry_uint32(centry);
3567 (void)centry_string(centry, mem_ctx);
3568 (void)centry_string(centry, mem_ctx);
3571 centry_free(centry);
3573 if (!(state->success)) {
3576 DEBUG(10,("validate_sn: %s ok\n", keystr));
3580 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3581 struct tdb_validation_status *state)
3583 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3590 (void)centry_string(centry, mem_ctx);
3591 (void)centry_string(centry, mem_ctx);
3592 (void)centry_string(centry, mem_ctx);
3593 (void)centry_string(centry, mem_ctx);
3594 (void)centry_string(centry, mem_ctx);
3595 (void)centry_uint32(centry);
3596 (void)centry_uint32(centry);
3597 (void)centry_string(centry, mem_ctx);
3598 (void)centry_sid(centry, &sid);
3599 (void)centry_sid(centry, &sid);
3601 centry_free(centry);
3603 if (!(state->success)) {
3606 DEBUG(10,("validate_u: %s ok\n", keystr));
3610 static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3611 struct tdb_validation_status *state)
3613 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3619 (void)centry_nttime(centry);
3620 (void)centry_nttime(centry);
3621 (void)centry_uint16(centry);
3623 centry_free(centry);
3625 if (!(state->success)) {
3628 DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
3632 static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3633 struct tdb_validation_status *state)
3635 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3641 (void)centry_uint16(centry);
3642 (void)centry_uint16(centry);
3643 (void)centry_uint32(centry);
3644 (void)centry_nttime(centry);
3645 (void)centry_nttime(centry);
3647 centry_free(centry);
3649 if (!(state->success)) {
3652 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
3656 static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3657 struct tdb_validation_status *state)
3659 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3665 (void)centry_time(centry);
3666 (void)centry_hash16(centry, mem_ctx);
3668 /* We only have 17 bytes more data in the salted cred case. */
3669 if (centry->len - centry->ofs == 17) {
3670 (void)centry_hash16(centry, mem_ctx);
3673 centry_free(centry);
3675 if (!(state->success)) {
3678 DEBUG(10,("validate_cred: %s ok\n", keystr));
3682 static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3683 struct tdb_validation_status *state)
3685 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3686 int32_t num_entries, i;
3692 num_entries = (int32_t)centry_uint32(centry);
3694 for (i=0; i< num_entries; i++) {
3696 (void)centry_string(centry, mem_ctx);
3697 (void)centry_string(centry, mem_ctx);
3698 (void)centry_string(centry, mem_ctx);
3699 (void)centry_string(centry, mem_ctx);
3700 (void)centry_string(centry, mem_ctx);
3701 (void)centry_uint32(centry);
3702 (void)centry_uint32(centry);
3703 (void)centry_string(centry, mem_ctx);
3704 (void)centry_sid(centry, &sid);
3705 (void)centry_sid(centry, &sid);
3708 centry_free(centry);
3710 if (!(state->success)) {
3713 DEBUG(10,("validate_ul: %s ok\n", keystr));
3717 static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3718 struct tdb_validation_status *state)
3720 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3721 int32_t num_entries, i;
3727 num_entries = centry_uint32(centry);
3729 for (i=0; i< num_entries; i++) {
3730 (void)centry_string(centry, mem_ctx);
3731 (void)centry_string(centry, mem_ctx);
3732 (void)centry_uint32(centry);
3735 centry_free(centry);
3737 if (!(state->success)) {
3740 DEBUG(10,("validate_gl: %s ok\n", keystr));
3744 static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3745 struct tdb_validation_status *state)
3747 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3748 int32_t num_aliases, i;
3754 num_aliases = centry_uint32(centry);
3756 for (i=0; i < num_aliases; i++) {
3757 (void)centry_uint32(centry);
3760 centry_free(centry);
3762 if (!(state->success)) {
3765 DEBUG(10,("validate_ua: %s ok\n", keystr));
3769 static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3770 struct tdb_validation_status *state)
3772 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3773 int32_t num_names, i;
3779 num_names = centry_uint32(centry);
3781 for (i=0; i< num_names; i++) {
3783 centry_sid(centry, &sid);
3784 (void)centry_string(centry, mem_ctx);
3785 (void)centry_uint32(centry);
3788 centry_free(centry);
3790 if (!(state->success)) {
3793 DEBUG(10,("validate_gm: %s ok\n", keystr));
3797 static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3798 struct tdb_validation_status *state)
3800 /* Can't say anything about this other than must be nonzero. */
3801 if (dbuf.dsize == 0) {
3802 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3804 state->bad_entry = true;
3805 state->success = false;
3809 DEBUG(10,("validate_dr: %s ok\n", keystr));
3813 static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3814 struct tdb_validation_status *state)
3816 /* Can't say anything about this other than must be nonzero. */
3817 if (dbuf.dsize == 0) {
3818 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3820 state->bad_entry = true;
3821 state->success = false;
3825 DEBUG(10,("validate_de: %s ok\n", keystr));
3829 static int validate_pwinfo(TALLOC_CTX *mem_ctx, const char *keystr,
3830 TDB_DATA dbuf, struct tdb_validation_status *state)
3832 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3838 (void)centry_string(centry, mem_ctx);
3839 (void)centry_string(centry, mem_ctx);
3840 (void)centry_string(centry, mem_ctx);
3841 (void)centry_uint32(centry);
3843 centry_free(centry);
3845 if (!(state->success)) {
3848 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3852 static int validate_nss_an(TALLOC_CTX *mem_ctx, const char *keystr,
3854 struct tdb_validation_status *state)
3856 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3862 (void)centry_string( centry, mem_ctx );
3864 centry_free(centry);
3866 if (!(state->success)) {
3869 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3873 static int validate_nss_na(TALLOC_CTX *mem_ctx, const char *keystr,
3875 struct tdb_validation_status *state)
3877 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3883 (void)centry_string( centry, mem_ctx );
3885 centry_free(centry);
3887 if (!(state->success)) {
3890 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3894 static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
3896 struct tdb_validation_status *state)
3898 if (dbuf.dsize == 0) {
3899 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3900 "key %s (len ==0) ?\n", keystr));
3901 state->bad_entry = true;
3902 state->success = false;
3906 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
3907 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3911 static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3912 struct tdb_validation_status *state)
3914 if (dbuf.dsize != 4) {
3915 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3916 keystr, (unsigned int)dbuf.dsize ));
3917 state->bad_entry = true;
3918 state->success = false;
3921 DEBUG(10,("validate_offline: %s ok\n", keystr));
3925 static int validate_ndr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3926 struct tdb_validation_status *state)
3929 * Ignore validation for now. The proper way to do this is with a
3930 * checksum. Just pure parsing does not really catch much.
3935 static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3936 struct tdb_validation_status *state)
3938 if (dbuf.dsize != 4) {
3939 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3940 "key %s (len %u != 4) ?\n",
3941 keystr, (unsigned int)dbuf.dsize));
3942 state->bad_entry = true;
3943 state->success = false;
3947 DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
3951 /***********************************************************************
3952 A list of all possible cache tdb keys with associated validation
3954 ***********************************************************************/
3956 struct key_val_struct {
3957 const char *keyname;
3958 int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
3960 {"SEQNUM/", validate_seqnum},
3961 {"NS/", validate_ns},
3962 {"SN/", validate_sn},
3964 {"LOC_POL/", validate_loc_pol},
3965 {"PWD_POL/", validate_pwd_pol},
3966 {"CRED/", validate_cred},
3967 {"UL/", validate_ul},
3968 {"GL/", validate_gl},
3969 {"UA", validate_ua},
3970 {"GM/", validate_gm},
3971 {"DR/", validate_dr},
3972 {"DE/", validate_de},
3973 {"NSS/PWINFO/", validate_pwinfo},
3974 {"TRUSTDOMCACHE/", validate_trustdomcache},
3975 {"NSS/NA/", validate_nss_na},
3976 {"NSS/AN/", validate_nss_an},
3977 {"WINBINDD_OFFLINE", validate_offline},
3978 {"NDR/", validate_ndr},
3979 {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
3983 /***********************************************************************
3984 Function to look at every entry in the tdb and validate it as far as
3986 ***********************************************************************/
3988 static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
3991 unsigned int max_key_len = 1024;
3992 struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
3994 /* Paranoia check. */
3995 if (strncmp("UA/", (const char *)kbuf.dptr, 3) == 0 ||
3996 strncmp("NDR/", (const char *)kbuf.dptr, 4) == 0) {
3997 max_key_len = 1024 * 1024;
3999 if (kbuf.dsize > max_key_len) {
4000 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4002 (unsigned int)kbuf.dsize, (unsigned int)max_key_len));
4006 for (i = 0; key_val[i].keyname; i++) {
4007 size_t namelen = strlen(key_val[i].keyname);
4008 if (kbuf.dsize >= namelen && (
4009 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
4010 TALLOC_CTX *mem_ctx;
4014 keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
4018 memcpy(keystr, kbuf.dptr, kbuf.dsize);
4019 keystr[kbuf.dsize] = '\0';
4021 mem_ctx = talloc_init("validate_ctx");
4027 ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
4031 talloc_destroy(mem_ctx);
4036 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4037 dump_data(0, (uint8_t *)kbuf.dptr, kbuf.dsize);
4038 DEBUG(0,("data :\n"));
4039 dump_data(0, (uint8_t *)dbuf.dptr, dbuf.dsize);
4040 v_state->unknown_key = true;
4041 v_state->success = false;
4042 return 1; /* terminate. */
4045 static void validate_panic(const char *const why)
4047 DEBUG(0,("validating cache: would panic %s\n", why ));
4048 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4052 static int wbcache_update_centry_fn(TDB_CONTEXT *tdb,
4060 if (is_non_centry_key(key)) {
4064 if (data.dptr == NULL || data.dsize == 0) {
4065 if (tdb_delete(tdb, key) < 0) {
4066 DEBUG(0, ("tdb_delete for [%s] failed!\n",
4072 /* add timeout to blob (uint64_t) */
4073 blob.dsize = data.dsize + 8;
4075 blob.dptr = SMB_XMALLOC_ARRAY(uint8_t, blob.dsize);
4076 if (blob.dptr == NULL) {
4079 memset(blob.dptr, 0, blob.dsize);
4081 /* copy status and seqnum */
4082 memcpy(blob.dptr, data.dptr, 8);
4085 ctimeout = lp_winbind_cache_time() + time(NULL);
4086 SBVAL(blob.dptr, 8, ctimeout);
4089 memcpy(blob.dptr + 16, data.dptr + 8, data.dsize - 8);
4091 if (tdb_store(tdb, key, blob, TDB_REPLACE) < 0) {
4092 DEBUG(0, ("tdb_store to update [%s] failed!\n",
4094 SAFE_FREE(blob.dptr);
4098 SAFE_FREE(blob.dptr);
4102 static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT *tdb)
4106 DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
4108 rc = tdb_traverse(tdb, wbcache_update_centry_fn, NULL);
4116 /***********************************************************************
4117 Try and validate every entry in the winbindd cache. If we fail here,
4118 delete the cache tdb and return non-zero.
4119 ***********************************************************************/
4121 int winbindd_validate_cache(void)
4124 char *tdb_path = NULL;
4125 TDB_CONTEXT *tdb = NULL;
4129 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4130 smb_panic_fn = validate_panic;
4132 tdb_path = wcache_path();
4133 if (tdb_path == NULL) {
4137 tdb = tdb_open_log(tdb_path,
4138 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
4139 TDB_INCOMPATIBLE_HASH |
4140 ( lp_winbind_offline_logon()
4142 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
4146 DEBUG(0, ("winbindd_validate_cache: "
4147 "error opening/initializing tdb\n"));
4151 /* Version check and upgrade code. */
4152 if (!tdb_fetch_uint32(tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers_id)) {
4153 DEBUG(10, ("Fresh database\n"));
4154 tdb_store_uint32(tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION);
4155 vers_id = WINBINDD_CACHE_VERSION;
4158 if (vers_id != WINBINDD_CACHE_VERSION) {
4159 if (vers_id == WINBINDD_CACHE_VER1) {
4160 ok = wbcache_upgrade_v1_to_v2(tdb);
4162 DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
4167 tdb_store_uint32(tdb,
4168 WINBINDD_CACHE_VERSION_KEYSTR,
4169 WINBINDD_CACHE_VERSION);
4170 vers_id = WINBINDD_CACHE_VER2;
4176 ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
4179 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4180 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
4185 TALLOC_FREE(tdb_path);
4186 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4187 smb_panic_fn = smb_panic;
4191 /***********************************************************************
4192 Try and validate every entry in the winbindd cache.
4193 ***********************************************************************/
4195 int winbindd_validate_cache_nobackup(void)
4200 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4201 smb_panic_fn = validate_panic;
4203 tdb_path = wcache_path();
4204 if (tdb_path == NULL) {
4205 goto err_panic_restore;
4208 if (wcache == NULL || wcache->tdb == NULL) {
4209 ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
4211 ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
4215 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4219 TALLOC_FREE(tdb_path);
4221 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4223 smb_panic_fn = smb_panic;
4227 bool winbindd_cache_validate_and_initialize(void)
4229 close_winbindd_cache();
4231 if (lp_winbind_offline_logon()) {
4232 if (winbindd_validate_cache() < 0) {
4233 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4234 "could be restored.\n"));
4238 return initialize_winbindd_cache();
4241 /*********************************************************************
4242 ********************************************************************/
4244 static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
4245 struct winbindd_tdc_domain **domains,
4246 size_t *num_domains )
4248 struct winbindd_tdc_domain *list = NULL;
4251 bool set_only = false;
4253 /* don't allow duplicates */
4258 for ( i=0; i< (*num_domains); i++ ) {
4259 if ( strequal( new_dom->name, list[i].domain_name ) ) {
4260 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4271 list = talloc_array( NULL, struct winbindd_tdc_domain, 1 );
4274 list = talloc_realloc( *domains, *domains,
4275 struct winbindd_tdc_domain,
4280 ZERO_STRUCT( list[idx] );
4286 list[idx].domain_name = talloc_strdup(list, new_dom->name);
4287 if (list[idx].domain_name == NULL) {
4290 if (new_dom->alt_name != NULL) {
4291 list[idx].dns_name = talloc_strdup(list, new_dom->alt_name);
4292 if (list[idx].dns_name == NULL) {
4297 if ( !is_null_sid( &new_dom->sid ) ) {
4298 sid_copy( &list[idx].sid, &new_dom->sid );
4300 sid_copy(&list[idx].sid, &global_sid_NULL);
4303 if ( new_dom->domain_flags != 0x0 )
4304 list[idx].trust_flags = new_dom->domain_flags;
4306 if ( new_dom->domain_type != 0x0 )
4307 list[idx].trust_type = new_dom->domain_type;
4309 if ( new_dom->domain_trust_attribs != 0x0 )
4310 list[idx].trust_attribs = new_dom->domain_trust_attribs;
4314 *num_domains = idx + 1;
4320 /*********************************************************************
4321 ********************************************************************/
4323 static TDB_DATA make_tdc_key( const char *domain_name )
4325 char *keystr = NULL;
4326 TDB_DATA key = { NULL, 0 };
4328 if ( !domain_name ) {
4329 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4333 if (asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name ) == -1) {
4336 key = string_term_tdb_data(keystr);
4341 /*********************************************************************
4342 ********************************************************************/
4344 static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
4346 unsigned char **buf )
4348 unsigned char *buffer = NULL;
4353 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4361 /* Store the number of array items first */
4362 len += tdb_pack( buffer+len, buflen-len, "d",
4365 /* now pack each domain trust record */
4366 for ( i=0; i<num_domains; i++ ) {
4371 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4372 domains[i].domain_name,
4373 domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
4376 len += tdb_pack( buffer+len, buflen-len, "fffddd",
4377 domains[i].domain_name,
4378 domains[i].dns_name ? domains[i].dns_name : "",
4379 sid_to_fstring(tmp, &domains[i].sid),
4380 domains[i].trust_flags,
4381 domains[i].trust_attribs,
4382 domains[i].trust_type );
4385 if ( buflen < len ) {
4387 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
4388 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4402 /*********************************************************************
4403 ********************************************************************/
4405 static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
4406 struct winbindd_tdc_domain **domains )
4408 fstring domain_name, dns_name, sid_string;
4409 uint32_t type, attribs, flags;
4413 struct winbindd_tdc_domain *list = NULL;
4415 /* get the number of domains */
4416 len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
4418 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4422 list = talloc_array( NULL, struct winbindd_tdc_domain, num_domains );
4424 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4428 for ( i=0; i<num_domains; i++ ) {
4431 this_len = tdb_unpack( buf+len, buflen-len, "fffddd",
4439 if ( this_len == -1 ) {
4440 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4441 TALLOC_FREE( list );
4446 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4447 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4448 domain_name, dns_name, sid_string,
4449 flags, attribs, type));
4451 list[i].domain_name = talloc_strdup( list, domain_name );
4452 list[i].dns_name = NULL;
4453 if (dns_name[0] != '\0') {
4454 list[i].dns_name = talloc_strdup(list, dns_name);
4456 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
4457 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4460 list[i].trust_flags = flags;
4461 list[i].trust_attribs = attribs;
4462 list[i].trust_type = type;
4470 /*********************************************************************
4471 ********************************************************************/
4473 static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
4475 TDB_DATA key = make_tdc_key( lp_workgroup() );
4476 TDB_DATA data = { NULL, 0 };
4482 /* See if we were asked to delete the cache entry */
4485 ret = tdb_delete( wcache->tdb, key );
4489 data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
4496 ret = tdb_store( wcache->tdb, key, data, 0 );
4499 SAFE_FREE( data.dptr );
4500 SAFE_FREE( key.dptr );
4502 return ( ret == 0 );
4505 /*********************************************************************
4506 ********************************************************************/
4508 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
4510 TDB_DATA key = make_tdc_key( lp_workgroup() );
4511 TDB_DATA data = { NULL, 0 };
4519 data = tdb_fetch( wcache->tdb, key );
4521 SAFE_FREE( key.dptr );
4526 *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
4528 SAFE_FREE( data.dptr );
4536 /*********************************************************************
4537 ********************************************************************/
4539 bool wcache_tdc_add_domain( struct winbindd_domain *domain )
4541 struct winbindd_tdc_domain *dom_list = NULL;
4542 size_t num_domains = 0;
4545 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4546 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4547 domain->name, domain->alt_name,
4548 sid_string_dbg(&domain->sid),
4549 domain->domain_flags,
4550 domain->domain_trust_attribs,
4551 domain->domain_type));
4553 if ( !init_wcache() ) {
4557 /* fetch the list */
4559 wcache_tdc_fetch_list( &dom_list, &num_domains );
4561 /* add the new domain */
4563 if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
4567 /* pack the domain */
4569 if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
4577 TALLOC_FREE( dom_list );
4582 static struct winbindd_tdc_domain *wcache_tdc_dup_domain(
4583 TALLOC_CTX *mem_ctx, const struct winbindd_tdc_domain *src)
4585 struct winbindd_tdc_domain *dst;
4587 dst = talloc(mem_ctx, struct winbindd_tdc_domain);
4591 dst->domain_name = talloc_strdup(dst, src->domain_name);
4592 if (dst->domain_name == NULL) {
4596 dst->dns_name = NULL;
4597 if (src->dns_name != NULL) {
4598 dst->dns_name = talloc_strdup(dst, src->dns_name);
4599 if (dst->dns_name == NULL) {
4604 sid_copy(&dst->sid, &src->sid);
4605 dst->trust_flags = src->trust_flags;
4606 dst->trust_type = src->trust_type;
4607 dst->trust_attribs = src->trust_attribs;
4614 /*********************************************************************
4615 ********************************************************************/
4617 struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
4619 struct winbindd_tdc_domain *dom_list = NULL;
4620 size_t num_domains = 0;
4622 struct winbindd_tdc_domain *d = NULL;
4624 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
4626 if ( !init_wcache() ) {
4630 /* fetch the list */
4632 wcache_tdc_fetch_list( &dom_list, &num_domains );
4634 for ( i=0; i<num_domains; i++ ) {
4635 if ( strequal(name, dom_list[i].domain_name) ||
4636 strequal(name, dom_list[i].dns_name) )
4638 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4641 d = wcache_tdc_dup_domain(ctx, &dom_list[i]);
4646 TALLOC_FREE( dom_list );
4651 /*********************************************************************
4652 ********************************************************************/
4654 struct winbindd_tdc_domain*
4655 wcache_tdc_fetch_domainbysid(TALLOC_CTX *ctx,
4656 const struct dom_sid *sid)
4658 struct winbindd_tdc_domain *dom_list = NULL;
4659 size_t num_domains = 0;
4661 struct winbindd_tdc_domain *d = NULL;
4663 DEBUG(10,("wcache_tdc_fetch_domainbysid: Searching for domain %s\n",
4664 sid_string_dbg(sid)));
4666 if (!init_wcache()) {
4670 /* fetch the list */
4672 wcache_tdc_fetch_list(&dom_list, &num_domains);
4674 for (i = 0; i<num_domains; i++) {
4675 if (dom_sid_equal(sid, &(dom_list[i].sid))) {
4676 DEBUG(10, ("wcache_tdc_fetch_domainbysid: "
4677 "Found domain %s for SID %s\n",
4678 dom_list[i].domain_name,
4679 sid_string_dbg(sid)));
4681 d = wcache_tdc_dup_domain(ctx, &dom_list[i]);
4686 TALLOC_FREE(dom_list);
4692 /*********************************************************************
4693 ********************************************************************/
4695 void wcache_tdc_clear( void )
4697 if ( !init_wcache() )
4700 wcache_tdc_store_list( NULL, 0 );
4706 /*********************************************************************
4707 ********************************************************************/
4709 static void wcache_save_user_pwinfo(struct winbindd_domain *domain,
4711 const struct dom_sid *user_sid,
4712 const char *homedir,
4717 struct cache_entry *centry;
4720 if ( (centry = centry_start(domain, status)) == NULL )
4723 centry_put_string( centry, homedir );
4724 centry_put_string( centry, shell );
4725 centry_put_string( centry, gecos );
4726 centry_put_uint32( centry, gid );
4728 centry_end(centry, "NSS/PWINFO/%s", sid_to_fstring(tmp, user_sid) );
4730 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid) ));
4732 centry_free(centry);
4737 NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
4738 const struct dom_sid *user_sid,
4740 const char **homedir, const char **shell,
4741 const char **gecos, gid_t *p_gid)
4743 struct winbind_cache *cache = get_cache(domain);
4744 struct cache_entry *centry = NULL;
4751 centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s",
4752 sid_to_fstring(tmp, user_sid));
4757 *homedir = centry_string( centry, ctx );
4758 *shell = centry_string( centry, ctx );
4759 *gecos = centry_string( centry, ctx );
4760 *p_gid = centry_uint32( centry );
4762 centry_free(centry);
4764 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4765 sid_string_dbg(user_sid)));
4767 return NT_STATUS_OK;
4771 nt_status = nss_get_info( domain->name, user_sid, ctx,
4772 homedir, shell, gecos, p_gid );
4774 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status)));
4776 if ( NT_STATUS_IS_OK(nt_status) ) {
4777 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir));
4778 DEBUGADD(10, ("\tshell = '%s'\n", *shell));
4779 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos));
4780 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid));
4782 wcache_save_user_pwinfo( domain, nt_status, user_sid,
4783 *homedir, *shell, *gecos, *p_gid );
4786 if ( NT_STATUS_EQUAL( nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
4787 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4789 set_domain_offline( domain );
4797 static bool wcache_ndr_key(TALLOC_CTX *mem_ctx, const char *domain_name,
4798 uint32_t opnum, const DATA_BLOB *req,
4804 key = talloc_asprintf(mem_ctx, "NDR/%s/%d/", domain_name, (int)opnum);
4808 keylen = talloc_get_size(key) - 1;
4810 key = talloc_realloc(mem_ctx, key, char, keylen + req->length);
4814 memcpy(key + keylen, req->data, req->length);
4816 pkey->dptr = (uint8_t *)key;
4817 pkey->dsize = talloc_get_size(key);
4821 static bool wcache_opnum_cacheable(uint32_t opnum)
4824 case NDR_WBINT_PING:
4825 case NDR_WBINT_QUERYSEQUENCENUMBER:
4826 case NDR_WBINT_ALLOCATEUID:
4827 case NDR_WBINT_ALLOCATEGID:
4828 case NDR_WBINT_CHECKMACHINEACCOUNT:
4829 case NDR_WBINT_CHANGEMACHINEACCOUNT:
4830 case NDR_WBINT_PINGDC:
4836 bool wcache_fetch_ndr(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
4837 uint32_t opnum, const DATA_BLOB *req, DATA_BLOB *resp)
4842 if (!wcache_opnum_cacheable(opnum) ||
4843 is_my_own_sam_domain(domain) ||
4844 is_builtin_domain(domain)) {
4848 if (wcache->tdb == NULL) {
4852 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4855 data = tdb_fetch(wcache->tdb, key);
4856 TALLOC_FREE(key.dptr);
4858 if (data.dptr == NULL) {
4861 if (data.dsize < 12) {
4865 if (!is_domain_offline(domain)) {
4866 uint32_t entry_seqnum, dom_seqnum, last_check;
4867 uint64_t entry_timeout;
4869 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum,
4873 entry_seqnum = IVAL(data.dptr, 0);
4874 if (entry_seqnum != dom_seqnum) {
4875 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4876 (int)entry_seqnum));
4879 entry_timeout = BVAL(data.dptr, 4);
4880 if (time(NULL) > entry_timeout) {
4881 DEBUG(10, ("Entry has timed out\n"));
4886 resp->data = (uint8_t *)talloc_memdup(mem_ctx, data.dptr + 12,
4888 if (resp->data == NULL) {
4889 DEBUG(10, ("talloc failed\n"));
4892 resp->length = data.dsize - 12;
4896 SAFE_FREE(data.dptr);
4900 void wcache_store_ndr(struct winbindd_domain *domain, uint32_t opnum,
4901 const DATA_BLOB *req, const DATA_BLOB *resp)
4904 uint32_t dom_seqnum, last_check;
4907 if (!wcache_opnum_cacheable(opnum) ||
4908 is_my_own_sam_domain(domain) ||
4909 is_builtin_domain(domain)) {
4913 if (wcache->tdb == NULL) {
4917 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum, &last_check)) {
4918 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4923 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4927 timeout = time(NULL) + lp_winbind_cache_time();
4929 data.dsize = resp->length + 12;
4930 data.dptr = talloc_array(key.dptr, uint8_t, data.dsize);
4931 if (data.dptr == NULL) {
4935 SIVAL(data.dptr, 0, dom_seqnum);
4936 SBVAL(data.dptr, 4, timeout);
4937 memcpy(data.dptr + 12, resp->data, resp->length);
4939 tdb_store(wcache->tdb, key, data, 0);
4942 TALLOC_FREE(key.dptr);