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/>.
28 #include "tdb_validate.h"
29 #include "../libcli/auth/libcli_auth.h"
30 #include "../librpc/gen_ndr/ndr_wbint.h"
34 #define DBGC_CLASS DBGC_WINBIND
36 #define WINBINDD_CACHE_VERSION 1
37 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
39 extern struct winbindd_methods reconnect_methods;
41 extern struct winbindd_methods ads_methods;
43 extern struct winbindd_methods builtin_passdb_methods;
44 extern struct winbindd_methods sam_passdb_methods;
47 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
48 * Here are the list of entry types that are *not* stored
49 * as form struct cache_entry in the cache.
52 static const char *non_centry_keys[] = {
57 WINBINDD_CACHE_VERSION_KEYSTR,
61 /************************************************************************
62 Is this key a non-centry type ?
63 ************************************************************************/
65 static bool is_non_centry_key(TDB_DATA kbuf)
69 if (kbuf.dptr == NULL || kbuf.dsize == 0) {
72 for (i = 0; non_centry_keys[i] != NULL; i++) {
73 size_t namelen = strlen(non_centry_keys[i]);
74 if (kbuf.dsize < namelen) {
77 if (strncmp(non_centry_keys[i], (const char *)kbuf.dptr, namelen) == 0) {
84 /* Global online/offline state - False when online. winbindd starts up online
85 and sets this to true if the first query fails and there's an entry in
86 the cache tdb telling us to stay offline. */
88 static bool global_winbindd_offline_state;
90 struct winbind_cache {
96 uint32 sequence_number;
101 void (*smb_panic_fn)(const char *const why) = smb_panic;
103 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
105 static struct winbind_cache *wcache;
107 void winbindd_check_cache_size(time_t t)
109 static time_t last_check_time;
112 if (last_check_time == (time_t)0)
115 if (t - last_check_time < 60 && t - last_check_time > 0)
118 if (wcache == NULL || wcache->tdb == NULL) {
119 DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
123 if (fstat(tdb_fd(wcache->tdb), &st) == -1) {
124 DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno) ));
128 if (st.st_size > WINBINDD_MAX_CACHE_SIZE) {
129 DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
130 (unsigned long)st.st_size,
131 (unsigned long)WINBINDD_MAX_CACHE_SIZE));
132 wcache_flush_cache();
136 /* get the winbind_cache structure */
137 static struct winbind_cache *get_cache(struct winbindd_domain *domain)
139 struct winbind_cache *ret = wcache;
141 /* We have to know what type of domain we are dealing with first. */
143 if (domain->internal) {
144 domain->backend = &builtin_passdb_methods;
145 domain->initialized = True;
148 if (strequal(domain->name, get_global_sam_name()) &&
149 sid_equal(&domain->sid, get_global_sam_sid())) {
150 domain->backend = &sam_passdb_methods;
151 domain->initialized = True;
154 if ( !domain->initialized ) {
155 init_dc_connection( domain );
159 OK. listen up becasue I'm only going to say this once.
160 We have the following scenarios to consider
161 (a) trusted AD domains on a Samba DC,
162 (b) trusted AD domains and we are joined to a non-kerberos domain
163 (c) trusted AD domains and we are joined to a kerberos (AD) domain
165 For (a) we can always contact the trusted domain using krb5
166 since we have the domain trust account password
168 For (b) we can only use RPC since we have no way of
169 getting a krb5 ticket in our own domain
171 For (c) we can always use krb5 since we have a kerberos trust
176 if (!domain->backend) {
178 struct winbindd_domain *our_domain = domain;
180 /* find our domain first so we can figure out if we
181 are joined to a kerberized domain */
183 if ( !domain->primary )
184 our_domain = find_our_domain();
186 if ((our_domain->active_directory || IS_DC)
187 && domain->active_directory
188 && !lp_winbind_rpc_only()) {
189 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain->name));
190 domain->backend = &ads_methods;
192 #endif /* HAVE_ADS */
193 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain->name));
194 domain->backend = &reconnect_methods;
197 #endif /* HAVE_ADS */
203 ret = SMB_XMALLOC_P(struct winbind_cache);
207 wcache_flush_cache();
213 free a centry structure
215 static void centry_free(struct cache_entry *centry)
219 SAFE_FREE(centry->data);
223 static bool centry_check_bytes(struct cache_entry *centry, size_t nbytes)
225 if (centry->len - centry->ofs < nbytes) {
226 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
227 (unsigned int)nbytes,
228 centry->len - centry->ofs));
235 pull a uint32 from a cache entry
237 static uint32 centry_uint32(struct cache_entry *centry)
241 if (!centry_check_bytes(centry, 4)) {
242 smb_panic_fn("centry_uint32");
244 ret = IVAL(centry->data, centry->ofs);
250 pull a uint16 from a cache entry
252 static uint16 centry_uint16(struct cache_entry *centry)
255 if (!centry_check_bytes(centry, 2)) {
256 smb_panic_fn("centry_uint16");
258 ret = CVAL(centry->data, centry->ofs);
264 pull a uint8 from a cache entry
266 static uint8 centry_uint8(struct cache_entry *centry)
269 if (!centry_check_bytes(centry, 1)) {
270 smb_panic_fn("centry_uint8");
272 ret = CVAL(centry->data, centry->ofs);
278 pull a NTTIME from a cache entry
280 static NTTIME centry_nttime(struct cache_entry *centry)
283 if (!centry_check_bytes(centry, 8)) {
284 smb_panic_fn("centry_nttime");
286 ret = IVAL(centry->data, centry->ofs);
288 ret += (uint64_t)IVAL(centry->data, centry->ofs) << 32;
294 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
296 static time_t centry_time(struct cache_entry *centry)
298 return (time_t)centry_nttime(centry);
301 /* pull a string from a cache entry, using the supplied
304 static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
309 len = centry_uint8(centry);
312 /* a deliberate NULL string */
316 if (!centry_check_bytes(centry, (size_t)len)) {
317 smb_panic_fn("centry_string");
320 ret = TALLOC_ARRAY(mem_ctx, char, len+1);
322 smb_panic_fn("centry_string out of memory\n");
324 memcpy(ret,centry->data + centry->ofs, len);
330 /* pull a hash16 from a cache entry, using the supplied
333 static char *centry_hash16(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
338 len = centry_uint8(centry);
341 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
346 if (!centry_check_bytes(centry, 16)) {
350 ret = TALLOC_ARRAY(mem_ctx, char, 16);
352 smb_panic_fn("centry_hash out of memory\n");
354 memcpy(ret,centry->data + centry->ofs, 16);
359 /* pull a sid from a cache entry, using the supplied
362 static bool centry_sid(struct cache_entry *centry, struct dom_sid *sid)
367 sid_string = centry_string(centry, talloc_tos());
368 if (sid_string == NULL) {
371 ret = string_to_sid(sid, sid_string);
372 TALLOC_FREE(sid_string);
378 pull a NTSTATUS from a cache entry
380 static NTSTATUS centry_ntstatus(struct cache_entry *centry)
384 status = NT_STATUS(centry_uint32(centry));
389 /* the server is considered down if it can't give us a sequence number */
390 static bool wcache_server_down(struct winbindd_domain *domain)
397 ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
400 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
405 static bool wcache_fetch_seqnum(const char *domain_name, uint32_t *seqnum,
406 uint32_t *last_seq_check)
411 if (wcache->tdb == NULL) {
412 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
416 key = talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name);
418 DEBUG(10, ("talloc failed\n"));
422 data = tdb_fetch_bystring(wcache->tdb, key);
425 if (data.dptr == NULL) {
426 DEBUG(10, ("wcache_fetch_seqnum: %s not found\n",
430 if (data.dsize != 8) {
431 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
433 SAFE_FREE(data.dptr);
437 *seqnum = IVAL(data.dptr, 0);
438 *last_seq_check = IVAL(data.dptr, 4);
439 SAFE_FREE(data.dptr);
444 static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
446 uint32 last_check, time_diff;
448 if (!wcache_fetch_seqnum(domain->name, &domain->sequence_number,
450 return NT_STATUS_UNSUCCESSFUL;
452 domain->last_seq_check = last_check;
454 /* have we expired? */
456 time_diff = now - domain->last_seq_check;
457 if ( time_diff > lp_winbind_cache_time() ) {
458 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
459 domain->name, domain->sequence_number,
460 (uint32)domain->last_seq_check));
461 return NT_STATUS_UNSUCCESSFUL;
464 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
465 domain->name, domain->sequence_number,
466 (uint32)domain->last_seq_check));
471 bool wcache_store_seqnum(const char *domain_name, uint32_t seqnum,
472 time_t last_seq_check)
478 if (wcache->tdb == NULL) {
479 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
483 key_str = talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name);
484 if (key_str == NULL) {
485 DEBUG(10, ("talloc_asprintf failed\n"));
489 SIVAL(buf, 0, seqnum);
490 SIVAL(buf, 4, last_seq_check);
492 ret = tdb_store_bystring(wcache->tdb, key_str,
493 make_tdb_data(buf, sizeof(buf)), TDB_REPLACE);
494 TALLOC_FREE(key_str);
496 DEBUG(10, ("tdb_store_bystring failed: %s\n",
497 tdb_errorstr(wcache->tdb)));
498 TALLOC_FREE(key_str);
502 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
503 domain_name, seqnum, (unsigned)last_seq_check));
508 static bool store_cache_seqnum( struct winbindd_domain *domain )
510 return wcache_store_seqnum(domain->name, domain->sequence_number,
511 domain->last_seq_check);
515 refresh the domain sequence number. If force is true
516 then always refresh it, no matter how recently we fetched it
519 static void refresh_sequence_number(struct winbindd_domain *domain, bool force)
523 time_t t = time(NULL);
524 unsigned cache_time = lp_winbind_cache_time();
526 if (is_domain_offline(domain)) {
532 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
533 /* trying to reconnect is expensive, don't do it too often */
534 if (domain->sequence_number == DOM_SEQUENCE_NONE) {
539 time_diff = t - domain->last_seq_check;
541 /* see if we have to refetch the domain sequence number */
542 if (!force && (time_diff < cache_time) &&
543 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
544 NT_STATUS_IS_OK(domain->last_status)) {
545 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
549 /* try to get the sequence number from the tdb cache first */
550 /* this will update the timestamp as well */
552 status = fetch_cache_seqnum( domain, t );
553 if (NT_STATUS_IS_OK(status) &&
554 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
555 NT_STATUS_IS_OK(domain->last_status)) {
559 /* important! make sure that we know if this is a native
560 mode domain or not. And that we can contact it. */
562 if ( winbindd_can_contact_domain( domain ) ) {
563 status = domain->backend->sequence_number(domain,
564 &domain->sequence_number);
566 /* just use the current time */
567 status = NT_STATUS_OK;
568 domain->sequence_number = time(NULL);
572 /* the above call could have set our domain->backend to NULL when
573 * coming from offline to online mode, make sure to reinitialize the
574 * backend - Guenther */
577 if (!NT_STATUS_IS_OK(status)) {
578 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status)));
579 domain->sequence_number = DOM_SEQUENCE_NONE;
582 domain->last_status = status;
583 domain->last_seq_check = time(NULL);
585 /* save the new sequence number in the cache */
586 store_cache_seqnum( domain );
589 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
590 domain->name, domain->sequence_number));
596 decide if a cache entry has expired
598 static bool centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
600 /* If we've been told to be offline - stay in that state... */
601 if (lp_winbind_offline_logon() && global_winbindd_offline_state) {
602 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
603 keystr, domain->name ));
607 /* when the domain is offline return the cached entry.
608 * This deals with transient offline states... */
610 if (!domain->online) {
611 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
612 keystr, domain->name ));
616 /* if the server is OK and our cache entry came from when it was down then
617 the entry is invalid */
618 if ((domain->sequence_number != DOM_SEQUENCE_NONE) &&
619 (centry->sequence_number == DOM_SEQUENCE_NONE)) {
620 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
621 keystr, domain->name ));
625 /* if the server is down or the cache entry is not older than the
626 current sequence number then it is OK */
627 if (wcache_server_down(domain) ||
628 centry->sequence_number == domain->sequence_number) {
629 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
630 keystr, domain->name ));
634 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
635 keystr, domain->name ));
641 static struct cache_entry *wcache_fetch_raw(char *kstr)
644 struct cache_entry *centry;
647 key = string_tdb_data(kstr);
648 data = tdb_fetch(wcache->tdb, key);
654 centry = SMB_XMALLOC_P(struct cache_entry);
655 centry->data = (unsigned char *)data.dptr;
656 centry->len = data.dsize;
659 if (centry->len < 8) {
660 /* huh? corrupt cache? */
661 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr));
666 centry->status = centry_ntstatus(centry);
667 centry->sequence_number = centry_uint32(centry);
673 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
674 number and return status
676 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
677 struct winbindd_domain *domain,
678 const char *format, ...) PRINTF_ATTRIBUTE(3,4);
679 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
680 struct winbindd_domain *domain,
681 const char *format, ...)
685 struct cache_entry *centry;
687 if (!winbindd_use_cache()) {
691 refresh_sequence_number(domain, false);
693 va_start(ap, format);
694 smb_xvasprintf(&kstr, format, ap);
697 centry = wcache_fetch_raw(kstr);
698 if (centry == NULL) {
703 if (centry_expired(domain, kstr, centry)) {
705 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
706 kstr, domain->name ));
713 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
714 kstr, domain->name ));
720 static void wcache_delete(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
721 static void wcache_delete(const char *format, ...)
727 va_start(ap, format);
728 smb_xvasprintf(&kstr, format, ap);
731 key = string_tdb_data(kstr);
733 tdb_delete(wcache->tdb, key);
738 make sure we have at least len bytes available in a centry
740 static void centry_expand(struct cache_entry *centry, uint32 len)
742 if (centry->len - centry->ofs >= len)
745 centry->data = SMB_REALLOC_ARRAY(centry->data, unsigned char,
748 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
749 smb_panic_fn("out of memory in centry_expand");
754 push a uint32 into a centry
756 static void centry_put_uint32(struct cache_entry *centry, uint32 v)
758 centry_expand(centry, 4);
759 SIVAL(centry->data, centry->ofs, v);
764 push a uint16 into a centry
766 static void centry_put_uint16(struct cache_entry *centry, uint16 v)
768 centry_expand(centry, 2);
769 SIVAL(centry->data, centry->ofs, v);
774 push a uint8 into a centry
776 static void centry_put_uint8(struct cache_entry *centry, uint8 v)
778 centry_expand(centry, 1);
779 SCVAL(centry->data, centry->ofs, v);
784 push a string into a centry
786 static void centry_put_string(struct cache_entry *centry, const char *s)
791 /* null strings are marked as len 0xFFFF */
792 centry_put_uint8(centry, 0xFF);
797 /* can't handle more than 254 char strings. Truncating is probably best */
799 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len));
802 centry_put_uint8(centry, len);
803 centry_expand(centry, len);
804 memcpy(centry->data + centry->ofs, s, len);
809 push a 16 byte hash into a centry - treat as 16 byte string.
811 static void centry_put_hash16(struct cache_entry *centry, const uint8 val[16])
813 centry_put_uint8(centry, 16);
814 centry_expand(centry, 16);
815 memcpy(centry->data + centry->ofs, val, 16);
819 static void centry_put_sid(struct cache_entry *centry, const struct dom_sid *sid)
822 centry_put_string(centry, sid_to_fstring(sid_string, sid));
827 put NTSTATUS into a centry
829 static void centry_put_ntstatus(struct cache_entry *centry, NTSTATUS status)
831 uint32 status_value = NT_STATUS_V(status);
832 centry_put_uint32(centry, status_value);
837 push a NTTIME into a centry
839 static void centry_put_nttime(struct cache_entry *centry, NTTIME nt)
841 centry_expand(centry, 8);
842 SIVAL(centry->data, centry->ofs, nt & 0xFFFFFFFF);
844 SIVAL(centry->data, centry->ofs, nt >> 32);
849 push a time_t into a centry - use a 64 bit size.
850 NTTIME here is being used as a convenient 64-bit size.
852 static void centry_put_time(struct cache_entry *centry, time_t t)
854 NTTIME nt = (NTTIME)t;
855 centry_put_nttime(centry, nt);
859 start a centry for output. When finished, call centry_end()
861 struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status)
863 struct cache_entry *centry;
868 centry = SMB_XMALLOC_P(struct cache_entry);
870 centry->len = 8192; /* reasonable default */
871 centry->data = SMB_XMALLOC_ARRAY(uint8, centry->len);
873 centry->sequence_number = domain->sequence_number;
874 centry_put_ntstatus(centry, status);
875 centry_put_uint32(centry, centry->sequence_number);
880 finish a centry and write it to the tdb
882 static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
883 static void centry_end(struct cache_entry *centry, const char *format, ...)
889 if (!winbindd_use_cache()) {
893 va_start(ap, format);
894 smb_xvasprintf(&kstr, format, ap);
897 key = string_tdb_data(kstr);
898 data.dptr = centry->data;
899 data.dsize = centry->ofs;
901 tdb_store(wcache->tdb, key, data, TDB_REPLACE);
905 static void wcache_save_name_to_sid(struct winbindd_domain *domain,
906 NTSTATUS status, const char *domain_name,
907 const char *name, const struct dom_sid *sid,
908 enum lsa_SidType type)
910 struct cache_entry *centry;
913 centry = centry_start(domain, status);
916 centry_put_uint32(centry, type);
917 centry_put_sid(centry, sid);
918 fstrcpy(uname, name);
920 centry_end(centry, "NS/%s/%s", domain_name, uname);
921 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name,
922 uname, sid_string_dbg(sid), nt_errstr(status)));
926 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
927 const struct dom_sid *sid, const char *domain_name, const char *name, enum lsa_SidType type)
929 struct cache_entry *centry;
932 centry = centry_start(domain, status);
936 if (NT_STATUS_IS_OK(status)) {
937 centry_put_uint32(centry, type);
938 centry_put_string(centry, domain_name);
939 centry_put_string(centry, name);
942 centry_end(centry, "SN/%s", sid_to_fstring(sid_string, sid));
943 DEBUG(10,("wcache_save_sid_to_name: %s -> %s (%s)\n", sid_string,
944 name, nt_errstr(status)));
949 static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status,
950 struct wbint_userinfo *info)
952 struct cache_entry *centry;
955 if (is_null_sid(&info->user_sid)) {
959 centry = centry_start(domain, status);
962 centry_put_string(centry, info->acct_name);
963 centry_put_string(centry, info->full_name);
964 centry_put_string(centry, info->homedir);
965 centry_put_string(centry, info->shell);
966 centry_put_uint32(centry, info->primary_gid);
967 centry_put_sid(centry, &info->user_sid);
968 centry_put_sid(centry, &info->group_sid);
969 centry_end(centry, "U/%s", sid_to_fstring(sid_string,
971 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
975 static void wcache_save_lockout_policy(struct winbindd_domain *domain,
977 struct samr_DomInfo12 *lockout_policy)
979 struct cache_entry *centry;
981 centry = centry_start(domain, status);
985 centry_put_nttime(centry, lockout_policy->lockout_duration);
986 centry_put_nttime(centry, lockout_policy->lockout_window);
987 centry_put_uint16(centry, lockout_policy->lockout_threshold);
989 centry_end(centry, "LOC_POL/%s", domain->name);
991 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
998 static void wcache_save_password_policy(struct winbindd_domain *domain,
1000 struct samr_DomInfo1 *policy)
1002 struct cache_entry *centry;
1004 centry = centry_start(domain, status);
1008 centry_put_uint16(centry, policy->min_password_length);
1009 centry_put_uint16(centry, policy->password_history_length);
1010 centry_put_uint32(centry, policy->password_properties);
1011 centry_put_nttime(centry, policy->max_password_age);
1012 centry_put_nttime(centry, policy->min_password_age);
1014 centry_end(centry, "PWD_POL/%s", domain->name);
1016 DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
1018 centry_free(centry);
1021 /***************************************************************************
1022 ***************************************************************************/
1024 static void wcache_save_username_alias(struct winbindd_domain *domain,
1026 const char *name, const char *alias)
1028 struct cache_entry *centry;
1031 if ( (centry = centry_start(domain, status)) == NULL )
1034 centry_put_string( centry, alias );
1036 fstrcpy(uname, name);
1038 centry_end(centry, "NSS/NA/%s", uname);
1040 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name, alias ));
1042 centry_free(centry);
1045 static void wcache_save_alias_username(struct winbindd_domain *domain,
1047 const char *alias, const char *name)
1049 struct cache_entry *centry;
1052 if ( (centry = centry_start(domain, status)) == NULL )
1055 centry_put_string( centry, name );
1057 fstrcpy(uname, alias);
1059 centry_end(centry, "NSS/AN/%s", uname);
1061 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias, name ));
1063 centry_free(centry);
1066 /***************************************************************************
1067 ***************************************************************************/
1069 NTSTATUS resolve_username_to_alias( TALLOC_CTX *mem_ctx,
1070 struct winbindd_domain *domain,
1071 const char *name, char **alias )
1073 struct winbind_cache *cache = get_cache(domain);
1074 struct cache_entry *centry = NULL;
1078 if ( domain->internal )
1079 return NT_STATUS_NOT_SUPPORTED;
1084 if ( (upper_name = SMB_STRDUP(name)) == NULL )
1085 return NT_STATUS_NO_MEMORY;
1086 strupper_m(upper_name);
1088 centry = wcache_fetch(cache, domain, "NSS/NA/%s", upper_name);
1090 SAFE_FREE( upper_name );
1095 status = centry->status;
1097 if (!NT_STATUS_IS_OK(status)) {
1098 centry_free(centry);
1102 *alias = centry_string( centry, mem_ctx );
1104 centry_free(centry);
1106 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1107 name, *alias ? *alias : "(none)"));
1109 return (*alias) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1113 /* If its not in cache and we are offline, then fail */
1115 if ( get_global_winbindd_state_offline() || !domain->online ) {
1116 DEBUG(8,("resolve_username_to_alias: rejecting query "
1117 "in offline mode\n"));
1118 return NT_STATUS_NOT_FOUND;
1121 status = nss_map_to_alias( mem_ctx, domain->name, name, alias );
1123 if ( NT_STATUS_IS_OK( status ) ) {
1124 wcache_save_username_alias(domain, status, name, *alias);
1127 if ( NT_STATUS_EQUAL( status, NT_STATUS_NONE_MAPPED ) ) {
1128 wcache_save_username_alias(domain, status, name, "(NULL)");
1131 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1132 nt_errstr(status)));
1134 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1135 set_domain_offline( domain );
1141 /***************************************************************************
1142 ***************************************************************************/
1144 NTSTATUS resolve_alias_to_username( TALLOC_CTX *mem_ctx,
1145 struct winbindd_domain *domain,
1146 const char *alias, char **name )
1148 struct winbind_cache *cache = get_cache(domain);
1149 struct cache_entry *centry = NULL;
1153 if ( domain->internal )
1154 return NT_STATUS_NOT_SUPPORTED;
1159 if ( (upper_name = SMB_STRDUP(alias)) == NULL )
1160 return NT_STATUS_NO_MEMORY;
1161 strupper_m(upper_name);
1163 centry = wcache_fetch(cache, domain, "NSS/AN/%s", upper_name);
1165 SAFE_FREE( upper_name );
1170 status = centry->status;
1172 if (!NT_STATUS_IS_OK(status)) {
1173 centry_free(centry);
1177 *name = centry_string( centry, mem_ctx );
1179 centry_free(centry);
1181 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1182 alias, *name ? *name : "(none)"));
1184 return (*name) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1188 /* If its not in cache and we are offline, then fail */
1190 if ( get_global_winbindd_state_offline() || !domain->online ) {
1191 DEBUG(8,("resolve_alias_to_username: rejecting query "
1192 "in offline mode\n"));
1193 return NT_STATUS_NOT_FOUND;
1196 /* an alias cannot contain a domain prefix or '@' */
1198 if (strchr(alias, '\\') || strchr(alias, '@')) {
1199 DEBUG(10,("resolve_alias_to_username: skipping fully "
1200 "qualified name %s\n", alias));
1201 return NT_STATUS_OBJECT_NAME_INVALID;
1204 status = nss_map_from_alias( mem_ctx, domain->name, alias, name );
1206 if ( NT_STATUS_IS_OK( status ) ) {
1207 wcache_save_alias_username( domain, status, alias, *name );
1210 if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1211 wcache_save_alias_username(domain, status, alias, "(NULL)");
1214 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1215 nt_errstr(status)));
1217 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1218 set_domain_offline( domain );
1224 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const struct dom_sid *sid)
1226 struct winbind_cache *cache = get_cache(domain);
1228 fstring key_str, tmp;
1232 return NT_STATUS_INTERNAL_DB_ERROR;
1235 if (is_null_sid(sid)) {
1236 return NT_STATUS_INVALID_SID;
1239 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1240 return NT_STATUS_INVALID_SID;
1243 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
1245 data = tdb_fetch(cache->tdb, string_tdb_data(key_str));
1247 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1250 SAFE_FREE(data.dptr);
1251 return NT_STATUS_OK;
1254 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1255 as new salted ones. */
1257 NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
1258 TALLOC_CTX *mem_ctx,
1259 const struct dom_sid *sid,
1260 const uint8 **cached_nt_pass,
1261 const uint8 **cached_salt)
1263 struct winbind_cache *cache = get_cache(domain);
1264 struct cache_entry *centry = NULL;
1271 return NT_STATUS_INTERNAL_DB_ERROR;
1274 if (is_null_sid(sid)) {
1275 return NT_STATUS_INVALID_SID;
1278 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1279 return NT_STATUS_INVALID_SID;
1282 /* Try and get a salted cred first. If we can't
1283 fall back to an unsalted cred. */
1285 centry = wcache_fetch(cache, domain, "CRED/%s",
1286 sid_to_fstring(tmp, sid));
1288 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1289 sid_string_dbg(sid)));
1290 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1293 t = centry_time(centry);
1295 /* In the salted case this isn't actually the nt_hash itself,
1296 but the MD5 of the salt + nt_hash. Let the caller
1297 sort this out. It can tell as we only return the cached_salt
1298 if we are returning a salted cred. */
1300 *cached_nt_pass = (const uint8 *)centry_hash16(centry, mem_ctx);
1301 if (*cached_nt_pass == NULL) {
1304 sid_to_fstring(sidstr, sid);
1306 /* Bad (old) cred cache. Delete and pretend we
1308 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1310 wcache_delete("CRED/%s", sidstr);
1311 centry_free(centry);
1312 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1315 /* We only have 17 bytes more data in the salted cred case. */
1316 if (centry->len - centry->ofs == 17) {
1317 *cached_salt = (const uint8 *)centry_hash16(centry, mem_ctx);
1319 *cached_salt = NULL;
1322 dump_data_pw("cached_nt_pass", *cached_nt_pass, NT_HASH_LEN);
1324 dump_data_pw("cached_salt", *cached_salt, NT_HASH_LEN);
1327 status = centry->status;
1329 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1330 sid_string_dbg(sid), nt_errstr(status) ));
1332 centry_free(centry);
1336 /* Store creds for a SID - only writes out new salted ones. */
1338 NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
1339 TALLOC_CTX *mem_ctx,
1340 const struct dom_sid *sid,
1341 const uint8 nt_pass[NT_HASH_LEN])
1343 struct cache_entry *centry;
1346 uint8 cred_salt[NT_HASH_LEN];
1347 uint8 salted_hash[NT_HASH_LEN];
1349 if (is_null_sid(sid)) {
1350 return NT_STATUS_INVALID_SID;
1353 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1354 return NT_STATUS_INVALID_SID;
1357 centry = centry_start(domain, NT_STATUS_OK);
1359 return NT_STATUS_INTERNAL_DB_ERROR;
1362 dump_data_pw("nt_pass", nt_pass, NT_HASH_LEN);
1364 centry_put_time(centry, time(NULL));
1366 /* Create a salt and then salt the hash. */
1367 generate_random_buffer(cred_salt, NT_HASH_LEN);
1368 E_md5hash(cred_salt, nt_pass, salted_hash);
1370 centry_put_hash16(centry, salted_hash);
1371 centry_put_hash16(centry, cred_salt);
1372 centry_end(centry, "CRED/%s", sid_to_fstring(sid_string, sid));
1374 DEBUG(10,("wcache_save_creds: %s\n", sid_string));
1376 centry_free(centry);
1378 return NT_STATUS_OK;
1382 /* Query display info. This is the basic user list fn */
1383 static NTSTATUS query_user_list(struct winbindd_domain *domain,
1384 TALLOC_CTX *mem_ctx,
1385 uint32 *num_entries,
1386 struct wbint_userinfo **info)
1388 struct winbind_cache *cache = get_cache(domain);
1389 struct cache_entry *centry = NULL;
1391 unsigned int i, retry;
1392 bool old_status = domain->online;
1397 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1402 *num_entries = centry_uint32(centry);
1404 if (*num_entries == 0)
1407 (*info) = TALLOC_ARRAY(mem_ctx, struct wbint_userinfo, *num_entries);
1409 smb_panic_fn("query_user_list out of memory");
1411 for (i=0; i<(*num_entries); i++) {
1412 (*info)[i].acct_name = centry_string(centry, mem_ctx);
1413 (*info)[i].full_name = centry_string(centry, mem_ctx);
1414 (*info)[i].homedir = centry_string(centry, mem_ctx);
1415 (*info)[i].shell = centry_string(centry, mem_ctx);
1416 centry_sid(centry, &(*info)[i].user_sid);
1417 centry_sid(centry, &(*info)[i].group_sid);
1421 status = centry->status;
1423 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1424 domain->name, nt_errstr(status) ));
1426 centry_free(centry);
1433 /* Return status value returned by seq number check */
1435 if (!NT_STATUS_IS_OK(domain->last_status))
1436 return domain->last_status;
1438 /* Put the query_user_list() in a retry loop. There appears to be
1439 * some bug either with Windows 2000 or Samba's handling of large
1440 * rpc replies. This manifests itself as sudden disconnection
1441 * at a random point in the enumeration of a large (60k) user list.
1442 * The retry loop simply tries the operation again. )-: It's not
1443 * pretty but an acceptable workaround until we work out what the
1444 * real problem is. */
1449 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1452 status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
1453 if (!NT_STATUS_IS_OK(status)) {
1454 DEBUG(3, ("query_user_list: returned 0x%08x, "
1455 "retrying\n", NT_STATUS_V(status)));
1457 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1458 DEBUG(3, ("query_user_list: flushing "
1459 "connection cache\n"));
1460 invalidate_cm_connection(&domain->conn);
1462 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1463 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1464 if (!domain->internal && old_status) {
1465 set_domain_offline(domain);
1467 /* store partial response. */
1468 if (*num_entries > 0) {
1470 * humm, what about the status used for cache?
1471 * Should it be NT_STATUS_OK?
1476 * domain is offline now, and there is no user entries,
1477 * try to fetch from cache again.
1479 if (cache->tdb && !domain->online && !domain->internal && old_status) {
1480 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1481 /* partial response... */
1485 goto do_fetch_cache;
1492 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
1496 refresh_sequence_number(domain, false);
1497 if (!NT_STATUS_IS_OK(status)) {
1500 centry = centry_start(domain, status);
1503 centry_put_uint32(centry, *num_entries);
1504 for (i=0; i<(*num_entries); i++) {
1505 centry_put_string(centry, (*info)[i].acct_name);
1506 centry_put_string(centry, (*info)[i].full_name);
1507 centry_put_string(centry, (*info)[i].homedir);
1508 centry_put_string(centry, (*info)[i].shell);
1509 centry_put_sid(centry, &(*info)[i].user_sid);
1510 centry_put_sid(centry, &(*info)[i].group_sid);
1511 if (domain->backend && domain->backend->consistent) {
1512 /* when the backend is consistent we can pre-prime some mappings */
1513 wcache_save_name_to_sid(domain, NT_STATUS_OK,
1515 (*info)[i].acct_name,
1516 &(*info)[i].user_sid,
1518 wcache_save_sid_to_name(domain, NT_STATUS_OK,
1519 &(*info)[i].user_sid,
1521 (*info)[i].acct_name,
1523 wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
1526 centry_end(centry, "UL/%s", domain->name);
1527 centry_free(centry);
1533 /* list all domain groups */
1534 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
1535 TALLOC_CTX *mem_ctx,
1536 uint32 *num_entries,
1537 struct acct_info **info)
1539 struct winbind_cache *cache = get_cache(domain);
1540 struct cache_entry *centry = NULL;
1545 old_status = domain->online;
1549 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1554 *num_entries = centry_uint32(centry);
1556 if (*num_entries == 0)
1559 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1561 smb_panic_fn("enum_dom_groups out of memory");
1563 for (i=0; i<(*num_entries); i++) {
1564 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1565 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1566 (*info)[i].rid = centry_uint32(centry);
1570 status = centry->status;
1572 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1573 domain->name, nt_errstr(status) ));
1575 centry_free(centry);
1582 /* Return status value returned by seq number check */
1584 if (!NT_STATUS_IS_OK(domain->last_status))
1585 return domain->last_status;
1587 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1590 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1592 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1593 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1594 if (!domain->internal && old_status) {
1595 set_domain_offline(domain);
1599 !domain->internal &&
1601 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1603 goto do_fetch_cache;
1608 refresh_sequence_number(domain, false);
1609 if (!NT_STATUS_IS_OK(status)) {
1612 centry = centry_start(domain, status);
1615 centry_put_uint32(centry, *num_entries);
1616 for (i=0; i<(*num_entries); i++) {
1617 centry_put_string(centry, (*info)[i].acct_name);
1618 centry_put_string(centry, (*info)[i].acct_desc);
1619 centry_put_uint32(centry, (*info)[i].rid);
1621 centry_end(centry, "GL/%s/domain", domain->name);
1622 centry_free(centry);
1628 /* list all domain groups */
1629 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
1630 TALLOC_CTX *mem_ctx,
1631 uint32 *num_entries,
1632 struct acct_info **info)
1634 struct winbind_cache *cache = get_cache(domain);
1635 struct cache_entry *centry = NULL;
1640 old_status = domain->online;
1644 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1649 *num_entries = centry_uint32(centry);
1651 if (*num_entries == 0)
1654 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1656 smb_panic_fn("enum_dom_groups out of memory");
1658 for (i=0; i<(*num_entries); i++) {
1659 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1660 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1661 (*info)[i].rid = centry_uint32(centry);
1666 /* If we are returning cached data and the domain controller
1667 is down then we don't know whether the data is up to date
1668 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1671 if (wcache_server_down(domain)) {
1672 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1673 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1675 status = centry->status;
1677 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1678 domain->name, nt_errstr(status) ));
1680 centry_free(centry);
1687 /* Return status value returned by seq number check */
1689 if (!NT_STATUS_IS_OK(domain->last_status))
1690 return domain->last_status;
1692 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1695 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1697 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1698 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1699 if (!domain->internal && old_status) {
1700 set_domain_offline(domain);
1703 !domain->internal &&
1706 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1708 goto do_fetch_cache;
1713 refresh_sequence_number(domain, false);
1714 if (!NT_STATUS_IS_OK(status)) {
1717 centry = centry_start(domain, status);
1720 centry_put_uint32(centry, *num_entries);
1721 for (i=0; i<(*num_entries); i++) {
1722 centry_put_string(centry, (*info)[i].acct_name);
1723 centry_put_string(centry, (*info)[i].acct_desc);
1724 centry_put_uint32(centry, (*info)[i].rid);
1726 centry_end(centry, "GL/%s/local", domain->name);
1727 centry_free(centry);
1733 NTSTATUS wcache_name_to_sid(struct winbindd_domain *domain,
1734 const char *domain_name,
1736 struct dom_sid *sid,
1737 enum lsa_SidType *type)
1739 struct winbind_cache *cache = get_cache(domain);
1740 struct cache_entry *centry;
1744 if (cache->tdb == NULL) {
1745 return NT_STATUS_NOT_FOUND;
1748 uname = talloc_strdup_upper(talloc_tos(), name);
1749 if (uname == NULL) {
1750 return NT_STATUS_NO_MEMORY;
1753 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1755 if (centry == NULL) {
1756 return NT_STATUS_NOT_FOUND;
1759 status = centry->status;
1760 if (NT_STATUS_IS_OK(status)) {
1761 *type = (enum lsa_SidType)centry_uint32(centry);
1762 centry_sid(centry, sid);
1765 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1766 "%s\n", domain->name, nt_errstr(status) ));
1768 centry_free(centry);
1772 /* convert a single name to a sid in a domain */
1773 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
1774 TALLOC_CTX *mem_ctx,
1775 const char *domain_name,
1778 struct dom_sid *sid,
1779 enum lsa_SidType *type)
1784 old_status = domain->online;
1786 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1787 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1793 /* If the seq number check indicated that there is a problem
1794 * with this DC, then return that status... except for
1795 * access_denied. This is special because the dc may be in
1796 * "restrict anonymous = 1" mode, in which case it will deny
1797 * most unauthenticated operations, but *will* allow the LSA
1798 * name-to-sid that we try as a fallback. */
1800 if (!(NT_STATUS_IS_OK(domain->last_status)
1801 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1802 return domain->last_status;
1804 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1807 status = domain->backend->name_to_sid(domain, mem_ctx, domain_name,
1808 name, flags, sid, type);
1810 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1811 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1812 if (!domain->internal && old_status) {
1813 set_domain_offline(domain);
1815 if (!domain->internal &&
1818 NTSTATUS cache_status;
1819 cache_status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1820 return cache_status;
1824 refresh_sequence_number(domain, false);
1826 if (domain->online &&
1827 (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
1828 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1830 /* Only save the reverse mapping if this was not a UPN */
1831 if (!strchr(name, '@')) {
1832 strupper_m(CONST_DISCARD(char *,domain_name));
1833 strlower_m(CONST_DISCARD(char *,name));
1834 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1841 NTSTATUS wcache_sid_to_name(struct winbindd_domain *domain,
1842 const struct dom_sid *sid,
1843 TALLOC_CTX *mem_ctx,
1846 enum lsa_SidType *type)
1848 struct winbind_cache *cache = get_cache(domain);
1849 struct cache_entry *centry;
1853 if (cache->tdb == NULL) {
1854 return NT_STATUS_NOT_FOUND;
1857 sid_string = sid_string_tos(sid);
1858 if (sid_string == NULL) {
1859 return NT_STATUS_NO_MEMORY;
1862 centry = wcache_fetch(cache, domain, "SN/%s", sid_string);
1863 TALLOC_FREE(sid_string);
1864 if (centry == NULL) {
1865 return NT_STATUS_NOT_FOUND;
1868 if (NT_STATUS_IS_OK(centry->status)) {
1869 *type = (enum lsa_SidType)centry_uint32(centry);
1870 *domain_name = centry_string(centry, mem_ctx);
1871 *name = centry_string(centry, mem_ctx);
1874 status = centry->status;
1875 centry_free(centry);
1877 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1878 "%s\n", domain->name, nt_errstr(status) ));
1883 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1885 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
1886 TALLOC_CTX *mem_ctx,
1887 const struct dom_sid *sid,
1890 enum lsa_SidType *type)
1895 old_status = domain->online;
1896 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
1898 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1903 *domain_name = NULL;
1905 /* If the seq number check indicated that there is a problem
1906 * with this DC, then return that status... except for
1907 * access_denied. This is special because the dc may be in
1908 * "restrict anonymous = 1" mode, in which case it will deny
1909 * most unauthenticated operations, but *will* allow the LSA
1910 * sid-to-name that we try as a fallback. */
1912 if (!(NT_STATUS_IS_OK(domain->last_status)
1913 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1914 return domain->last_status;
1916 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1919 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1921 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1922 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1923 if (!domain->internal && old_status) {
1924 set_domain_offline(domain);
1926 if (!domain->internal &&
1929 NTSTATUS cache_status;
1930 cache_status = wcache_sid_to_name(domain, sid, mem_ctx,
1931 domain_name, name, type);
1932 return cache_status;
1936 refresh_sequence_number(domain, false);
1937 if (!NT_STATUS_IS_OK(status)) {
1940 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1942 /* We can't save the name to sid mapping here, as with sid history a
1943 * later name2sid would give the wrong sid. */
1948 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
1949 TALLOC_CTX *mem_ctx,
1950 const struct dom_sid *domain_sid,
1955 enum lsa_SidType **types)
1957 struct winbind_cache *cache = get_cache(domain);
1959 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1964 old_status = domain->online;
1965 *domain_name = NULL;
1973 if (num_rids == 0) {
1974 return NT_STATUS_OK;
1977 *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
1978 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
1980 if ((*names == NULL) || (*types == NULL)) {
1981 result = NT_STATUS_NO_MEMORY;
1985 have_mapped = have_unmapped = false;
1987 for (i=0; i<num_rids; i++) {
1989 struct cache_entry *centry;
1992 if (!sid_compose(&sid, domain_sid, rids[i])) {
1993 result = NT_STATUS_INTERNAL_ERROR;
1997 centry = wcache_fetch(cache, domain, "SN/%s",
1998 sid_to_fstring(tmp, &sid));
2003 (*types)[i] = SID_NAME_UNKNOWN;
2004 (*names)[i] = talloc_strdup(*names, "");
2006 if (NT_STATUS_IS_OK(centry->status)) {
2009 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
2011 dom = centry_string(centry, mem_ctx);
2012 if (*domain_name == NULL) {
2018 (*names)[i] = centry_string(centry, *names);
2020 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
2021 have_unmapped = true;
2024 /* something's definitely wrong */
2025 result = centry->status;
2029 centry_free(centry);
2033 return NT_STATUS_NONE_MAPPED;
2035 if (!have_unmapped) {
2036 return NT_STATUS_OK;
2038 return STATUS_SOME_UNMAPPED;
2042 TALLOC_FREE(*names);
2043 TALLOC_FREE(*types);
2045 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
2046 rids, num_rids, domain_name,
2049 if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
2050 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2051 if (!domain->internal && old_status) {
2052 set_domain_offline(domain);
2055 !domain->internal &&
2058 have_mapped = have_unmapped = false;
2060 for (i=0; i<num_rids; i++) {
2062 struct cache_entry *centry;
2065 if (!sid_compose(&sid, domain_sid, rids[i])) {
2066 result = NT_STATUS_INTERNAL_ERROR;
2070 centry = wcache_fetch(cache, domain, "SN/%s",
2071 sid_to_fstring(tmp, &sid));
2073 (*types)[i] = SID_NAME_UNKNOWN;
2074 (*names)[i] = talloc_strdup(*names, "");
2078 (*types)[i] = SID_NAME_UNKNOWN;
2079 (*names)[i] = talloc_strdup(*names, "");
2081 if (NT_STATUS_IS_OK(centry->status)) {
2084 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
2086 dom = centry_string(centry, mem_ctx);
2087 if (*domain_name == NULL) {
2093 (*names)[i] = centry_string(centry, *names);
2095 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
2096 have_unmapped = true;
2099 /* something's definitely wrong */
2100 result = centry->status;
2104 centry_free(centry);
2108 return NT_STATUS_NONE_MAPPED;
2110 if (!have_unmapped) {
2111 return NT_STATUS_OK;
2113 return STATUS_SOME_UNMAPPED;
2117 None of the queried rids has been found so save all negative entries
2119 if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
2120 for (i = 0; i < num_rids; i++) {
2122 const char *name = "";
2123 const enum lsa_SidType type = SID_NAME_UNKNOWN;
2124 NTSTATUS status = NT_STATUS_NONE_MAPPED;
2126 if (!sid_compose(&sid, domain_sid, rids[i])) {
2127 return NT_STATUS_INTERNAL_ERROR;
2130 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2138 Some or all of the queried rids have been found.
2140 if (!NT_STATUS_IS_OK(result) &&
2141 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
2145 refresh_sequence_number(domain, false);
2147 for (i=0; i<num_rids; i++) {
2151 if (!sid_compose(&sid, domain_sid, rids[i])) {
2152 result = NT_STATUS_INTERNAL_ERROR;
2156 status = (*types)[i] == SID_NAME_UNKNOWN ?
2157 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
2159 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2160 (*names)[i], (*types)[i]);
2166 TALLOC_FREE(*names);
2167 TALLOC_FREE(*types);
2171 NTSTATUS wcache_query_user(struct winbindd_domain *domain,
2172 TALLOC_CTX *mem_ctx,
2173 const struct dom_sid *user_sid,
2174 struct wbint_userinfo *info)
2176 struct winbind_cache *cache = get_cache(domain);
2177 struct cache_entry *centry = NULL;
2181 if (cache->tdb == NULL) {
2182 return NT_STATUS_NOT_FOUND;
2185 sid_string = sid_string_tos(user_sid);
2186 if (sid_string == NULL) {
2187 return NT_STATUS_NO_MEMORY;
2190 centry = wcache_fetch(cache, domain, "U/%s", sid_string);
2191 TALLOC_FREE(sid_string);
2192 if (centry == NULL) {
2193 return NT_STATUS_NOT_FOUND;
2197 * If we have an access denied cache entry and a cached info3
2198 * in the samlogon cache then do a query. This will force the
2199 * rpc back end to return the info3 data.
2202 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED) &&
2203 netsamlogon_cache_have(user_sid)) {
2204 DEBUG(10, ("query_user: cached access denied and have cached "
2206 domain->last_status = NT_STATUS_OK;
2207 centry_free(centry);
2208 return NT_STATUS_NOT_FOUND;
2211 /* if status is not ok then this is a negative hit
2212 and the rest of the data doesn't matter */
2213 status = centry->status;
2214 if (NT_STATUS_IS_OK(status)) {
2215 info->acct_name = centry_string(centry, mem_ctx);
2216 info->full_name = centry_string(centry, mem_ctx);
2217 info->homedir = centry_string(centry, mem_ctx);
2218 info->shell = centry_string(centry, mem_ctx);
2219 info->primary_gid = centry_uint32(centry);
2220 centry_sid(centry, &info->user_sid);
2221 centry_sid(centry, &info->group_sid);
2224 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2225 "%s\n", domain->name, nt_errstr(status) ));
2227 centry_free(centry);
2231 /* Lookup user information from a rid */
2232 static NTSTATUS query_user(struct winbindd_domain *domain,
2233 TALLOC_CTX *mem_ctx,
2234 const struct dom_sid *user_sid,
2235 struct wbint_userinfo *info)
2240 old_status = domain->online;
2241 status = wcache_query_user(domain, mem_ctx, user_sid, info);
2242 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2248 /* Return status value returned by seq number check */
2250 if (!NT_STATUS_IS_OK(domain->last_status))
2251 return domain->last_status;
2253 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2256 status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
2258 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2259 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2260 if (!domain->internal && old_status) {
2261 set_domain_offline(domain);
2263 if (!domain->internal &&
2266 NTSTATUS cache_status;
2267 cache_status = wcache_query_user(domain, mem_ctx, user_sid, info);
2268 return cache_status;
2272 refresh_sequence_number(domain, false);
2273 if (!NT_STATUS_IS_OK(status)) {
2276 wcache_save_user(domain, status, info);
2281 NTSTATUS wcache_lookup_usergroups(struct winbindd_domain *domain,
2282 TALLOC_CTX *mem_ctx,
2283 const struct dom_sid *user_sid,
2284 uint32_t *pnum_sids,
2285 struct dom_sid **psids)
2287 struct winbind_cache *cache = get_cache(domain);
2288 struct cache_entry *centry = NULL;
2290 uint32_t i, num_sids;
2291 struct dom_sid *sids;
2294 if (cache->tdb == NULL) {
2295 return NT_STATUS_NOT_FOUND;
2298 centry = wcache_fetch(cache, domain, "UG/%s",
2299 sid_to_fstring(sid_string, user_sid));
2300 if (centry == NULL) {
2301 return NT_STATUS_NOT_FOUND;
2304 /* If we have an access denied cache entry and a cached info3 in the
2305 samlogon cache then do a query. This will force the rpc back end
2306 to return the info3 data. */
2308 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)
2309 && netsamlogon_cache_have(user_sid)) {
2310 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2312 domain->last_status = NT_STATUS_OK;
2313 centry_free(centry);
2314 return NT_STATUS_NOT_FOUND;
2317 num_sids = centry_uint32(centry);
2318 sids = talloc_array(mem_ctx, struct dom_sid, num_sids);
2320 centry_free(centry);
2321 return NT_STATUS_NO_MEMORY;
2324 for (i=0; i<num_sids; i++) {
2325 centry_sid(centry, &sids[i]);
2328 status = centry->status;
2330 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2331 "status: %s\n", domain->name, nt_errstr(status)));
2333 centry_free(centry);
2335 *pnum_sids = num_sids;
2340 /* Lookup groups a user is a member of. */
2341 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
2342 TALLOC_CTX *mem_ctx,
2343 const struct dom_sid *user_sid,
2344 uint32 *num_groups, struct dom_sid **user_gids)
2346 struct cache_entry *centry = NULL;
2352 old_status = domain->online;
2353 status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2354 num_groups, user_gids);
2355 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2360 (*user_gids) = NULL;
2362 /* Return status value returned by seq number check */
2364 if (!NT_STATUS_IS_OK(domain->last_status))
2365 return domain->last_status;
2367 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2370 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
2372 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2373 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2374 if (!domain->internal && old_status) {
2375 set_domain_offline(domain);
2377 if (!domain->internal &&
2380 NTSTATUS cache_status;
2381 cache_status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2382 num_groups, user_gids);
2383 return cache_status;
2386 if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
2390 refresh_sequence_number(domain, false);
2391 if (!NT_STATUS_IS_OK(status)) {
2394 centry = centry_start(domain, status);
2398 centry_put_uint32(centry, *num_groups);
2399 for (i=0; i<(*num_groups); i++) {
2400 centry_put_sid(centry, &(*user_gids)[i]);
2403 centry_end(centry, "UG/%s", sid_to_fstring(sid_string, user_sid));
2404 centry_free(centry);
2410 static char *wcache_make_sidlist(TALLOC_CTX *mem_ctx, uint32_t num_sids,
2411 const struct dom_sid *sids)
2416 sidlist = talloc_strdup(mem_ctx, "");
2417 if (sidlist == NULL) {
2420 for (i=0; i<num_sids; i++) {
2422 sidlist = talloc_asprintf_append_buffer(
2423 sidlist, "/%s", sid_to_fstring(tmp, &sids[i]));
2424 if (sidlist == NULL) {
2431 NTSTATUS wcache_lookup_useraliases(struct winbindd_domain *domain,
2432 TALLOC_CTX *mem_ctx, uint32_t num_sids,
2433 const struct dom_sid *sids,
2434 uint32_t *pnum_aliases, uint32_t **paliases)
2436 struct winbind_cache *cache = get_cache(domain);
2437 struct cache_entry *centry = NULL;
2438 uint32_t num_aliases;
2444 if (cache->tdb == NULL) {
2445 return NT_STATUS_NOT_FOUND;
2448 if (num_sids == 0) {
2451 return NT_STATUS_OK;
2454 /* We need to cache indexed by the whole list of SIDs, the aliases
2455 * resulting might come from any of the SIDs. */
2457 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2458 if (sidlist == NULL) {
2459 return NT_STATUS_NO_MEMORY;
2462 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
2463 TALLOC_FREE(sidlist);
2464 if (centry == NULL) {
2465 return NT_STATUS_NOT_FOUND;
2468 num_aliases = centry_uint32(centry);
2469 aliases = talloc_array(mem_ctx, uint32_t, num_aliases);
2470 if (aliases == NULL) {
2471 centry_free(centry);
2472 return NT_STATUS_NO_MEMORY;
2475 for (i=0; i<num_aliases; i++) {
2476 aliases[i] = centry_uint32(centry);
2479 status = centry->status;
2481 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2482 "status %s\n", domain->name, nt_errstr(status)));
2484 centry_free(centry);
2486 *pnum_aliases = num_aliases;
2487 *paliases = aliases;
2492 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
2493 TALLOC_CTX *mem_ctx,
2494 uint32 num_sids, const struct dom_sid *sids,
2495 uint32 *num_aliases, uint32 **alias_rids)
2497 struct cache_entry *centry = NULL;
2503 old_status = domain->online;
2504 status = wcache_lookup_useraliases(domain, mem_ctx, num_sids, sids,
2505 num_aliases, alias_rids);
2506 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2511 (*alias_rids) = NULL;
2513 if (!NT_STATUS_IS_OK(domain->last_status))
2514 return domain->last_status;
2516 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2517 "for domain %s\n", domain->name ));
2519 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2520 if (sidlist == NULL) {
2521 return NT_STATUS_NO_MEMORY;
2524 status = domain->backend->lookup_useraliases(domain, mem_ctx,
2526 num_aliases, alias_rids);
2528 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2529 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2530 if (!domain->internal && old_status) {
2531 set_domain_offline(domain);
2533 if (!domain->internal &&
2536 NTSTATUS cache_status;
2537 cache_status = wcache_lookup_useraliases(domain, mem_ctx, num_sids,
2538 sids, num_aliases, alias_rids);
2539 return cache_status;
2543 refresh_sequence_number(domain, false);
2544 if (!NT_STATUS_IS_OK(status)) {
2547 centry = centry_start(domain, status);
2550 centry_put_uint32(centry, *num_aliases);
2551 for (i=0; i<(*num_aliases); i++)
2552 centry_put_uint32(centry, (*alias_rids)[i]);
2553 centry_end(centry, "UA%s", sidlist);
2554 centry_free(centry);
2560 NTSTATUS wcache_lookup_groupmem(struct winbindd_domain *domain,
2561 TALLOC_CTX *mem_ctx,
2562 const struct dom_sid *group_sid,
2563 uint32_t *num_names,
2564 struct dom_sid **sid_mem, char ***names,
2565 uint32_t **name_types)
2567 struct winbind_cache *cache = get_cache(domain);
2568 struct cache_entry *centry = NULL;
2573 if (cache->tdb == NULL) {
2574 return NT_STATUS_NOT_FOUND;
2577 sid_string = sid_string_tos(group_sid);
2578 if (sid_string == NULL) {
2579 return NT_STATUS_NO_MEMORY;
2582 centry = wcache_fetch(cache, domain, "GM/%s", sid_string);
2583 TALLOC_FREE(sid_string);
2584 if (centry == NULL) {
2585 return NT_STATUS_NOT_FOUND;
2592 *num_names = centry_uint32(centry);
2593 if (*num_names == 0) {
2594 centry_free(centry);
2595 return NT_STATUS_OK;
2598 *sid_mem = talloc_array(mem_ctx, struct dom_sid, *num_names);
2599 *names = talloc_array(mem_ctx, char *, *num_names);
2600 *name_types = talloc_array(mem_ctx, uint32, *num_names);
2602 if ((*sid_mem == NULL) || (*names == NULL) || (*name_types == NULL)) {
2603 TALLOC_FREE(*sid_mem);
2604 TALLOC_FREE(*names);
2605 TALLOC_FREE(*name_types);
2606 centry_free(centry);
2607 return NT_STATUS_NO_MEMORY;
2610 for (i=0; i<(*num_names); i++) {
2611 centry_sid(centry, &(*sid_mem)[i]);
2612 (*names)[i] = centry_string(centry, mem_ctx);
2613 (*name_types)[i] = centry_uint32(centry);
2616 status = centry->status;
2618 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2619 "status: %s\n", domain->name, nt_errstr(status)));
2621 centry_free(centry);
2625 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
2626 TALLOC_CTX *mem_ctx,
2627 const struct dom_sid *group_sid,
2628 enum lsa_SidType type,
2630 struct dom_sid **sid_mem, char ***names,
2631 uint32 **name_types)
2633 struct cache_entry *centry = NULL;
2639 old_status = domain->online;
2640 status = wcache_lookup_groupmem(domain, mem_ctx, group_sid, num_names,
2641 sid_mem, names, name_types);
2642 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2649 (*name_types) = NULL;
2651 /* Return status value returned by seq number check */
2653 if (!NT_STATUS_IS_OK(domain->last_status))
2654 return domain->last_status;
2656 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2659 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid,
2661 sid_mem, names, name_types);
2663 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2664 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2665 if (!domain->internal && old_status) {
2666 set_domain_offline(domain);
2668 if (!domain->internal &&
2671 NTSTATUS cache_status;
2672 cache_status = wcache_lookup_groupmem(domain, mem_ctx, group_sid,
2673 num_names, sid_mem, names,
2675 return cache_status;
2679 refresh_sequence_number(domain, false);
2680 if (!NT_STATUS_IS_OK(status)) {
2683 centry = centry_start(domain, status);
2686 centry_put_uint32(centry, *num_names);
2687 for (i=0; i<(*num_names); i++) {
2688 centry_put_sid(centry, &(*sid_mem)[i]);
2689 centry_put_string(centry, (*names)[i]);
2690 centry_put_uint32(centry, (*name_types)[i]);
2692 centry_end(centry, "GM/%s", sid_to_fstring(sid_string, group_sid));
2693 centry_free(centry);
2699 /* find the sequence number for a domain */
2700 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
2702 refresh_sequence_number(domain, false);
2704 *seq = domain->sequence_number;
2706 return NT_STATUS_OK;
2709 /* enumerate trusted domains
2710 * (we need to have the list of trustdoms in the cache when we go offline) -
2712 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
2713 TALLOC_CTX *mem_ctx,
2714 struct netr_DomainTrustList *trusts)
2717 struct winbind_cache *cache;
2718 struct winbindd_tdc_domain *dom_list = NULL;
2719 size_t num_domains = 0;
2720 bool retval = false;
2724 old_status = domain->online;
2726 trusts->array = NULL;
2728 cache = get_cache(domain);
2729 if (!cache || !cache->tdb) {
2733 if (domain->online) {
2737 retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2738 if (!retval || !num_domains || !dom_list) {
2739 TALLOC_FREE(dom_list);
2744 trusts->array = TALLOC_ZERO_ARRAY(mem_ctx, struct netr_DomainTrust, num_domains);
2745 if (!trusts->array) {
2746 TALLOC_FREE(dom_list);
2747 return NT_STATUS_NO_MEMORY;
2750 for (i = 0; i < num_domains; i++) {
2751 struct netr_DomainTrust *trust;
2752 struct dom_sid *sid;
2753 struct winbindd_domain *dom;
2755 dom = find_domain_from_name_noinit(dom_list[i].domain_name);
2756 if (dom && dom->internal) {
2760 trust = &trusts->array[trusts->count];
2761 trust->netbios_name = talloc_strdup(trusts->array, dom_list[i].domain_name);
2762 trust->dns_name = talloc_strdup(trusts->array, dom_list[i].dns_name);
2763 sid = talloc(trusts->array, struct dom_sid);
2764 if (!trust->netbios_name || !trust->dns_name ||
2766 TALLOC_FREE(dom_list);
2767 TALLOC_FREE(trusts->array);
2768 return NT_STATUS_NO_MEMORY;
2771 trust->trust_flags = dom_list[i].trust_flags;
2772 trust->trust_attributes = dom_list[i].trust_attribs;
2773 trust->trust_type = dom_list[i].trust_type;
2774 sid_copy(sid, &dom_list[i].sid);
2779 TALLOC_FREE(dom_list);
2780 return NT_STATUS_OK;
2783 /* Return status value returned by seq number check */
2785 if (!NT_STATUS_IS_OK(domain->last_status))
2786 return domain->last_status;
2788 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2791 status = domain->backend->trusted_domains(domain, mem_ctx, trusts);
2793 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2794 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2795 if (!domain->internal && old_status) {
2796 set_domain_offline(domain);
2798 if (!domain->internal &&
2801 retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2802 if (retval && num_domains && dom_list) {
2803 TALLOC_FREE(trusts->array);
2805 goto do_fetch_cache;
2809 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2810 * so that the generic centry handling still applies correctly -
2813 if (!NT_STATUS_IS_ERR(status)) {
2814 status = NT_STATUS_OK;
2819 /* get lockout policy */
2820 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
2821 TALLOC_CTX *mem_ctx,
2822 struct samr_DomInfo12 *policy)
2824 struct winbind_cache *cache = get_cache(domain);
2825 struct cache_entry *centry = NULL;
2829 old_status = domain->online;
2833 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2839 policy->lockout_duration = centry_nttime(centry);
2840 policy->lockout_window = centry_nttime(centry);
2841 policy->lockout_threshold = centry_uint16(centry);
2843 status = centry->status;
2845 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2846 domain->name, nt_errstr(status) ));
2848 centry_free(centry);
2852 ZERO_STRUCTP(policy);
2854 /* Return status value returned by seq number check */
2856 if (!NT_STATUS_IS_OK(domain->last_status))
2857 return domain->last_status;
2859 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2862 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2864 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2865 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2866 if (!domain->internal && old_status) {
2867 set_domain_offline(domain);
2870 !domain->internal &&
2873 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2875 goto do_fetch_cache;
2880 refresh_sequence_number(domain, false);
2881 if (!NT_STATUS_IS_OK(status)) {
2884 wcache_save_lockout_policy(domain, status, policy);
2889 /* get password policy */
2890 static NTSTATUS password_policy(struct winbindd_domain *domain,
2891 TALLOC_CTX *mem_ctx,
2892 struct samr_DomInfo1 *policy)
2894 struct winbind_cache *cache = get_cache(domain);
2895 struct cache_entry *centry = NULL;
2899 old_status = domain->online;
2903 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2909 policy->min_password_length = centry_uint16(centry);
2910 policy->password_history_length = centry_uint16(centry);
2911 policy->password_properties = centry_uint32(centry);
2912 policy->max_password_age = centry_nttime(centry);
2913 policy->min_password_age = centry_nttime(centry);
2915 status = centry->status;
2917 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2918 domain->name, nt_errstr(status) ));
2920 centry_free(centry);
2924 ZERO_STRUCTP(policy);
2926 /* Return status value returned by seq number check */
2928 if (!NT_STATUS_IS_OK(domain->last_status))
2929 return domain->last_status;
2931 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2934 status = domain->backend->password_policy(domain, mem_ctx, policy);
2936 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2937 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2938 if (!domain->internal && old_status) {
2939 set_domain_offline(domain);
2942 !domain->internal &&
2945 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2947 goto do_fetch_cache;
2952 refresh_sequence_number(domain, false);
2953 if (!NT_STATUS_IS_OK(status)) {
2956 wcache_save_password_policy(domain, status, policy);
2962 /* Invalidate cached user and group lists coherently */
2964 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2967 if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
2968 strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
2969 tdb_delete(the_tdb, kbuf);
2974 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2976 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
2977 struct netr_SamInfo3 *info3)
2980 fstring key_str, sid_string;
2981 struct winbind_cache *cache;
2983 /* dont clear cached U/SID and UG/SID entries when we want to logon
2986 if (lp_winbind_offline_logon()) {
2993 cache = get_cache(domain);
2999 sid_compose(&sid, info3->base.domain_sid, info3->base.rid);
3001 /* Clear U/SID cache entry */
3002 fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, &sid));
3003 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
3004 tdb_delete(cache->tdb, string_tdb_data(key_str));
3006 /* Clear UG/SID cache entry */
3007 fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, &sid));
3008 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
3009 tdb_delete(cache->tdb, string_tdb_data(key_str));
3011 /* Samba/winbindd never needs this. */
3012 netsamlogon_clear_cached_user(info3);
3015 bool wcache_invalidate_cache(void)
3017 struct winbindd_domain *domain;
3019 for (domain = domain_list(); domain; domain = domain->next) {
3020 struct winbind_cache *cache = get_cache(domain);
3022 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3023 "entries for %s\n", domain->name));
3026 tdb_traverse(cache->tdb, traverse_fn, NULL);
3035 bool wcache_invalidate_cache_noinit(void)
3037 struct winbindd_domain *domain;
3039 for (domain = domain_list(); domain; domain = domain->next) {
3040 struct winbind_cache *cache;
3042 /* Skip uninitialized domains. */
3043 if (!domain->initialized && !domain->internal) {
3047 cache = get_cache(domain);
3049 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3050 "entries for %s\n", domain->name));
3053 tdb_traverse(cache->tdb, traverse_fn, NULL);
3055 * Flushing cache has nothing to with domains.
3056 * return here if we successfully flushed once.
3057 * To avoid unnecessary traversing the cache.
3068 bool init_wcache(void)
3070 if (wcache == NULL) {
3071 wcache = SMB_XMALLOC_P(struct winbind_cache);
3072 ZERO_STRUCTP(wcache);
3075 if (wcache->tdb != NULL)
3078 /* when working offline we must not clear the cache on restart */
3079 wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
3080 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3081 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
3082 O_RDWR|O_CREAT, 0600);
3084 if (wcache->tdb == NULL) {
3085 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3092 /************************************************************************
3093 This is called by the parent to initialize the cache file.
3094 We don't need sophisticated locking here as we know we're the
3096 ************************************************************************/
3098 bool initialize_winbindd_cache(void)
3100 bool cache_bad = true;
3103 if (!init_wcache()) {
3104 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3108 /* Check version number. */
3109 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
3110 vers == WINBINDD_CACHE_VERSION) {
3115 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3116 "and re-creating with version number %d\n",
3117 WINBINDD_CACHE_VERSION ));
3119 tdb_close(wcache->tdb);
3122 if (unlink(cache_path("winbindd_cache.tdb")) == -1) {
3123 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3124 cache_path("winbindd_cache.tdb"),
3128 if (!init_wcache()) {
3129 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3130 "init_wcache failed.\n"));
3134 /* Write the version. */
3135 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
3136 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3137 tdb_errorstr(wcache->tdb) ));
3142 tdb_close(wcache->tdb);
3147 void close_winbindd_cache(void)
3153 tdb_close(wcache->tdb);
3158 bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
3159 char **domain_name, char **name,
3160 enum lsa_SidType *type)
3162 struct winbindd_domain *domain;
3165 domain = find_lookup_domain_from_sid(sid);
3166 if (domain == NULL) {
3169 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
3171 return NT_STATUS_IS_OK(status);
3174 bool lookup_cached_name(TALLOC_CTX *mem_ctx,
3175 const char *domain_name,
3177 struct dom_sid *sid,
3178 enum lsa_SidType *type)
3180 struct winbindd_domain *domain;
3182 bool original_online_state;
3184 domain = find_lookup_domain_from_name(domain_name);
3185 if (domain == NULL) {
3189 /* If we are doing a cached logon, temporarily set the domain
3190 offline so the cache won't expire the entry */
3192 original_online_state = domain->online;
3193 domain->online = false;
3194 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
3195 domain->online = original_online_state;
3197 return NT_STATUS_IS_OK(status);
3200 void cache_name2sid(struct winbindd_domain *domain,
3201 const char *domain_name, const char *name,
3202 enum lsa_SidType type, const struct dom_sid *sid)
3204 refresh_sequence_number(domain, false);
3205 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
3210 * The original idea that this cache only contains centries has
3211 * been blurred - now other stuff gets put in here. Ensure we
3212 * ignore these things on cleanup.
3215 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
3216 TDB_DATA dbuf, void *state)
3218 struct cache_entry *centry;
3220 if (is_non_centry_key(kbuf)) {
3224 centry = wcache_fetch_raw((char *)kbuf.dptr);
3229 if (!NT_STATUS_IS_OK(centry->status)) {
3230 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
3231 tdb_delete(the_tdb, kbuf);
3234 centry_free(centry);
3238 /* flush the cache */
3239 void wcache_flush_cache(void)
3244 tdb_close(wcache->tdb);
3247 if (!winbindd_use_cache()) {
3251 /* when working offline we must not clear the cache on restart */
3252 wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
3253 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3254 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
3255 O_RDWR|O_CREAT, 0600);
3258 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3262 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
3264 DEBUG(10,("wcache_flush_cache success\n"));
3267 /* Count cached creds */
3269 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3272 int *cred_count = (int*)state;
3274 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3280 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
3282 struct winbind_cache *cache = get_cache(domain);
3287 return NT_STATUS_INTERNAL_DB_ERROR;
3290 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
3292 return NT_STATUS_OK;
3296 struct cred_list *prev, *next;
3301 static struct cred_list *wcache_cred_list;
3303 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3306 struct cred_list *cred;
3308 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3310 cred = SMB_MALLOC_P(struct cred_list);
3312 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3318 /* save a copy of the key */
3320 fstrcpy(cred->name, (const char *)kbuf.dptr);
3321 DLIST_ADD(wcache_cred_list, cred);
3327 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const struct dom_sid *sid)
3329 struct winbind_cache *cache = get_cache(domain);
3332 struct cred_list *cred, *oldest = NULL;
3335 return NT_STATUS_INTERNAL_DB_ERROR;
3338 /* we possibly already have an entry */
3339 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
3341 fstring key_str, tmp;
3343 DEBUG(11,("we already have an entry, deleting that\n"));
3345 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
3347 tdb_delete(cache->tdb, string_tdb_data(key_str));
3349 return NT_STATUS_OK;
3352 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
3354 return NT_STATUS_OK;
3355 } else if ((ret == -1) || (wcache_cred_list == NULL)) {
3356 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3359 ZERO_STRUCTP(oldest);
3361 for (cred = wcache_cred_list; cred; cred = cred->next) {
3366 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
3368 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3370 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
3374 t = IVAL(data.dptr, 0);
3375 SAFE_FREE(data.dptr);
3378 oldest = SMB_MALLOC_P(struct cred_list);
3379 if (oldest == NULL) {
3380 status = NT_STATUS_NO_MEMORY;
3384 fstrcpy(oldest->name, cred->name);
3385 oldest->created = t;
3389 if (t < oldest->created) {
3390 fstrcpy(oldest->name, cred->name);
3391 oldest->created = t;
3395 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
3396 status = NT_STATUS_OK;
3398 status = NT_STATUS_UNSUCCESSFUL;
3401 SAFE_FREE(wcache_cred_list);
3407 /* Change the global online/offline state. */
3408 bool set_global_winbindd_state_offline(void)
3412 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3414 /* Only go offline if someone has created
3415 the key "WINBINDD_OFFLINE" in the cache tdb. */
3417 if (wcache == NULL || wcache->tdb == NULL) {
3418 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3422 if (!lp_winbind_offline_logon()) {
3423 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3427 if (global_winbindd_offline_state) {
3428 /* Already offline. */
3432 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
3434 if (!data.dptr || data.dsize != 4) {
3435 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3436 SAFE_FREE(data.dptr);
3439 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3440 global_winbindd_offline_state = true;
3441 SAFE_FREE(data.dptr);
3446 void set_global_winbindd_state_online(void)
3448 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3450 if (!lp_winbind_offline_logon()) {
3451 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3455 if (!global_winbindd_offline_state) {
3456 /* Already online. */
3459 global_winbindd_offline_state = false;
3465 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3466 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
3469 bool get_global_winbindd_state_offline(void)
3471 return global_winbindd_offline_state;
3474 /***********************************************************************
3475 Validate functions for all possible cache tdb keys.
3476 ***********************************************************************/
3478 static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
3479 struct tdb_validation_status *state)
3481 struct cache_entry *centry;
3483 centry = SMB_XMALLOC_P(struct cache_entry);
3484 centry->data = (unsigned char *)memdup(data.dptr, data.dsize);
3485 if (!centry->data) {
3489 centry->len = data.dsize;
3492 if (centry->len < 8) {
3493 /* huh? corrupt cache? */
3494 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr));
3495 centry_free(centry);
3496 state->bad_entry = true;
3497 state->success = false;
3501 centry->status = NT_STATUS(centry_uint32(centry));
3502 centry->sequence_number = centry_uint32(centry);
3506 static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3507 struct tdb_validation_status *state)
3509 if (dbuf.dsize != 8) {
3510 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3511 keystr, (unsigned int)dbuf.dsize ));
3512 state->bad_entry = true;
3518 static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3519 struct tdb_validation_status *state)
3521 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3526 (void)centry_uint32(centry);
3527 if (NT_STATUS_IS_OK(centry->status)) {
3529 (void)centry_sid(centry, &sid);
3532 centry_free(centry);
3534 if (!(state->success)) {
3537 DEBUG(10,("validate_ns: %s ok\n", keystr));
3541 static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3542 struct tdb_validation_status *state)
3544 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3549 if (NT_STATUS_IS_OK(centry->status)) {
3550 (void)centry_uint32(centry);
3551 (void)centry_string(centry, mem_ctx);
3552 (void)centry_string(centry, mem_ctx);
3555 centry_free(centry);
3557 if (!(state->success)) {
3560 DEBUG(10,("validate_sn: %s ok\n", keystr));
3564 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3565 struct tdb_validation_status *state)
3567 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3574 (void)centry_string(centry, mem_ctx);
3575 (void)centry_string(centry, mem_ctx);
3576 (void)centry_string(centry, mem_ctx);
3577 (void)centry_string(centry, mem_ctx);
3578 (void)centry_uint32(centry);
3579 (void)centry_sid(centry, &sid);
3580 (void)centry_sid(centry, &sid);
3582 centry_free(centry);
3584 if (!(state->success)) {
3587 DEBUG(10,("validate_u: %s ok\n", keystr));
3591 static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3592 struct tdb_validation_status *state)
3594 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3600 (void)centry_nttime(centry);
3601 (void)centry_nttime(centry);
3602 (void)centry_uint16(centry);
3604 centry_free(centry);
3606 if (!(state->success)) {
3609 DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
3613 static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3614 struct tdb_validation_status *state)
3616 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3622 (void)centry_uint16(centry);
3623 (void)centry_uint16(centry);
3624 (void)centry_uint32(centry);
3625 (void)centry_nttime(centry);
3626 (void)centry_nttime(centry);
3628 centry_free(centry);
3630 if (!(state->success)) {
3633 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
3637 static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3638 struct tdb_validation_status *state)
3640 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3646 (void)centry_time(centry);
3647 (void)centry_hash16(centry, mem_ctx);
3649 /* We only have 17 bytes more data in the salted cred case. */
3650 if (centry->len - centry->ofs == 17) {
3651 (void)centry_hash16(centry, mem_ctx);
3654 centry_free(centry);
3656 if (!(state->success)) {
3659 DEBUG(10,("validate_cred: %s ok\n", keystr));
3663 static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3664 struct tdb_validation_status *state)
3666 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3667 int32 num_entries, i;
3673 num_entries = (int32)centry_uint32(centry);
3675 for (i=0; i< num_entries; i++) {
3677 (void)centry_string(centry, mem_ctx);
3678 (void)centry_string(centry, mem_ctx);
3679 (void)centry_string(centry, mem_ctx);
3680 (void)centry_string(centry, mem_ctx);
3681 (void)centry_sid(centry, &sid);
3682 (void)centry_sid(centry, &sid);
3685 centry_free(centry);
3687 if (!(state->success)) {
3690 DEBUG(10,("validate_ul: %s ok\n", keystr));
3694 static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3695 struct tdb_validation_status *state)
3697 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3698 int32 num_entries, i;
3704 num_entries = centry_uint32(centry);
3706 for (i=0; i< num_entries; i++) {
3707 (void)centry_string(centry, mem_ctx);
3708 (void)centry_string(centry, mem_ctx);
3709 (void)centry_uint32(centry);
3712 centry_free(centry);
3714 if (!(state->success)) {
3717 DEBUG(10,("validate_gl: %s ok\n", keystr));
3721 static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3722 struct tdb_validation_status *state)
3724 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3725 int32 num_groups, i;
3731 num_groups = centry_uint32(centry);
3733 for (i=0; i< num_groups; i++) {
3735 centry_sid(centry, &sid);
3738 centry_free(centry);
3740 if (!(state->success)) {
3743 DEBUG(10,("validate_ug: %s ok\n", keystr));
3747 static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3748 struct tdb_validation_status *state)
3750 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3751 int32 num_aliases, i;
3757 num_aliases = centry_uint32(centry);
3759 for (i=0; i < num_aliases; i++) {
3760 (void)centry_uint32(centry);
3763 centry_free(centry);
3765 if (!(state->success)) {
3768 DEBUG(10,("validate_ua: %s ok\n", keystr));
3772 static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3773 struct tdb_validation_status *state)
3775 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3782 num_names = centry_uint32(centry);
3784 for (i=0; i< num_names; i++) {
3786 centry_sid(centry, &sid);
3787 (void)centry_string(centry, mem_ctx);
3788 (void)centry_uint32(centry);
3791 centry_free(centry);
3793 if (!(state->success)) {
3796 DEBUG(10,("validate_gm: %s ok\n", keystr));
3800 static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3801 struct tdb_validation_status *state)
3803 /* Can't say anything about this other than must be nonzero. */
3804 if (dbuf.dsize == 0) {
3805 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3807 state->bad_entry = true;
3808 state->success = false;
3812 DEBUG(10,("validate_dr: %s ok\n", keystr));
3816 static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3817 struct tdb_validation_status *state)
3819 /* Can't say anything about this other than must be nonzero. */
3820 if (dbuf.dsize == 0) {
3821 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3823 state->bad_entry = true;
3824 state->success = false;
3828 DEBUG(10,("validate_de: %s ok\n", keystr));
3832 static int validate_pwinfo(TALLOC_CTX *mem_ctx, const char *keystr,
3833 TDB_DATA dbuf, struct tdb_validation_status *state)
3835 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3841 (void)centry_string(centry, mem_ctx);
3842 (void)centry_string(centry, mem_ctx);
3843 (void)centry_string(centry, mem_ctx);
3844 (void)centry_uint32(centry);
3846 centry_free(centry);
3848 if (!(state->success)) {
3851 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3855 static int validate_nss_an(TALLOC_CTX *mem_ctx, const char *keystr,
3857 struct tdb_validation_status *state)
3859 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3865 (void)centry_string( centry, mem_ctx );
3867 centry_free(centry);
3869 if (!(state->success)) {
3872 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3876 static int validate_nss_na(TALLOC_CTX *mem_ctx, const char *keystr,
3878 struct tdb_validation_status *state)
3880 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3886 (void)centry_string( centry, mem_ctx );
3888 centry_free(centry);
3890 if (!(state->success)) {
3893 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3897 static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
3899 struct tdb_validation_status *state)
3901 if (dbuf.dsize == 0) {
3902 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3903 "key %s (len ==0) ?\n", keystr));
3904 state->bad_entry = true;
3905 state->success = false;
3909 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
3910 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3914 static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3915 struct tdb_validation_status *state)
3917 if (dbuf.dsize != 4) {
3918 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3919 keystr, (unsigned int)dbuf.dsize ));
3920 state->bad_entry = true;
3921 state->success = false;
3924 DEBUG(10,("validate_offline: %s ok\n", keystr));
3928 static int validate_ndr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3929 struct tdb_validation_status *state)
3932 * Ignore validation for now. The proper way to do this is with a
3933 * checksum. Just pure parsing does not really catch much.
3938 static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3939 struct tdb_validation_status *state)
3941 if (dbuf.dsize != 4) {
3942 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3943 "key %s (len %u != 4) ?\n",
3944 keystr, (unsigned int)dbuf.dsize));
3945 state->bad_entry = true;
3946 state->success = false;
3950 DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
3954 /***********************************************************************
3955 A list of all possible cache tdb keys with associated validation
3957 ***********************************************************************/
3959 struct key_val_struct {
3960 const char *keyname;
3961 int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
3963 {"SEQNUM/", validate_seqnum},
3964 {"NS/", validate_ns},
3965 {"SN/", validate_sn},
3967 {"LOC_POL/", validate_loc_pol},
3968 {"PWD_POL/", validate_pwd_pol},
3969 {"CRED/", validate_cred},
3970 {"UL/", validate_ul},
3971 {"GL/", validate_gl},
3972 {"UG/", validate_ug},
3973 {"UA", validate_ua},
3974 {"GM/", validate_gm},
3975 {"DR/", validate_dr},
3976 {"DE/", validate_de},
3977 {"NSS/PWINFO/", validate_pwinfo},
3978 {"TRUSTDOMCACHE/", validate_trustdomcache},
3979 {"NSS/NA/", validate_nss_na},
3980 {"NSS/AN/", validate_nss_an},
3981 {"WINBINDD_OFFLINE", validate_offline},
3982 {"NDR/", validate_ndr},
3983 {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
3987 /***********************************************************************
3988 Function to look at every entry in the tdb and validate it as far as
3990 ***********************************************************************/
3992 static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
3995 unsigned int max_key_len = 1024;
3996 struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
3998 /* Paranoia check. */
3999 if (strncmp("UA/", (const char *)kbuf.dptr, 3) == 0) {
4000 max_key_len = 1024 * 1024;
4002 if (kbuf.dsize > max_key_len) {
4003 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4005 (unsigned int)kbuf.dsize, (unsigned int)max_key_len));
4009 for (i = 0; key_val[i].keyname; i++) {
4010 size_t namelen = strlen(key_val[i].keyname);
4011 if (kbuf.dsize >= namelen && (
4012 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
4013 TALLOC_CTX *mem_ctx;
4017 keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
4021 memcpy(keystr, kbuf.dptr, kbuf.dsize);
4022 keystr[kbuf.dsize] = '\0';
4024 mem_ctx = talloc_init("validate_ctx");
4030 ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
4034 talloc_destroy(mem_ctx);
4039 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4040 dump_data(0, (uint8 *)kbuf.dptr, kbuf.dsize);
4041 DEBUG(0,("data :\n"));
4042 dump_data(0, (uint8 *)dbuf.dptr, dbuf.dsize);
4043 v_state->unknown_key = true;
4044 v_state->success = false;
4045 return 1; /* terminate. */
4048 static void validate_panic(const char *const why)
4050 DEBUG(0,("validating cache: would panic %s\n", why ));
4051 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4055 /***********************************************************************
4056 Try and validate every entry in the winbindd cache. If we fail here,
4057 delete the cache tdb and return non-zero.
4058 ***********************************************************************/
4060 int winbindd_validate_cache(void)
4063 const char *tdb_path = cache_path("winbindd_cache.tdb");
4064 TDB_CONTEXT *tdb = NULL;
4066 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4067 smb_panic_fn = validate_panic;
4070 tdb = tdb_open_log(tdb_path,
4071 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
4072 ( lp_winbind_offline_logon()
4074 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
4078 DEBUG(0, ("winbindd_validate_cache: "
4079 "error opening/initializing tdb\n"));
4084 ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
4087 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4088 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
4093 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4094 smb_panic_fn = smb_panic;
4098 /***********************************************************************
4099 Try and validate every entry in the winbindd cache.
4100 ***********************************************************************/
4102 int winbindd_validate_cache_nobackup(void)
4105 const char *tdb_path = cache_path("winbindd_cache.tdb");
4107 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4108 smb_panic_fn = validate_panic;
4111 if (wcache == NULL || wcache->tdb == NULL) {
4112 ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
4114 ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
4118 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4122 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4124 smb_panic_fn = smb_panic;
4128 bool winbindd_cache_validate_and_initialize(void)
4130 close_winbindd_cache();
4132 if (lp_winbind_offline_logon()) {
4133 if (winbindd_validate_cache() < 0) {
4134 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4135 "could be restored.\n"));
4139 return initialize_winbindd_cache();
4142 /*********************************************************************
4143 ********************************************************************/
4145 static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
4146 struct winbindd_tdc_domain **domains,
4147 size_t *num_domains )
4149 struct winbindd_tdc_domain *list = NULL;
4152 bool set_only = false;
4154 /* don't allow duplicates */
4159 for ( i=0; i< (*num_domains); i++ ) {
4160 if ( strequal( new_dom->name, list[i].domain_name ) ) {
4161 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4172 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, 1 );
4175 list = TALLOC_REALLOC_ARRAY( *domains, *domains,
4176 struct winbindd_tdc_domain,
4181 ZERO_STRUCT( list[idx] );
4187 list[idx].domain_name = talloc_strdup( list, new_dom->name );
4188 list[idx].dns_name = talloc_strdup( list, new_dom->alt_name );
4190 if ( !is_null_sid( &new_dom->sid ) ) {
4191 sid_copy( &list[idx].sid, &new_dom->sid );
4193 sid_copy(&list[idx].sid, &global_sid_NULL);
4196 if ( new_dom->domain_flags != 0x0 )
4197 list[idx].trust_flags = new_dom->domain_flags;
4199 if ( new_dom->domain_type != 0x0 )
4200 list[idx].trust_type = new_dom->domain_type;
4202 if ( new_dom->domain_trust_attribs != 0x0 )
4203 list[idx].trust_attribs = new_dom->domain_trust_attribs;
4207 *num_domains = idx + 1;
4213 /*********************************************************************
4214 ********************************************************************/
4216 static TDB_DATA make_tdc_key( const char *domain_name )
4218 char *keystr = NULL;
4219 TDB_DATA key = { NULL, 0 };
4221 if ( !domain_name ) {
4222 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4226 if (asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name ) == -1) {
4229 key = string_term_tdb_data(keystr);
4234 /*********************************************************************
4235 ********************************************************************/
4237 static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
4239 unsigned char **buf )
4241 unsigned char *buffer = NULL;
4246 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4254 /* Store the number of array items first */
4255 len += tdb_pack( buffer+len, buflen-len, "d",
4258 /* now pack each domain trust record */
4259 for ( i=0; i<num_domains; i++ ) {
4264 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4265 domains[i].domain_name,
4266 domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
4269 len += tdb_pack( buffer+len, buflen-len, "fffddd",
4270 domains[i].domain_name,
4271 domains[i].dns_name,
4272 sid_to_fstring(tmp, &domains[i].sid),
4273 domains[i].trust_flags,
4274 domains[i].trust_attribs,
4275 domains[i].trust_type );
4278 if ( buflen < len ) {
4280 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
4281 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4295 /*********************************************************************
4296 ********************************************************************/
4298 static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
4299 struct winbindd_tdc_domain **domains )
4301 fstring domain_name, dns_name, sid_string;
4302 uint32 type, attribs, flags;
4306 struct winbindd_tdc_domain *list = NULL;
4308 /* get the number of domains */
4309 len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
4311 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4315 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, num_domains );
4317 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4321 for ( i=0; i<num_domains; i++ ) {
4322 len += tdb_unpack( buf+len, buflen-len, "fffddd",
4331 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4332 TALLOC_FREE( list );
4336 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4337 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4338 domain_name, dns_name, sid_string,
4339 flags, attribs, type));
4341 list[i].domain_name = talloc_strdup( list, domain_name );
4342 list[i].dns_name = talloc_strdup( list, dns_name );
4343 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
4344 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4347 list[i].trust_flags = flags;
4348 list[i].trust_attribs = attribs;
4349 list[i].trust_type = type;
4357 /*********************************************************************
4358 ********************************************************************/
4360 static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
4362 TDB_DATA key = make_tdc_key( lp_workgroup() );
4363 TDB_DATA data = { NULL, 0 };
4369 /* See if we were asked to delete the cache entry */
4372 ret = tdb_delete( wcache->tdb, key );
4376 data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
4383 ret = tdb_store( wcache->tdb, key, data, 0 );
4386 SAFE_FREE( data.dptr );
4387 SAFE_FREE( key.dptr );
4389 return ( ret != -1 );
4392 /*********************************************************************
4393 ********************************************************************/
4395 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
4397 TDB_DATA key = make_tdc_key( lp_workgroup() );
4398 TDB_DATA data = { NULL, 0 };
4406 data = tdb_fetch( wcache->tdb, key );
4408 SAFE_FREE( key.dptr );
4413 *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
4415 SAFE_FREE( data.dptr );
4423 /*********************************************************************
4424 ********************************************************************/
4426 bool wcache_tdc_add_domain( struct winbindd_domain *domain )
4428 struct winbindd_tdc_domain *dom_list = NULL;
4429 size_t num_domains = 0;
4432 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4433 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4434 domain->name, domain->alt_name,
4435 sid_string_dbg(&domain->sid),
4436 domain->domain_flags,
4437 domain->domain_trust_attribs,
4438 domain->domain_type));
4440 if ( !init_wcache() ) {
4444 /* fetch the list */
4446 wcache_tdc_fetch_list( &dom_list, &num_domains );
4448 /* add the new domain */
4450 if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
4454 /* pack the domain */
4456 if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
4464 TALLOC_FREE( dom_list );
4469 /*********************************************************************
4470 ********************************************************************/
4472 struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
4474 struct winbindd_tdc_domain *dom_list = NULL;
4475 size_t num_domains = 0;
4477 struct winbindd_tdc_domain *d = NULL;
4479 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
4481 if ( !init_wcache() ) {
4485 /* fetch the list */
4487 wcache_tdc_fetch_list( &dom_list, &num_domains );
4489 for ( i=0; i<num_domains; i++ ) {
4490 if ( strequal(name, dom_list[i].domain_name) ||
4491 strequal(name, dom_list[i].dns_name) )
4493 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4496 d = TALLOC_P( ctx, struct winbindd_tdc_domain );
4500 d->domain_name = talloc_strdup( d, dom_list[i].domain_name );
4501 d->dns_name = talloc_strdup( d, dom_list[i].dns_name );
4502 sid_copy( &d->sid, &dom_list[i].sid );
4503 d->trust_flags = dom_list[i].trust_flags;
4504 d->trust_type = dom_list[i].trust_type;
4505 d->trust_attribs = dom_list[i].trust_attribs;
4511 TALLOC_FREE( dom_list );
4517 /*********************************************************************
4518 ********************************************************************/
4520 void wcache_tdc_clear( void )
4522 if ( !init_wcache() )
4525 wcache_tdc_store_list( NULL, 0 );
4531 /*********************************************************************
4532 ********************************************************************/
4534 static void wcache_save_user_pwinfo(struct winbindd_domain *domain,
4536 const struct dom_sid *user_sid,
4537 const char *homedir,
4542 struct cache_entry *centry;
4545 if ( (centry = centry_start(domain, status)) == NULL )
4548 centry_put_string( centry, homedir );
4549 centry_put_string( centry, shell );
4550 centry_put_string( centry, gecos );
4551 centry_put_uint32( centry, gid );
4553 centry_end(centry, "NSS/PWINFO/%s", sid_to_fstring(tmp, user_sid) );
4555 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid) ));
4557 centry_free(centry);
4560 NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
4561 const struct dom_sid *user_sid,
4563 ADS_STRUCT *ads, LDAPMessage *msg,
4564 const char **homedir, const char **shell,
4565 const char **gecos, gid_t *p_gid)
4567 struct winbind_cache *cache = get_cache(domain);
4568 struct cache_entry *centry = NULL;
4575 centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s",
4576 sid_to_fstring(tmp, user_sid));
4581 *homedir = centry_string( centry, ctx );
4582 *shell = centry_string( centry, ctx );
4583 *gecos = centry_string( centry, ctx );
4584 *p_gid = centry_uint32( centry );
4586 centry_free(centry);
4588 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4589 sid_string_dbg(user_sid)));
4591 return NT_STATUS_OK;
4595 nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg,
4596 homedir, shell, gecos, p_gid );
4598 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status)));
4600 if ( NT_STATUS_IS_OK(nt_status) ) {
4601 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir));
4602 DEBUGADD(10, ("\tshell = '%s'\n", *shell));
4603 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos));
4604 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid));
4606 wcache_save_user_pwinfo( domain, nt_status, user_sid,
4607 *homedir, *shell, *gecos, *p_gid );
4610 if ( NT_STATUS_EQUAL( nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
4611 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4613 set_domain_offline( domain );
4620 /* the cache backend methods are exposed via this structure */
4621 struct winbindd_methods cache_methods = {
4639 static bool wcache_ndr_key(TALLOC_CTX *mem_ctx, char *domain_name,
4640 uint32_t opnum, const DATA_BLOB *req,
4646 key = talloc_asprintf(mem_ctx, "NDR/%s/%d/", domain_name, (int)opnum);
4650 keylen = talloc_get_size(key) - 1;
4652 key = talloc_realloc(mem_ctx, key, char, keylen + req->length);
4656 memcpy(key + keylen, req->data, req->length);
4658 pkey->dptr = (uint8_t *)key;
4659 pkey->dsize = talloc_get_size(key);
4663 static bool wcache_opnum_cacheable(uint32_t opnum)
4666 case NDR_WBINT_PING:
4667 case NDR_WBINT_QUERYSEQUENCENUMBER:
4668 case NDR_WBINT_ALLOCATEUID:
4669 case NDR_WBINT_ALLOCATEGID:
4670 case NDR_WBINT_CHECKMACHINEACCOUNT:
4671 case NDR_WBINT_CHANGEMACHINEACCOUNT:
4672 case NDR_WBINT_PINGDC:
4678 bool wcache_fetch_ndr(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
4679 uint32_t opnum, const DATA_BLOB *req, DATA_BLOB *resp)
4684 if (!wcache_opnum_cacheable(opnum)) {
4688 if (wcache->tdb == NULL) {
4692 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4695 data = tdb_fetch(wcache->tdb, key);
4696 TALLOC_FREE(key.dptr);
4698 if (data.dptr == NULL) {
4701 if (data.dsize < 4) {
4705 if (!is_domain_offline(domain)) {
4706 uint32_t entry_seqnum, dom_seqnum, last_check;
4708 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum,
4712 entry_seqnum = IVAL(data.dptr, 0);
4713 if (entry_seqnum != dom_seqnum) {
4714 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4715 (int)entry_seqnum));
4720 resp->data = (uint8_t *)talloc_memdup(mem_ctx, data.dptr + 4,
4722 if (resp->data == NULL) {
4723 DEBUG(10, ("talloc failed\n"));
4726 resp->length = data.dsize - 4;
4730 SAFE_FREE(data.dptr);
4734 void wcache_store_ndr(struct winbindd_domain *domain, uint32_t opnum,
4735 const DATA_BLOB *req, const DATA_BLOB *resp)
4738 uint32_t dom_seqnum, last_check;
4740 if (!wcache_opnum_cacheable(opnum)) {
4744 if (wcache->tdb == NULL) {
4748 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum, &last_check)) {
4749 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4754 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4758 data.dsize = resp->length + 4;
4759 data.dptr = talloc_array(key.dptr, uint8_t, data.dsize);
4760 if (data.dptr == NULL) {
4764 SIVAL(data.dptr, 0, dom_seqnum);
4765 memcpy(data.dptr+4, resp->data, resp->length);
4767 tdb_store(wcache->tdb, key, data, 0);
4770 TALLOC_FREE(key.dptr);