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"
35 #define DBGC_CLASS DBGC_WINBIND
37 #define WINBINDD_CACHE_VERSION 1
38 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
40 extern struct winbindd_methods reconnect_methods;
42 extern struct winbindd_methods ads_methods;
44 extern struct winbindd_methods builtin_passdb_methods;
45 extern struct winbindd_methods sam_passdb_methods;
48 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
49 * Here are the list of entry types that are *not* stored
50 * as form struct cache_entry in the cache.
53 static const char *non_centry_keys[] = {
58 WINBINDD_CACHE_VERSION_KEYSTR,
62 /************************************************************************
63 Is this key a non-centry type ?
64 ************************************************************************/
66 static bool is_non_centry_key(TDB_DATA kbuf)
70 if (kbuf.dptr == NULL || kbuf.dsize == 0) {
73 for (i = 0; non_centry_keys[i] != NULL; i++) {
74 size_t namelen = strlen(non_centry_keys[i]);
75 if (kbuf.dsize < namelen) {
78 if (strncmp(non_centry_keys[i], (const char *)kbuf.dptr, namelen) == 0) {
85 /* Global online/offline state - False when online. winbindd starts up online
86 and sets this to true if the first query fails and there's an entry in
87 the cache tdb telling us to stay offline. */
89 static bool global_winbindd_offline_state;
91 struct winbind_cache {
97 uint32 sequence_number;
102 void (*smb_panic_fn)(const char *const why) = smb_panic;
104 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
106 static struct winbind_cache *wcache;
108 void winbindd_check_cache_size(time_t t)
110 static time_t last_check_time;
113 if (last_check_time == (time_t)0)
116 if (t - last_check_time < 60 && t - last_check_time > 0)
119 if (wcache == NULL || wcache->tdb == NULL) {
120 DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
124 if (fstat(tdb_fd(wcache->tdb), &st) == -1) {
125 DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno) ));
129 if (st.st_size > WINBINDD_MAX_CACHE_SIZE) {
130 DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
131 (unsigned long)st.st_size,
132 (unsigned long)WINBINDD_MAX_CACHE_SIZE));
133 wcache_flush_cache();
137 /* get the winbind_cache structure */
138 static struct winbind_cache *get_cache(struct winbindd_domain *domain)
140 struct winbind_cache *ret = wcache;
142 /* We have to know what type of domain we are dealing with first. */
144 if (domain->internal) {
145 domain->backend = &builtin_passdb_methods;
146 domain->initialized = True;
149 if (strequal(domain->name, get_global_sam_name()) &&
150 sid_equal(&domain->sid, get_global_sam_sid())) {
151 domain->backend = &sam_passdb_methods;
152 domain->initialized = True;
155 if ( !domain->initialized ) {
156 init_dc_connection( domain );
160 OK. listen up becasue I'm only going to say this once.
161 We have the following scenarios to consider
162 (a) trusted AD domains on a Samba DC,
163 (b) trusted AD domains and we are joined to a non-kerberos domain
164 (c) trusted AD domains and we are joined to a kerberos (AD) domain
166 For (a) we can always contact the trusted domain using krb5
167 since we have the domain trust account password
169 For (b) we can only use RPC since we have no way of
170 getting a krb5 ticket in our own domain
172 For (c) we can always use krb5 since we have a kerberos trust
177 if (!domain->backend) {
179 struct winbindd_domain *our_domain = domain;
181 /* find our domain first so we can figure out if we
182 are joined to a kerberized domain */
184 if ( !domain->primary )
185 our_domain = find_our_domain();
187 if ((our_domain->active_directory || IS_DC)
188 && domain->active_directory
189 && !lp_winbind_rpc_only()) {
190 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain->name));
191 domain->backend = &ads_methods;
193 #endif /* HAVE_ADS */
194 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain->name));
195 domain->backend = &reconnect_methods;
198 #endif /* HAVE_ADS */
204 ret = SMB_XMALLOC_P(struct winbind_cache);
208 wcache_flush_cache();
214 free a centry structure
216 static void centry_free(struct cache_entry *centry)
220 SAFE_FREE(centry->data);
224 static bool centry_check_bytes(struct cache_entry *centry, size_t nbytes)
226 if (centry->len - centry->ofs < nbytes) {
227 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
228 (unsigned int)nbytes,
229 centry->len - centry->ofs));
236 pull a uint32 from a cache entry
238 static uint32 centry_uint32(struct cache_entry *centry)
242 if (!centry_check_bytes(centry, 4)) {
243 smb_panic_fn("centry_uint32");
245 ret = IVAL(centry->data, centry->ofs);
251 pull a uint16 from a cache entry
253 static uint16 centry_uint16(struct cache_entry *centry)
256 if (!centry_check_bytes(centry, 2)) {
257 smb_panic_fn("centry_uint16");
259 ret = CVAL(centry->data, centry->ofs);
265 pull a uint8 from a cache entry
267 static uint8 centry_uint8(struct cache_entry *centry)
270 if (!centry_check_bytes(centry, 1)) {
271 smb_panic_fn("centry_uint8");
273 ret = CVAL(centry->data, centry->ofs);
279 pull a NTTIME from a cache entry
281 static NTTIME centry_nttime(struct cache_entry *centry)
284 if (!centry_check_bytes(centry, 8)) {
285 smb_panic_fn("centry_nttime");
287 ret = IVAL(centry->data, centry->ofs);
289 ret += (uint64_t)IVAL(centry->data, centry->ofs) << 32;
295 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
297 static time_t centry_time(struct cache_entry *centry)
299 return (time_t)centry_nttime(centry);
302 /* pull a string from a cache entry, using the supplied
305 static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
310 len = centry_uint8(centry);
313 /* a deliberate NULL string */
317 if (!centry_check_bytes(centry, (size_t)len)) {
318 smb_panic_fn("centry_string");
321 ret = TALLOC_ARRAY(mem_ctx, char, len+1);
323 smb_panic_fn("centry_string out of memory\n");
325 memcpy(ret,centry->data + centry->ofs, len);
331 /* pull a hash16 from a cache entry, using the supplied
334 static char *centry_hash16(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
339 len = centry_uint8(centry);
342 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
347 if (!centry_check_bytes(centry, 16)) {
351 ret = TALLOC_ARRAY(mem_ctx, char, 16);
353 smb_panic_fn("centry_hash out of memory\n");
355 memcpy(ret,centry->data + centry->ofs, 16);
360 /* pull a sid from a cache entry, using the supplied
363 static bool centry_sid(struct cache_entry *centry, struct dom_sid *sid)
368 sid_string = centry_string(centry, talloc_tos());
369 if (sid_string == NULL) {
372 ret = string_to_sid(sid, sid_string);
373 TALLOC_FREE(sid_string);
379 pull a NTSTATUS from a cache entry
381 static NTSTATUS centry_ntstatus(struct cache_entry *centry)
385 status = NT_STATUS(centry_uint32(centry));
390 /* the server is considered down if it can't give us a sequence number */
391 static bool wcache_server_down(struct winbindd_domain *domain)
398 ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
401 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
406 static bool wcache_fetch_seqnum(const char *domain_name, uint32_t *seqnum,
407 uint32_t *last_seq_check)
412 if (wcache->tdb == NULL) {
413 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
417 key = talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name);
419 DEBUG(10, ("talloc failed\n"));
423 data = tdb_fetch_bystring(wcache->tdb, key);
426 if (data.dptr == NULL) {
427 DEBUG(10, ("wcache_fetch_seqnum: %s not found\n",
431 if (data.dsize != 8) {
432 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
434 SAFE_FREE(data.dptr);
438 *seqnum = IVAL(data.dptr, 0);
439 *last_seq_check = IVAL(data.dptr, 4);
440 SAFE_FREE(data.dptr);
445 static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
447 uint32 last_check, time_diff;
449 if (!wcache_fetch_seqnum(domain->name, &domain->sequence_number,
451 return NT_STATUS_UNSUCCESSFUL;
453 domain->last_seq_check = last_check;
455 /* have we expired? */
457 time_diff = now - domain->last_seq_check;
458 if ( time_diff > lp_winbind_cache_time() ) {
459 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
460 domain->name, domain->sequence_number,
461 (uint32)domain->last_seq_check));
462 return NT_STATUS_UNSUCCESSFUL;
465 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
466 domain->name, domain->sequence_number,
467 (uint32)domain->last_seq_check));
472 bool wcache_store_seqnum(const char *domain_name, uint32_t seqnum,
473 time_t last_seq_check)
479 if (wcache->tdb == NULL) {
480 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
484 key_str = talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name);
485 if (key_str == NULL) {
486 DEBUG(10, ("talloc_asprintf failed\n"));
490 SIVAL(buf, 0, seqnum);
491 SIVAL(buf, 4, last_seq_check);
493 ret = tdb_store_bystring(wcache->tdb, key_str,
494 make_tdb_data(buf, sizeof(buf)), TDB_REPLACE);
495 TALLOC_FREE(key_str);
497 DEBUG(10, ("tdb_store_bystring failed: %s\n",
498 tdb_errorstr(wcache->tdb)));
499 TALLOC_FREE(key_str);
503 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
504 domain_name, seqnum, (unsigned)last_seq_check));
509 static bool store_cache_seqnum( struct winbindd_domain *domain )
511 return wcache_store_seqnum(domain->name, domain->sequence_number,
512 domain->last_seq_check);
516 refresh the domain sequence number. If force is true
517 then always refresh it, no matter how recently we fetched it
520 static void refresh_sequence_number(struct winbindd_domain *domain, bool force)
524 time_t t = time(NULL);
525 unsigned cache_time = lp_winbind_cache_time();
527 if (is_domain_offline(domain)) {
533 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
534 /* trying to reconnect is expensive, don't do it too often */
535 if (domain->sequence_number == DOM_SEQUENCE_NONE) {
540 time_diff = t - domain->last_seq_check;
542 /* see if we have to refetch the domain sequence number */
543 if (!force && (time_diff < cache_time) &&
544 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
545 NT_STATUS_IS_OK(domain->last_status)) {
546 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
550 /* try to get the sequence number from the tdb cache first */
551 /* this will update the timestamp as well */
553 status = fetch_cache_seqnum( domain, t );
554 if (NT_STATUS_IS_OK(status) &&
555 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
556 NT_STATUS_IS_OK(domain->last_status)) {
560 /* important! make sure that we know if this is a native
561 mode domain or not. And that we can contact it. */
563 if ( winbindd_can_contact_domain( domain ) ) {
564 status = domain->backend->sequence_number(domain,
565 &domain->sequence_number);
567 /* just use the current time */
568 status = NT_STATUS_OK;
569 domain->sequence_number = time(NULL);
573 /* the above call could have set our domain->backend to NULL when
574 * coming from offline to online mode, make sure to reinitialize the
575 * backend - Guenther */
578 if (!NT_STATUS_IS_OK(status)) {
579 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status)));
580 domain->sequence_number = DOM_SEQUENCE_NONE;
583 domain->last_status = status;
584 domain->last_seq_check = time(NULL);
586 /* save the new sequence number in the cache */
587 store_cache_seqnum( domain );
590 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
591 domain->name, domain->sequence_number));
597 decide if a cache entry has expired
599 static bool centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
601 /* If we've been told to be offline - stay in that state... */
602 if (lp_winbind_offline_logon() && global_winbindd_offline_state) {
603 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
604 keystr, domain->name ));
608 /* when the domain is offline return the cached entry.
609 * This deals with transient offline states... */
611 if (!domain->online) {
612 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
613 keystr, domain->name ));
617 /* if the server is OK and our cache entry came from when it was down then
618 the entry is invalid */
619 if ((domain->sequence_number != DOM_SEQUENCE_NONE) &&
620 (centry->sequence_number == DOM_SEQUENCE_NONE)) {
621 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
622 keystr, domain->name ));
626 /* if the server is down or the cache entry is not older than the
627 current sequence number then it is OK */
628 if (wcache_server_down(domain) ||
629 centry->sequence_number == domain->sequence_number) {
630 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
631 keystr, domain->name ));
635 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
636 keystr, domain->name ));
642 static struct cache_entry *wcache_fetch_raw(char *kstr)
645 struct cache_entry *centry;
648 key = string_tdb_data(kstr);
649 data = tdb_fetch(wcache->tdb, key);
655 centry = SMB_XMALLOC_P(struct cache_entry);
656 centry->data = (unsigned char *)data.dptr;
657 centry->len = data.dsize;
660 if (centry->len < 8) {
661 /* huh? corrupt cache? */
662 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr));
667 centry->status = centry_ntstatus(centry);
668 centry->sequence_number = centry_uint32(centry);
673 static bool is_my_own_sam_domain(struct winbindd_domain *domain)
675 if (strequal(domain->name, get_global_sam_name()) &&
676 sid_equal(&domain->sid, get_global_sam_sid())) {
683 static bool is_builtin_domain(struct winbindd_domain *domain)
685 if (strequal(domain->name, "BUILTIN") &&
686 sid_equal(&domain->sid, &global_sid_Builtin)) {
694 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
695 number and return status
697 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
698 struct winbindd_domain *domain,
699 const char *format, ...) PRINTF_ATTRIBUTE(3,4);
700 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
701 struct winbindd_domain *domain,
702 const char *format, ...)
706 struct cache_entry *centry;
708 if (!winbindd_use_cache() ||
709 is_my_own_sam_domain(domain) ||
710 is_builtin_domain(domain)) {
714 refresh_sequence_number(domain, false);
716 va_start(ap, format);
717 smb_xvasprintf(&kstr, format, ap);
720 centry = wcache_fetch_raw(kstr);
721 if (centry == NULL) {
726 if (centry_expired(domain, kstr, centry)) {
728 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
729 kstr, domain->name ));
736 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
737 kstr, domain->name ));
743 static void wcache_delete(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
744 static void wcache_delete(const char *format, ...)
750 va_start(ap, format);
751 smb_xvasprintf(&kstr, format, ap);
754 key = string_tdb_data(kstr);
756 tdb_delete(wcache->tdb, key);
761 make sure we have at least len bytes available in a centry
763 static void centry_expand(struct cache_entry *centry, uint32 len)
765 if (centry->len - centry->ofs >= len)
768 centry->data = SMB_REALLOC_ARRAY(centry->data, unsigned char,
771 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
772 smb_panic_fn("out of memory in centry_expand");
777 push a uint32 into a centry
779 static void centry_put_uint32(struct cache_entry *centry, uint32 v)
781 centry_expand(centry, 4);
782 SIVAL(centry->data, centry->ofs, v);
787 push a uint16 into a centry
789 static void centry_put_uint16(struct cache_entry *centry, uint16 v)
791 centry_expand(centry, 2);
792 SIVAL(centry->data, centry->ofs, v);
797 push a uint8 into a centry
799 static void centry_put_uint8(struct cache_entry *centry, uint8 v)
801 centry_expand(centry, 1);
802 SCVAL(centry->data, centry->ofs, v);
807 push a string into a centry
809 static void centry_put_string(struct cache_entry *centry, const char *s)
814 /* null strings are marked as len 0xFFFF */
815 centry_put_uint8(centry, 0xFF);
820 /* can't handle more than 254 char strings. Truncating is probably best */
822 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len));
825 centry_put_uint8(centry, len);
826 centry_expand(centry, len);
827 memcpy(centry->data + centry->ofs, s, len);
832 push a 16 byte hash into a centry - treat as 16 byte string.
834 static void centry_put_hash16(struct cache_entry *centry, const uint8 val[16])
836 centry_put_uint8(centry, 16);
837 centry_expand(centry, 16);
838 memcpy(centry->data + centry->ofs, val, 16);
842 static void centry_put_sid(struct cache_entry *centry, const struct dom_sid *sid)
845 centry_put_string(centry, sid_to_fstring(sid_string, sid));
850 put NTSTATUS into a centry
852 static void centry_put_ntstatus(struct cache_entry *centry, NTSTATUS status)
854 uint32 status_value = NT_STATUS_V(status);
855 centry_put_uint32(centry, status_value);
860 push a NTTIME into a centry
862 static void centry_put_nttime(struct cache_entry *centry, NTTIME nt)
864 centry_expand(centry, 8);
865 SIVAL(centry->data, centry->ofs, nt & 0xFFFFFFFF);
867 SIVAL(centry->data, centry->ofs, nt >> 32);
872 push a time_t into a centry - use a 64 bit size.
873 NTTIME here is being used as a convenient 64-bit size.
875 static void centry_put_time(struct cache_entry *centry, time_t t)
877 NTTIME nt = (NTTIME)t;
878 centry_put_nttime(centry, nt);
882 start a centry for output. When finished, call centry_end()
884 struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status)
886 struct cache_entry *centry;
891 centry = SMB_XMALLOC_P(struct cache_entry);
893 centry->len = 8192; /* reasonable default */
894 centry->data = SMB_XMALLOC_ARRAY(uint8, centry->len);
896 centry->sequence_number = domain->sequence_number;
897 centry_put_ntstatus(centry, status);
898 centry_put_uint32(centry, centry->sequence_number);
903 finish a centry and write it to the tdb
905 static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
906 static void centry_end(struct cache_entry *centry, const char *format, ...)
912 if (!winbindd_use_cache()) {
916 va_start(ap, format);
917 smb_xvasprintf(&kstr, format, ap);
920 key = string_tdb_data(kstr);
921 data.dptr = centry->data;
922 data.dsize = centry->ofs;
924 tdb_store(wcache->tdb, key, data, TDB_REPLACE);
928 static void wcache_save_name_to_sid(struct winbindd_domain *domain,
929 NTSTATUS status, const char *domain_name,
930 const char *name, const struct dom_sid *sid,
931 enum lsa_SidType type)
933 struct cache_entry *centry;
936 centry = centry_start(domain, status);
939 centry_put_uint32(centry, type);
940 centry_put_sid(centry, sid);
941 fstrcpy(uname, name);
943 centry_end(centry, "NS/%s/%s", domain_name, uname);
944 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name,
945 uname, sid_string_dbg(sid), nt_errstr(status)));
949 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
950 const struct dom_sid *sid, const char *domain_name, const char *name, enum lsa_SidType type)
952 struct cache_entry *centry;
955 centry = centry_start(domain, status);
959 if (NT_STATUS_IS_OK(status)) {
960 centry_put_uint32(centry, type);
961 centry_put_string(centry, domain_name);
962 centry_put_string(centry, name);
965 centry_end(centry, "SN/%s", sid_to_fstring(sid_string, sid));
966 DEBUG(10,("wcache_save_sid_to_name: %s -> %s (%s)\n", sid_string,
967 name, nt_errstr(status)));
972 static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status,
973 struct wbint_userinfo *info)
975 struct cache_entry *centry;
978 if (is_null_sid(&info->user_sid)) {
982 centry = centry_start(domain, status);
985 centry_put_string(centry, info->acct_name);
986 centry_put_string(centry, info->full_name);
987 centry_put_string(centry, info->homedir);
988 centry_put_string(centry, info->shell);
989 centry_put_uint32(centry, info->primary_gid);
990 centry_put_sid(centry, &info->user_sid);
991 centry_put_sid(centry, &info->group_sid);
992 centry_end(centry, "U/%s", sid_to_fstring(sid_string,
994 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
998 static void wcache_save_lockout_policy(struct winbindd_domain *domain,
1000 struct samr_DomInfo12 *lockout_policy)
1002 struct cache_entry *centry;
1004 centry = centry_start(domain, status);
1008 centry_put_nttime(centry, lockout_policy->lockout_duration);
1009 centry_put_nttime(centry, lockout_policy->lockout_window);
1010 centry_put_uint16(centry, lockout_policy->lockout_threshold);
1012 centry_end(centry, "LOC_POL/%s", domain->name);
1014 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
1016 centry_free(centry);
1021 static void wcache_save_password_policy(struct winbindd_domain *domain,
1023 struct samr_DomInfo1 *policy)
1025 struct cache_entry *centry;
1027 centry = centry_start(domain, status);
1031 centry_put_uint16(centry, policy->min_password_length);
1032 centry_put_uint16(centry, policy->password_history_length);
1033 centry_put_uint32(centry, policy->password_properties);
1034 centry_put_nttime(centry, policy->max_password_age);
1035 centry_put_nttime(centry, policy->min_password_age);
1037 centry_end(centry, "PWD_POL/%s", domain->name);
1039 DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
1041 centry_free(centry);
1044 /***************************************************************************
1045 ***************************************************************************/
1047 static void wcache_save_username_alias(struct winbindd_domain *domain,
1049 const char *name, const char *alias)
1051 struct cache_entry *centry;
1054 if ( (centry = centry_start(domain, status)) == NULL )
1057 centry_put_string( centry, alias );
1059 fstrcpy(uname, name);
1061 centry_end(centry, "NSS/NA/%s", uname);
1063 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name, alias ));
1065 centry_free(centry);
1068 static void wcache_save_alias_username(struct winbindd_domain *domain,
1070 const char *alias, const char *name)
1072 struct cache_entry *centry;
1075 if ( (centry = centry_start(domain, status)) == NULL )
1078 centry_put_string( centry, name );
1080 fstrcpy(uname, alias);
1082 centry_end(centry, "NSS/AN/%s", uname);
1084 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias, name ));
1086 centry_free(centry);
1089 /***************************************************************************
1090 ***************************************************************************/
1092 NTSTATUS resolve_username_to_alias( TALLOC_CTX *mem_ctx,
1093 struct winbindd_domain *domain,
1094 const char *name, char **alias )
1096 struct winbind_cache *cache = get_cache(domain);
1097 struct cache_entry *centry = NULL;
1101 if ( domain->internal )
1102 return NT_STATUS_NOT_SUPPORTED;
1107 if ( (upper_name = SMB_STRDUP(name)) == NULL )
1108 return NT_STATUS_NO_MEMORY;
1109 strupper_m(upper_name);
1111 centry = wcache_fetch(cache, domain, "NSS/NA/%s", upper_name);
1113 SAFE_FREE( upper_name );
1118 status = centry->status;
1120 if (!NT_STATUS_IS_OK(status)) {
1121 centry_free(centry);
1125 *alias = centry_string( centry, mem_ctx );
1127 centry_free(centry);
1129 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1130 name, *alias ? *alias : "(none)"));
1132 return (*alias) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1136 /* If its not in cache and we are offline, then fail */
1138 if ( get_global_winbindd_state_offline() || !domain->online ) {
1139 DEBUG(8,("resolve_username_to_alias: rejecting query "
1140 "in offline mode\n"));
1141 return NT_STATUS_NOT_FOUND;
1144 status = nss_map_to_alias( mem_ctx, domain->name, name, alias );
1146 if ( NT_STATUS_IS_OK( status ) ) {
1147 wcache_save_username_alias(domain, status, name, *alias);
1150 if ( NT_STATUS_EQUAL( status, NT_STATUS_NONE_MAPPED ) ) {
1151 wcache_save_username_alias(domain, status, name, "(NULL)");
1154 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1155 nt_errstr(status)));
1157 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1158 set_domain_offline( domain );
1164 /***************************************************************************
1165 ***************************************************************************/
1167 NTSTATUS resolve_alias_to_username( TALLOC_CTX *mem_ctx,
1168 struct winbindd_domain *domain,
1169 const char *alias, char **name )
1171 struct winbind_cache *cache = get_cache(domain);
1172 struct cache_entry *centry = NULL;
1176 if ( domain->internal )
1177 return NT_STATUS_NOT_SUPPORTED;
1182 if ( (upper_name = SMB_STRDUP(alias)) == NULL )
1183 return NT_STATUS_NO_MEMORY;
1184 strupper_m(upper_name);
1186 centry = wcache_fetch(cache, domain, "NSS/AN/%s", upper_name);
1188 SAFE_FREE( upper_name );
1193 status = centry->status;
1195 if (!NT_STATUS_IS_OK(status)) {
1196 centry_free(centry);
1200 *name = centry_string( centry, mem_ctx );
1202 centry_free(centry);
1204 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1205 alias, *name ? *name : "(none)"));
1207 return (*name) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1211 /* If its not in cache and we are offline, then fail */
1213 if ( get_global_winbindd_state_offline() || !domain->online ) {
1214 DEBUG(8,("resolve_alias_to_username: rejecting query "
1215 "in offline mode\n"));
1216 return NT_STATUS_NOT_FOUND;
1219 /* an alias cannot contain a domain prefix or '@' */
1221 if (strchr(alias, '\\') || strchr(alias, '@')) {
1222 DEBUG(10,("resolve_alias_to_username: skipping fully "
1223 "qualified name %s\n", alias));
1224 return NT_STATUS_OBJECT_NAME_INVALID;
1227 status = nss_map_from_alias( mem_ctx, domain->name, alias, name );
1229 if ( NT_STATUS_IS_OK( status ) ) {
1230 wcache_save_alias_username( domain, status, alias, *name );
1233 if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1234 wcache_save_alias_username(domain, status, alias, "(NULL)");
1237 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1238 nt_errstr(status)));
1240 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1241 set_domain_offline( domain );
1247 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const struct dom_sid *sid)
1249 struct winbind_cache *cache = get_cache(domain);
1251 fstring key_str, tmp;
1255 return NT_STATUS_INTERNAL_DB_ERROR;
1258 if (is_null_sid(sid)) {
1259 return NT_STATUS_INVALID_SID;
1262 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1263 return NT_STATUS_INVALID_SID;
1266 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
1268 data = tdb_fetch(cache->tdb, string_tdb_data(key_str));
1270 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1273 SAFE_FREE(data.dptr);
1274 return NT_STATUS_OK;
1277 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1278 as new salted ones. */
1280 NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
1281 TALLOC_CTX *mem_ctx,
1282 const struct dom_sid *sid,
1283 const uint8 **cached_nt_pass,
1284 const uint8 **cached_salt)
1286 struct winbind_cache *cache = get_cache(domain);
1287 struct cache_entry *centry = NULL;
1294 return NT_STATUS_INTERNAL_DB_ERROR;
1297 if (is_null_sid(sid)) {
1298 return NT_STATUS_INVALID_SID;
1301 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1302 return NT_STATUS_INVALID_SID;
1305 /* Try and get a salted cred first. If we can't
1306 fall back to an unsalted cred. */
1308 centry = wcache_fetch(cache, domain, "CRED/%s",
1309 sid_to_fstring(tmp, sid));
1311 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1312 sid_string_dbg(sid)));
1313 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1316 t = centry_time(centry);
1318 /* In the salted case this isn't actually the nt_hash itself,
1319 but the MD5 of the salt + nt_hash. Let the caller
1320 sort this out. It can tell as we only return the cached_salt
1321 if we are returning a salted cred. */
1323 *cached_nt_pass = (const uint8 *)centry_hash16(centry, mem_ctx);
1324 if (*cached_nt_pass == NULL) {
1327 sid_to_fstring(sidstr, sid);
1329 /* Bad (old) cred cache. Delete and pretend we
1331 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1333 wcache_delete("CRED/%s", sidstr);
1334 centry_free(centry);
1335 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1338 /* We only have 17 bytes more data in the salted cred case. */
1339 if (centry->len - centry->ofs == 17) {
1340 *cached_salt = (const uint8 *)centry_hash16(centry, mem_ctx);
1342 *cached_salt = NULL;
1345 dump_data_pw("cached_nt_pass", *cached_nt_pass, NT_HASH_LEN);
1347 dump_data_pw("cached_salt", *cached_salt, NT_HASH_LEN);
1350 status = centry->status;
1352 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1353 sid_string_dbg(sid), nt_errstr(status) ));
1355 centry_free(centry);
1359 /* Store creds for a SID - only writes out new salted ones. */
1361 NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
1362 TALLOC_CTX *mem_ctx,
1363 const struct dom_sid *sid,
1364 const uint8 nt_pass[NT_HASH_LEN])
1366 struct cache_entry *centry;
1369 uint8 cred_salt[NT_HASH_LEN];
1370 uint8 salted_hash[NT_HASH_LEN];
1372 if (is_null_sid(sid)) {
1373 return NT_STATUS_INVALID_SID;
1376 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1377 return NT_STATUS_INVALID_SID;
1380 centry = centry_start(domain, NT_STATUS_OK);
1382 return NT_STATUS_INTERNAL_DB_ERROR;
1385 dump_data_pw("nt_pass", nt_pass, NT_HASH_LEN);
1387 centry_put_time(centry, time(NULL));
1389 /* Create a salt and then salt the hash. */
1390 generate_random_buffer(cred_salt, NT_HASH_LEN);
1391 E_md5hash(cred_salt, nt_pass, salted_hash);
1393 centry_put_hash16(centry, salted_hash);
1394 centry_put_hash16(centry, cred_salt);
1395 centry_end(centry, "CRED/%s", sid_to_fstring(sid_string, sid));
1397 DEBUG(10,("wcache_save_creds: %s\n", sid_string));
1399 centry_free(centry);
1401 return NT_STATUS_OK;
1405 /* Query display info. This is the basic user list fn */
1406 static NTSTATUS query_user_list(struct winbindd_domain *domain,
1407 TALLOC_CTX *mem_ctx,
1408 uint32 *num_entries,
1409 struct wbint_userinfo **info)
1411 struct winbind_cache *cache = get_cache(domain);
1412 struct cache_entry *centry = NULL;
1414 unsigned int i, retry;
1415 bool old_status = domain->online;
1420 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1425 *num_entries = centry_uint32(centry);
1427 if (*num_entries == 0)
1430 (*info) = TALLOC_ARRAY(mem_ctx, struct wbint_userinfo, *num_entries);
1432 smb_panic_fn("query_user_list out of memory");
1434 for (i=0; i<(*num_entries); i++) {
1435 (*info)[i].acct_name = centry_string(centry, mem_ctx);
1436 (*info)[i].full_name = centry_string(centry, mem_ctx);
1437 (*info)[i].homedir = centry_string(centry, mem_ctx);
1438 (*info)[i].shell = centry_string(centry, mem_ctx);
1439 centry_sid(centry, &(*info)[i].user_sid);
1440 centry_sid(centry, &(*info)[i].group_sid);
1444 status = centry->status;
1446 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1447 domain->name, nt_errstr(status) ));
1449 centry_free(centry);
1456 /* Return status value returned by seq number check */
1458 if (!NT_STATUS_IS_OK(domain->last_status))
1459 return domain->last_status;
1461 /* Put the query_user_list() in a retry loop. There appears to be
1462 * some bug either with Windows 2000 or Samba's handling of large
1463 * rpc replies. This manifests itself as sudden disconnection
1464 * at a random point in the enumeration of a large (60k) user list.
1465 * The retry loop simply tries the operation again. )-: It's not
1466 * pretty but an acceptable workaround until we work out what the
1467 * real problem is. */
1472 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1475 status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
1476 if (!NT_STATUS_IS_OK(status)) {
1477 DEBUG(3, ("query_user_list: returned 0x%08x, "
1478 "retrying\n", NT_STATUS_V(status)));
1480 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1481 DEBUG(3, ("query_user_list: flushing "
1482 "connection cache\n"));
1483 invalidate_cm_connection(&domain->conn);
1485 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1486 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1487 if (!domain->internal && old_status) {
1488 set_domain_offline(domain);
1490 /* store partial response. */
1491 if (*num_entries > 0) {
1493 * humm, what about the status used for cache?
1494 * Should it be NT_STATUS_OK?
1499 * domain is offline now, and there is no user entries,
1500 * try to fetch from cache again.
1502 if (cache->tdb && !domain->online && !domain->internal && old_status) {
1503 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1504 /* partial response... */
1508 goto do_fetch_cache;
1515 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
1519 refresh_sequence_number(domain, false);
1520 if (!NT_STATUS_IS_OK(status)) {
1523 centry = centry_start(domain, status);
1526 centry_put_uint32(centry, *num_entries);
1527 for (i=0; i<(*num_entries); i++) {
1528 centry_put_string(centry, (*info)[i].acct_name);
1529 centry_put_string(centry, (*info)[i].full_name);
1530 centry_put_string(centry, (*info)[i].homedir);
1531 centry_put_string(centry, (*info)[i].shell);
1532 centry_put_sid(centry, &(*info)[i].user_sid);
1533 centry_put_sid(centry, &(*info)[i].group_sid);
1534 if (domain->backend && domain->backend->consistent) {
1535 /* when the backend is consistent we can pre-prime some mappings */
1536 wcache_save_name_to_sid(domain, NT_STATUS_OK,
1538 (*info)[i].acct_name,
1539 &(*info)[i].user_sid,
1541 wcache_save_sid_to_name(domain, NT_STATUS_OK,
1542 &(*info)[i].user_sid,
1544 (*info)[i].acct_name,
1546 wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
1549 centry_end(centry, "UL/%s", domain->name);
1550 centry_free(centry);
1556 /* list all domain groups */
1557 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
1558 TALLOC_CTX *mem_ctx,
1559 uint32 *num_entries,
1560 struct acct_info **info)
1562 struct winbind_cache *cache = get_cache(domain);
1563 struct cache_entry *centry = NULL;
1568 old_status = domain->online;
1572 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1577 *num_entries = centry_uint32(centry);
1579 if (*num_entries == 0)
1582 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1584 smb_panic_fn("enum_dom_groups out of memory");
1586 for (i=0; i<(*num_entries); i++) {
1587 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1588 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1589 (*info)[i].rid = centry_uint32(centry);
1593 status = centry->status;
1595 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1596 domain->name, nt_errstr(status) ));
1598 centry_free(centry);
1605 /* Return status value returned by seq number check */
1607 if (!NT_STATUS_IS_OK(domain->last_status))
1608 return domain->last_status;
1610 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1613 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1615 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1616 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1617 if (!domain->internal && old_status) {
1618 set_domain_offline(domain);
1622 !domain->internal &&
1624 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1626 goto do_fetch_cache;
1631 refresh_sequence_number(domain, false);
1632 if (!NT_STATUS_IS_OK(status)) {
1635 centry = centry_start(domain, status);
1638 centry_put_uint32(centry, *num_entries);
1639 for (i=0; i<(*num_entries); i++) {
1640 centry_put_string(centry, (*info)[i].acct_name);
1641 centry_put_string(centry, (*info)[i].acct_desc);
1642 centry_put_uint32(centry, (*info)[i].rid);
1644 centry_end(centry, "GL/%s/domain", domain->name);
1645 centry_free(centry);
1651 /* list all domain groups */
1652 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
1653 TALLOC_CTX *mem_ctx,
1654 uint32 *num_entries,
1655 struct acct_info **info)
1657 struct winbind_cache *cache = get_cache(domain);
1658 struct cache_entry *centry = NULL;
1663 old_status = domain->online;
1667 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1672 *num_entries = centry_uint32(centry);
1674 if (*num_entries == 0)
1677 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1679 smb_panic_fn("enum_dom_groups out of memory");
1681 for (i=0; i<(*num_entries); i++) {
1682 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1683 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1684 (*info)[i].rid = centry_uint32(centry);
1689 /* If we are returning cached data and the domain controller
1690 is down then we don't know whether the data is up to date
1691 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1694 if (wcache_server_down(domain)) {
1695 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1696 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1698 status = centry->status;
1700 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1701 domain->name, nt_errstr(status) ));
1703 centry_free(centry);
1710 /* Return status value returned by seq number check */
1712 if (!NT_STATUS_IS_OK(domain->last_status))
1713 return domain->last_status;
1715 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1718 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1720 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1721 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1722 if (!domain->internal && old_status) {
1723 set_domain_offline(domain);
1726 !domain->internal &&
1729 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1731 goto do_fetch_cache;
1736 refresh_sequence_number(domain, false);
1737 if (!NT_STATUS_IS_OK(status)) {
1740 centry = centry_start(domain, status);
1743 centry_put_uint32(centry, *num_entries);
1744 for (i=0; i<(*num_entries); i++) {
1745 centry_put_string(centry, (*info)[i].acct_name);
1746 centry_put_string(centry, (*info)[i].acct_desc);
1747 centry_put_uint32(centry, (*info)[i].rid);
1749 centry_end(centry, "GL/%s/local", domain->name);
1750 centry_free(centry);
1756 NTSTATUS wcache_name_to_sid(struct winbindd_domain *domain,
1757 const char *domain_name,
1759 struct dom_sid *sid,
1760 enum lsa_SidType *type)
1762 struct winbind_cache *cache = get_cache(domain);
1763 struct cache_entry *centry;
1767 if (cache->tdb == NULL) {
1768 return NT_STATUS_NOT_FOUND;
1771 uname = talloc_strdup_upper(talloc_tos(), name);
1772 if (uname == NULL) {
1773 return NT_STATUS_NO_MEMORY;
1776 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1778 if (centry == NULL) {
1779 return NT_STATUS_NOT_FOUND;
1782 status = centry->status;
1783 if (NT_STATUS_IS_OK(status)) {
1784 *type = (enum lsa_SidType)centry_uint32(centry);
1785 centry_sid(centry, sid);
1788 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1789 "%s\n", domain->name, nt_errstr(status) ));
1791 centry_free(centry);
1795 /* convert a single name to a sid in a domain */
1796 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
1797 TALLOC_CTX *mem_ctx,
1798 const char *domain_name,
1801 struct dom_sid *sid,
1802 enum lsa_SidType *type)
1807 old_status = domain->online;
1809 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1810 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1816 /* If the seq number check indicated that there is a problem
1817 * with this DC, then return that status... except for
1818 * access_denied. This is special because the dc may be in
1819 * "restrict anonymous = 1" mode, in which case it will deny
1820 * most unauthenticated operations, but *will* allow the LSA
1821 * name-to-sid that we try as a fallback. */
1823 if (!(NT_STATUS_IS_OK(domain->last_status)
1824 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1825 return domain->last_status;
1827 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1830 status = domain->backend->name_to_sid(domain, mem_ctx, domain_name,
1831 name, flags, sid, type);
1833 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1834 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1835 if (!domain->internal && old_status) {
1836 set_domain_offline(domain);
1838 if (!domain->internal &&
1841 NTSTATUS cache_status;
1842 cache_status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1843 return cache_status;
1847 refresh_sequence_number(domain, false);
1849 if (domain->online &&
1850 (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
1851 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1853 /* Only save the reverse mapping if this was not a UPN */
1854 if (!strchr(name, '@')) {
1855 strupper_m(CONST_DISCARD(char *,domain_name));
1856 strlower_m(CONST_DISCARD(char *,name));
1857 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1864 NTSTATUS wcache_sid_to_name(struct winbindd_domain *domain,
1865 const struct dom_sid *sid,
1866 TALLOC_CTX *mem_ctx,
1869 enum lsa_SidType *type)
1871 struct winbind_cache *cache = get_cache(domain);
1872 struct cache_entry *centry;
1876 if (cache->tdb == NULL) {
1877 return NT_STATUS_NOT_FOUND;
1880 sid_string = sid_string_tos(sid);
1881 if (sid_string == NULL) {
1882 return NT_STATUS_NO_MEMORY;
1885 centry = wcache_fetch(cache, domain, "SN/%s", sid_string);
1886 TALLOC_FREE(sid_string);
1887 if (centry == NULL) {
1888 return NT_STATUS_NOT_FOUND;
1891 if (NT_STATUS_IS_OK(centry->status)) {
1892 *type = (enum lsa_SidType)centry_uint32(centry);
1893 *domain_name = centry_string(centry, mem_ctx);
1894 *name = centry_string(centry, mem_ctx);
1897 status = centry->status;
1898 centry_free(centry);
1900 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1901 "%s\n", domain->name, nt_errstr(status) ));
1906 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1908 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
1909 TALLOC_CTX *mem_ctx,
1910 const struct dom_sid *sid,
1913 enum lsa_SidType *type)
1918 old_status = domain->online;
1919 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
1921 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1926 *domain_name = NULL;
1928 /* If the seq number check indicated that there is a problem
1929 * with this DC, then return that status... except for
1930 * access_denied. This is special because the dc may be in
1931 * "restrict anonymous = 1" mode, in which case it will deny
1932 * most unauthenticated operations, but *will* allow the LSA
1933 * sid-to-name that we try as a fallback. */
1935 if (!(NT_STATUS_IS_OK(domain->last_status)
1936 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1937 return domain->last_status;
1939 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1942 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1944 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1945 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1946 if (!domain->internal && old_status) {
1947 set_domain_offline(domain);
1949 if (!domain->internal &&
1952 NTSTATUS cache_status;
1953 cache_status = wcache_sid_to_name(domain, sid, mem_ctx,
1954 domain_name, name, type);
1955 return cache_status;
1959 refresh_sequence_number(domain, false);
1960 if (!NT_STATUS_IS_OK(status)) {
1963 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1965 /* We can't save the name to sid mapping here, as with sid history a
1966 * later name2sid would give the wrong sid. */
1971 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
1972 TALLOC_CTX *mem_ctx,
1973 const struct dom_sid *domain_sid,
1978 enum lsa_SidType **types)
1980 struct winbind_cache *cache = get_cache(domain);
1982 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1987 old_status = domain->online;
1988 *domain_name = NULL;
1996 if (num_rids == 0) {
1997 return NT_STATUS_OK;
2000 *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
2001 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
2003 if ((*names == NULL) || (*types == NULL)) {
2004 result = NT_STATUS_NO_MEMORY;
2008 have_mapped = have_unmapped = false;
2010 for (i=0; i<num_rids; i++) {
2012 struct cache_entry *centry;
2015 if (!sid_compose(&sid, domain_sid, rids[i])) {
2016 result = NT_STATUS_INTERNAL_ERROR;
2020 centry = wcache_fetch(cache, domain, "SN/%s",
2021 sid_to_fstring(tmp, &sid));
2026 (*types)[i] = SID_NAME_UNKNOWN;
2027 (*names)[i] = talloc_strdup(*names, "");
2029 if (NT_STATUS_IS_OK(centry->status)) {
2032 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
2034 dom = centry_string(centry, mem_ctx);
2035 if (*domain_name == NULL) {
2041 (*names)[i] = centry_string(centry, *names);
2043 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
2044 have_unmapped = true;
2047 /* something's definitely wrong */
2048 result = centry->status;
2052 centry_free(centry);
2056 return NT_STATUS_NONE_MAPPED;
2058 if (!have_unmapped) {
2059 return NT_STATUS_OK;
2061 return STATUS_SOME_UNMAPPED;
2065 TALLOC_FREE(*names);
2066 TALLOC_FREE(*types);
2068 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
2069 rids, num_rids, domain_name,
2072 if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
2073 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2074 if (!domain->internal && old_status) {
2075 set_domain_offline(domain);
2078 !domain->internal &&
2081 have_mapped = have_unmapped = false;
2083 for (i=0; i<num_rids; i++) {
2085 struct cache_entry *centry;
2088 if (!sid_compose(&sid, domain_sid, rids[i])) {
2089 result = NT_STATUS_INTERNAL_ERROR;
2093 centry = wcache_fetch(cache, domain, "SN/%s",
2094 sid_to_fstring(tmp, &sid));
2096 (*types)[i] = SID_NAME_UNKNOWN;
2097 (*names)[i] = talloc_strdup(*names, "");
2101 (*types)[i] = SID_NAME_UNKNOWN;
2102 (*names)[i] = talloc_strdup(*names, "");
2104 if (NT_STATUS_IS_OK(centry->status)) {
2107 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
2109 dom = centry_string(centry, mem_ctx);
2110 if (*domain_name == NULL) {
2116 (*names)[i] = centry_string(centry, *names);
2118 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
2119 have_unmapped = true;
2122 /* something's definitely wrong */
2123 result = centry->status;
2127 centry_free(centry);
2131 return NT_STATUS_NONE_MAPPED;
2133 if (!have_unmapped) {
2134 return NT_STATUS_OK;
2136 return STATUS_SOME_UNMAPPED;
2140 None of the queried rids has been found so save all negative entries
2142 if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
2143 for (i = 0; i < num_rids; i++) {
2145 const char *name = "";
2146 const enum lsa_SidType type = SID_NAME_UNKNOWN;
2147 NTSTATUS status = NT_STATUS_NONE_MAPPED;
2149 if (!sid_compose(&sid, domain_sid, rids[i])) {
2150 return NT_STATUS_INTERNAL_ERROR;
2153 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2161 Some or all of the queried rids have been found.
2163 if (!NT_STATUS_IS_OK(result) &&
2164 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
2168 refresh_sequence_number(domain, false);
2170 for (i=0; i<num_rids; i++) {
2174 if (!sid_compose(&sid, domain_sid, rids[i])) {
2175 result = NT_STATUS_INTERNAL_ERROR;
2179 status = (*types)[i] == SID_NAME_UNKNOWN ?
2180 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
2182 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2183 (*names)[i], (*types)[i]);
2189 TALLOC_FREE(*names);
2190 TALLOC_FREE(*types);
2194 NTSTATUS wcache_query_user(struct winbindd_domain *domain,
2195 TALLOC_CTX *mem_ctx,
2196 const struct dom_sid *user_sid,
2197 struct wbint_userinfo *info)
2199 struct winbind_cache *cache = get_cache(domain);
2200 struct cache_entry *centry = NULL;
2204 if (cache->tdb == NULL) {
2205 return NT_STATUS_NOT_FOUND;
2208 sid_string = sid_string_tos(user_sid);
2209 if (sid_string == NULL) {
2210 return NT_STATUS_NO_MEMORY;
2213 centry = wcache_fetch(cache, domain, "U/%s", sid_string);
2214 TALLOC_FREE(sid_string);
2215 if (centry == NULL) {
2216 return NT_STATUS_NOT_FOUND;
2220 * If we have an access denied cache entry and a cached info3
2221 * in the samlogon cache then do a query. This will force the
2222 * rpc back end to return the info3 data.
2225 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED) &&
2226 netsamlogon_cache_have(user_sid)) {
2227 DEBUG(10, ("query_user: cached access denied and have cached "
2229 domain->last_status = NT_STATUS_OK;
2230 centry_free(centry);
2231 return NT_STATUS_NOT_FOUND;
2234 /* if status is not ok then this is a negative hit
2235 and the rest of the data doesn't matter */
2236 status = centry->status;
2237 if (NT_STATUS_IS_OK(status)) {
2238 info->acct_name = centry_string(centry, mem_ctx);
2239 info->full_name = centry_string(centry, mem_ctx);
2240 info->homedir = centry_string(centry, mem_ctx);
2241 info->shell = centry_string(centry, mem_ctx);
2242 info->primary_gid = centry_uint32(centry);
2243 centry_sid(centry, &info->user_sid);
2244 centry_sid(centry, &info->group_sid);
2247 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2248 "%s\n", domain->name, nt_errstr(status) ));
2250 centry_free(centry);
2254 /* Lookup user information from a rid */
2255 static NTSTATUS query_user(struct winbindd_domain *domain,
2256 TALLOC_CTX *mem_ctx,
2257 const struct dom_sid *user_sid,
2258 struct wbint_userinfo *info)
2263 old_status = domain->online;
2264 status = wcache_query_user(domain, mem_ctx, user_sid, info);
2265 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2271 /* Return status value returned by seq number check */
2273 if (!NT_STATUS_IS_OK(domain->last_status))
2274 return domain->last_status;
2276 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2279 status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
2281 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2282 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2283 if (!domain->internal && old_status) {
2284 set_domain_offline(domain);
2286 if (!domain->internal &&
2289 NTSTATUS cache_status;
2290 cache_status = wcache_query_user(domain, mem_ctx, user_sid, info);
2291 return cache_status;
2295 refresh_sequence_number(domain, false);
2296 if (!NT_STATUS_IS_OK(status)) {
2299 wcache_save_user(domain, status, info);
2304 NTSTATUS wcache_lookup_usergroups(struct winbindd_domain *domain,
2305 TALLOC_CTX *mem_ctx,
2306 const struct dom_sid *user_sid,
2307 uint32_t *pnum_sids,
2308 struct dom_sid **psids)
2310 struct winbind_cache *cache = get_cache(domain);
2311 struct cache_entry *centry = NULL;
2313 uint32_t i, num_sids;
2314 struct dom_sid *sids;
2317 if (cache->tdb == NULL) {
2318 return NT_STATUS_NOT_FOUND;
2321 centry = wcache_fetch(cache, domain, "UG/%s",
2322 sid_to_fstring(sid_string, user_sid));
2323 if (centry == NULL) {
2324 return NT_STATUS_NOT_FOUND;
2327 /* If we have an access denied cache entry and a cached info3 in the
2328 samlogon cache then do a query. This will force the rpc back end
2329 to return the info3 data. */
2331 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)
2332 && netsamlogon_cache_have(user_sid)) {
2333 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2335 domain->last_status = NT_STATUS_OK;
2336 centry_free(centry);
2337 return NT_STATUS_NOT_FOUND;
2340 num_sids = centry_uint32(centry);
2341 sids = talloc_array(mem_ctx, struct dom_sid, num_sids);
2343 centry_free(centry);
2344 return NT_STATUS_NO_MEMORY;
2347 for (i=0; i<num_sids; i++) {
2348 centry_sid(centry, &sids[i]);
2351 status = centry->status;
2353 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2354 "status: %s\n", domain->name, nt_errstr(status)));
2356 centry_free(centry);
2358 *pnum_sids = num_sids;
2363 /* Lookup groups a user is a member of. */
2364 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
2365 TALLOC_CTX *mem_ctx,
2366 const struct dom_sid *user_sid,
2367 uint32 *num_groups, struct dom_sid **user_gids)
2369 struct cache_entry *centry = NULL;
2375 old_status = domain->online;
2376 status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2377 num_groups, user_gids);
2378 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2383 (*user_gids) = NULL;
2385 /* Return status value returned by seq number check */
2387 if (!NT_STATUS_IS_OK(domain->last_status))
2388 return domain->last_status;
2390 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2393 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
2395 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2396 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2397 if (!domain->internal && old_status) {
2398 set_domain_offline(domain);
2400 if (!domain->internal &&
2403 NTSTATUS cache_status;
2404 cache_status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2405 num_groups, user_gids);
2406 return cache_status;
2409 if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
2413 refresh_sequence_number(domain, false);
2414 if (!NT_STATUS_IS_OK(status)) {
2417 centry = centry_start(domain, status);
2421 centry_put_uint32(centry, *num_groups);
2422 for (i=0; i<(*num_groups); i++) {
2423 centry_put_sid(centry, &(*user_gids)[i]);
2426 centry_end(centry, "UG/%s", sid_to_fstring(sid_string, user_sid));
2427 centry_free(centry);
2433 static char *wcache_make_sidlist(TALLOC_CTX *mem_ctx, uint32_t num_sids,
2434 const struct dom_sid *sids)
2439 sidlist = talloc_strdup(mem_ctx, "");
2440 if (sidlist == NULL) {
2443 for (i=0; i<num_sids; i++) {
2445 sidlist = talloc_asprintf_append_buffer(
2446 sidlist, "/%s", sid_to_fstring(tmp, &sids[i]));
2447 if (sidlist == NULL) {
2454 NTSTATUS wcache_lookup_useraliases(struct winbindd_domain *domain,
2455 TALLOC_CTX *mem_ctx, uint32_t num_sids,
2456 const struct dom_sid *sids,
2457 uint32_t *pnum_aliases, uint32_t **paliases)
2459 struct winbind_cache *cache = get_cache(domain);
2460 struct cache_entry *centry = NULL;
2461 uint32_t num_aliases;
2467 if (cache->tdb == NULL) {
2468 return NT_STATUS_NOT_FOUND;
2471 if (num_sids == 0) {
2474 return NT_STATUS_OK;
2477 /* We need to cache indexed by the whole list of SIDs, the aliases
2478 * resulting might come from any of the SIDs. */
2480 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2481 if (sidlist == NULL) {
2482 return NT_STATUS_NO_MEMORY;
2485 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
2486 TALLOC_FREE(sidlist);
2487 if (centry == NULL) {
2488 return NT_STATUS_NOT_FOUND;
2491 num_aliases = centry_uint32(centry);
2492 aliases = talloc_array(mem_ctx, uint32_t, num_aliases);
2493 if (aliases == NULL) {
2494 centry_free(centry);
2495 return NT_STATUS_NO_MEMORY;
2498 for (i=0; i<num_aliases; i++) {
2499 aliases[i] = centry_uint32(centry);
2502 status = centry->status;
2504 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2505 "status %s\n", domain->name, nt_errstr(status)));
2507 centry_free(centry);
2509 *pnum_aliases = num_aliases;
2510 *paliases = aliases;
2515 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
2516 TALLOC_CTX *mem_ctx,
2517 uint32 num_sids, const struct dom_sid *sids,
2518 uint32 *num_aliases, uint32 **alias_rids)
2520 struct cache_entry *centry = NULL;
2526 old_status = domain->online;
2527 status = wcache_lookup_useraliases(domain, mem_ctx, num_sids, sids,
2528 num_aliases, alias_rids);
2529 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2534 (*alias_rids) = NULL;
2536 if (!NT_STATUS_IS_OK(domain->last_status))
2537 return domain->last_status;
2539 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2540 "for domain %s\n", domain->name ));
2542 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2543 if (sidlist == NULL) {
2544 return NT_STATUS_NO_MEMORY;
2547 status = domain->backend->lookup_useraliases(domain, mem_ctx,
2549 num_aliases, alias_rids);
2551 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2552 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2553 if (!domain->internal && old_status) {
2554 set_domain_offline(domain);
2556 if (!domain->internal &&
2559 NTSTATUS cache_status;
2560 cache_status = wcache_lookup_useraliases(domain, mem_ctx, num_sids,
2561 sids, num_aliases, alias_rids);
2562 return cache_status;
2566 refresh_sequence_number(domain, false);
2567 if (!NT_STATUS_IS_OK(status)) {
2570 centry = centry_start(domain, status);
2573 centry_put_uint32(centry, *num_aliases);
2574 for (i=0; i<(*num_aliases); i++)
2575 centry_put_uint32(centry, (*alias_rids)[i]);
2576 centry_end(centry, "UA%s", sidlist);
2577 centry_free(centry);
2583 NTSTATUS wcache_lookup_groupmem(struct winbindd_domain *domain,
2584 TALLOC_CTX *mem_ctx,
2585 const struct dom_sid *group_sid,
2586 uint32_t *num_names,
2587 struct dom_sid **sid_mem, char ***names,
2588 uint32_t **name_types)
2590 struct winbind_cache *cache = get_cache(domain);
2591 struct cache_entry *centry = NULL;
2596 if (cache->tdb == NULL) {
2597 return NT_STATUS_NOT_FOUND;
2600 sid_string = sid_string_tos(group_sid);
2601 if (sid_string == NULL) {
2602 return NT_STATUS_NO_MEMORY;
2605 centry = wcache_fetch(cache, domain, "GM/%s", sid_string);
2606 TALLOC_FREE(sid_string);
2607 if (centry == NULL) {
2608 return NT_STATUS_NOT_FOUND;
2615 *num_names = centry_uint32(centry);
2616 if (*num_names == 0) {
2617 centry_free(centry);
2618 return NT_STATUS_OK;
2621 *sid_mem = talloc_array(mem_ctx, struct dom_sid, *num_names);
2622 *names = talloc_array(mem_ctx, char *, *num_names);
2623 *name_types = talloc_array(mem_ctx, uint32, *num_names);
2625 if ((*sid_mem == NULL) || (*names == NULL) || (*name_types == NULL)) {
2626 TALLOC_FREE(*sid_mem);
2627 TALLOC_FREE(*names);
2628 TALLOC_FREE(*name_types);
2629 centry_free(centry);
2630 return NT_STATUS_NO_MEMORY;
2633 for (i=0; i<(*num_names); i++) {
2634 centry_sid(centry, &(*sid_mem)[i]);
2635 (*names)[i] = centry_string(centry, mem_ctx);
2636 (*name_types)[i] = centry_uint32(centry);
2639 status = centry->status;
2641 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2642 "status: %s\n", domain->name, nt_errstr(status)));
2644 centry_free(centry);
2648 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
2649 TALLOC_CTX *mem_ctx,
2650 const struct dom_sid *group_sid,
2651 enum lsa_SidType type,
2653 struct dom_sid **sid_mem, char ***names,
2654 uint32 **name_types)
2656 struct cache_entry *centry = NULL;
2662 old_status = domain->online;
2663 status = wcache_lookup_groupmem(domain, mem_ctx, group_sid, num_names,
2664 sid_mem, names, name_types);
2665 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2672 (*name_types) = NULL;
2674 /* Return status value returned by seq number check */
2676 if (!NT_STATUS_IS_OK(domain->last_status))
2677 return domain->last_status;
2679 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2682 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid,
2684 sid_mem, names, name_types);
2686 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2687 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2688 if (!domain->internal && old_status) {
2689 set_domain_offline(domain);
2691 if (!domain->internal &&
2694 NTSTATUS cache_status;
2695 cache_status = wcache_lookup_groupmem(domain, mem_ctx, group_sid,
2696 num_names, sid_mem, names,
2698 return cache_status;
2702 refresh_sequence_number(domain, false);
2703 if (!NT_STATUS_IS_OK(status)) {
2706 centry = centry_start(domain, status);
2709 centry_put_uint32(centry, *num_names);
2710 for (i=0; i<(*num_names); i++) {
2711 centry_put_sid(centry, &(*sid_mem)[i]);
2712 centry_put_string(centry, (*names)[i]);
2713 centry_put_uint32(centry, (*name_types)[i]);
2715 centry_end(centry, "GM/%s", sid_to_fstring(sid_string, group_sid));
2716 centry_free(centry);
2722 /* find the sequence number for a domain */
2723 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
2725 refresh_sequence_number(domain, false);
2727 *seq = domain->sequence_number;
2729 return NT_STATUS_OK;
2732 /* enumerate trusted domains
2733 * (we need to have the list of trustdoms in the cache when we go offline) -
2735 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
2736 TALLOC_CTX *mem_ctx,
2737 struct netr_DomainTrustList *trusts)
2740 struct winbind_cache *cache;
2741 struct winbindd_tdc_domain *dom_list = NULL;
2742 size_t num_domains = 0;
2743 bool retval = false;
2747 old_status = domain->online;
2749 trusts->array = NULL;
2751 cache = get_cache(domain);
2752 if (!cache || !cache->tdb) {
2756 if (domain->online) {
2760 retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2761 if (!retval || !num_domains || !dom_list) {
2762 TALLOC_FREE(dom_list);
2767 trusts->array = TALLOC_ZERO_ARRAY(mem_ctx, struct netr_DomainTrust, num_domains);
2768 if (!trusts->array) {
2769 TALLOC_FREE(dom_list);
2770 return NT_STATUS_NO_MEMORY;
2773 for (i = 0; i < num_domains; i++) {
2774 struct netr_DomainTrust *trust;
2775 struct dom_sid *sid;
2776 struct winbindd_domain *dom;
2778 dom = find_domain_from_name_noinit(dom_list[i].domain_name);
2779 if (dom && dom->internal) {
2783 trust = &trusts->array[trusts->count];
2784 trust->netbios_name = talloc_strdup(trusts->array, dom_list[i].domain_name);
2785 trust->dns_name = talloc_strdup(trusts->array, dom_list[i].dns_name);
2786 sid = talloc(trusts->array, struct dom_sid);
2787 if (!trust->netbios_name || !trust->dns_name ||
2789 TALLOC_FREE(dom_list);
2790 TALLOC_FREE(trusts->array);
2791 return NT_STATUS_NO_MEMORY;
2794 trust->trust_flags = dom_list[i].trust_flags;
2795 trust->trust_attributes = dom_list[i].trust_attribs;
2796 trust->trust_type = dom_list[i].trust_type;
2797 sid_copy(sid, &dom_list[i].sid);
2802 TALLOC_FREE(dom_list);
2803 return NT_STATUS_OK;
2806 /* Return status value returned by seq number check */
2808 if (!NT_STATUS_IS_OK(domain->last_status))
2809 return domain->last_status;
2811 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2814 status = domain->backend->trusted_domains(domain, mem_ctx, trusts);
2816 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2817 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2818 if (!domain->internal && old_status) {
2819 set_domain_offline(domain);
2821 if (!domain->internal &&
2824 retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2825 if (retval && num_domains && dom_list) {
2826 TALLOC_FREE(trusts->array);
2828 goto do_fetch_cache;
2832 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2833 * so that the generic centry handling still applies correctly -
2836 if (!NT_STATUS_IS_ERR(status)) {
2837 status = NT_STATUS_OK;
2842 /* get lockout policy */
2843 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
2844 TALLOC_CTX *mem_ctx,
2845 struct samr_DomInfo12 *policy)
2847 struct winbind_cache *cache = get_cache(domain);
2848 struct cache_entry *centry = NULL;
2852 old_status = domain->online;
2856 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2862 policy->lockout_duration = centry_nttime(centry);
2863 policy->lockout_window = centry_nttime(centry);
2864 policy->lockout_threshold = centry_uint16(centry);
2866 status = centry->status;
2868 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2869 domain->name, nt_errstr(status) ));
2871 centry_free(centry);
2875 ZERO_STRUCTP(policy);
2877 /* Return status value returned by seq number check */
2879 if (!NT_STATUS_IS_OK(domain->last_status))
2880 return domain->last_status;
2882 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2885 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2887 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2888 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2889 if (!domain->internal && old_status) {
2890 set_domain_offline(domain);
2893 !domain->internal &&
2896 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2898 goto do_fetch_cache;
2903 refresh_sequence_number(domain, false);
2904 if (!NT_STATUS_IS_OK(status)) {
2907 wcache_save_lockout_policy(domain, status, policy);
2912 /* get password policy */
2913 static NTSTATUS password_policy(struct winbindd_domain *domain,
2914 TALLOC_CTX *mem_ctx,
2915 struct samr_DomInfo1 *policy)
2917 struct winbind_cache *cache = get_cache(domain);
2918 struct cache_entry *centry = NULL;
2922 old_status = domain->online;
2926 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2932 policy->min_password_length = centry_uint16(centry);
2933 policy->password_history_length = centry_uint16(centry);
2934 policy->password_properties = centry_uint32(centry);
2935 policy->max_password_age = centry_nttime(centry);
2936 policy->min_password_age = centry_nttime(centry);
2938 status = centry->status;
2940 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2941 domain->name, nt_errstr(status) ));
2943 centry_free(centry);
2947 ZERO_STRUCTP(policy);
2949 /* Return status value returned by seq number check */
2951 if (!NT_STATUS_IS_OK(domain->last_status))
2952 return domain->last_status;
2954 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2957 status = domain->backend->password_policy(domain, mem_ctx, policy);
2959 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2960 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2961 if (!domain->internal && old_status) {
2962 set_domain_offline(domain);
2965 !domain->internal &&
2968 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2970 goto do_fetch_cache;
2975 refresh_sequence_number(domain, false);
2976 if (!NT_STATUS_IS_OK(status)) {
2979 wcache_save_password_policy(domain, status, policy);
2985 /* Invalidate cached user and group lists coherently */
2987 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2990 if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
2991 strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
2992 tdb_delete(the_tdb, kbuf);
2997 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2999 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
3000 struct netr_SamInfo3 *info3)
3003 fstring key_str, sid_string;
3004 struct winbind_cache *cache;
3006 /* dont clear cached U/SID and UG/SID entries when we want to logon
3009 if (lp_winbind_offline_logon()) {
3016 cache = get_cache(domain);
3022 sid_compose(&sid, info3->base.domain_sid, info3->base.rid);
3024 /* Clear U/SID cache entry */
3025 fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, &sid));
3026 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
3027 tdb_delete(cache->tdb, string_tdb_data(key_str));
3029 /* Clear UG/SID cache entry */
3030 fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, &sid));
3031 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
3032 tdb_delete(cache->tdb, string_tdb_data(key_str));
3034 /* Samba/winbindd never needs this. */
3035 netsamlogon_clear_cached_user(info3);
3038 bool wcache_invalidate_cache(void)
3040 struct winbindd_domain *domain;
3042 for (domain = domain_list(); domain; domain = domain->next) {
3043 struct winbind_cache *cache = get_cache(domain);
3045 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3046 "entries for %s\n", domain->name));
3049 tdb_traverse(cache->tdb, traverse_fn, NULL);
3058 bool wcache_invalidate_cache_noinit(void)
3060 struct winbindd_domain *domain;
3062 for (domain = domain_list(); domain; domain = domain->next) {
3063 struct winbind_cache *cache;
3065 /* Skip uninitialized domains. */
3066 if (!domain->initialized && !domain->internal) {
3070 cache = get_cache(domain);
3072 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3073 "entries for %s\n", domain->name));
3076 tdb_traverse(cache->tdb, traverse_fn, NULL);
3078 * Flushing cache has nothing to with domains.
3079 * return here if we successfully flushed once.
3080 * To avoid unnecessary traversing the cache.
3091 bool init_wcache(void)
3093 if (wcache == NULL) {
3094 wcache = SMB_XMALLOC_P(struct winbind_cache);
3095 ZERO_STRUCTP(wcache);
3098 if (wcache->tdb != NULL)
3101 /* when working offline we must not clear the cache on restart */
3102 wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
3103 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3104 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
3105 O_RDWR|O_CREAT, 0600);
3107 if (wcache->tdb == NULL) {
3108 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3115 /************************************************************************
3116 This is called by the parent to initialize the cache file.
3117 We don't need sophisticated locking here as we know we're the
3119 ************************************************************************/
3121 bool initialize_winbindd_cache(void)
3123 bool cache_bad = true;
3126 if (!init_wcache()) {
3127 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3131 /* Check version number. */
3132 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
3133 vers == WINBINDD_CACHE_VERSION) {
3138 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3139 "and re-creating with version number %d\n",
3140 WINBINDD_CACHE_VERSION ));
3142 tdb_close(wcache->tdb);
3145 if (unlink(cache_path("winbindd_cache.tdb")) == -1) {
3146 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3147 cache_path("winbindd_cache.tdb"),
3151 if (!init_wcache()) {
3152 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3153 "init_wcache failed.\n"));
3157 /* Write the version. */
3158 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
3159 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3160 tdb_errorstr(wcache->tdb) ));
3165 tdb_close(wcache->tdb);
3170 void close_winbindd_cache(void)
3176 tdb_close(wcache->tdb);
3181 bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
3182 char **domain_name, char **name,
3183 enum lsa_SidType *type)
3185 struct winbindd_domain *domain;
3188 domain = find_lookup_domain_from_sid(sid);
3189 if (domain == NULL) {
3192 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
3194 return NT_STATUS_IS_OK(status);
3197 bool lookup_cached_name(const char *domain_name,
3199 struct dom_sid *sid,
3200 enum lsa_SidType *type)
3202 struct winbindd_domain *domain;
3204 bool original_online_state;
3206 domain = find_lookup_domain_from_name(domain_name);
3207 if (domain == NULL) {
3211 /* If we are doing a cached logon, temporarily set the domain
3212 offline so the cache won't expire the entry */
3214 original_online_state = domain->online;
3215 domain->online = false;
3216 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
3217 domain->online = original_online_state;
3219 return NT_STATUS_IS_OK(status);
3222 void cache_name2sid(struct winbindd_domain *domain,
3223 const char *domain_name, const char *name,
3224 enum lsa_SidType type, const struct dom_sid *sid)
3226 refresh_sequence_number(domain, false);
3227 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
3232 * The original idea that this cache only contains centries has
3233 * been blurred - now other stuff gets put in here. Ensure we
3234 * ignore these things on cleanup.
3237 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
3238 TDB_DATA dbuf, void *state)
3240 struct cache_entry *centry;
3242 if (is_non_centry_key(kbuf)) {
3246 centry = wcache_fetch_raw((char *)kbuf.dptr);
3251 if (!NT_STATUS_IS_OK(centry->status)) {
3252 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
3253 tdb_delete(the_tdb, kbuf);
3256 centry_free(centry);
3260 /* flush the cache */
3261 void wcache_flush_cache(void)
3266 tdb_close(wcache->tdb);
3269 if (!winbindd_use_cache()) {
3273 /* when working offline we must not clear the cache on restart */
3274 wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
3275 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3276 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
3277 O_RDWR|O_CREAT, 0600);
3280 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3284 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
3286 DEBUG(10,("wcache_flush_cache success\n"));
3289 /* Count cached creds */
3291 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3294 int *cred_count = (int*)state;
3296 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3302 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
3304 struct winbind_cache *cache = get_cache(domain);
3309 return NT_STATUS_INTERNAL_DB_ERROR;
3312 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
3314 return NT_STATUS_OK;
3318 struct cred_list *prev, *next;
3323 static struct cred_list *wcache_cred_list;
3325 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3328 struct cred_list *cred;
3330 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3332 cred = SMB_MALLOC_P(struct cred_list);
3334 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3340 /* save a copy of the key */
3342 fstrcpy(cred->name, (const char *)kbuf.dptr);
3343 DLIST_ADD(wcache_cred_list, cred);
3349 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const struct dom_sid *sid)
3351 struct winbind_cache *cache = get_cache(domain);
3354 struct cred_list *cred, *oldest = NULL;
3357 return NT_STATUS_INTERNAL_DB_ERROR;
3360 /* we possibly already have an entry */
3361 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
3363 fstring key_str, tmp;
3365 DEBUG(11,("we already have an entry, deleting that\n"));
3367 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
3369 tdb_delete(cache->tdb, string_tdb_data(key_str));
3371 return NT_STATUS_OK;
3374 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
3376 return NT_STATUS_OK;
3377 } else if ((ret == -1) || (wcache_cred_list == NULL)) {
3378 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3381 ZERO_STRUCTP(oldest);
3383 for (cred = wcache_cred_list; cred; cred = cred->next) {
3388 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
3390 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3392 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
3396 t = IVAL(data.dptr, 0);
3397 SAFE_FREE(data.dptr);
3400 oldest = SMB_MALLOC_P(struct cred_list);
3401 if (oldest == NULL) {
3402 status = NT_STATUS_NO_MEMORY;
3406 fstrcpy(oldest->name, cred->name);
3407 oldest->created = t;
3411 if (t < oldest->created) {
3412 fstrcpy(oldest->name, cred->name);
3413 oldest->created = t;
3417 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
3418 status = NT_STATUS_OK;
3420 status = NT_STATUS_UNSUCCESSFUL;
3423 SAFE_FREE(wcache_cred_list);
3429 /* Change the global online/offline state. */
3430 bool set_global_winbindd_state_offline(void)
3434 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3436 /* Only go offline if someone has created
3437 the key "WINBINDD_OFFLINE" in the cache tdb. */
3439 if (wcache == NULL || wcache->tdb == NULL) {
3440 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3444 if (!lp_winbind_offline_logon()) {
3445 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3449 if (global_winbindd_offline_state) {
3450 /* Already offline. */
3454 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
3456 if (!data.dptr || data.dsize != 4) {
3457 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3458 SAFE_FREE(data.dptr);
3461 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3462 global_winbindd_offline_state = true;
3463 SAFE_FREE(data.dptr);
3468 void set_global_winbindd_state_online(void)
3470 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3472 if (!lp_winbind_offline_logon()) {
3473 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3477 if (!global_winbindd_offline_state) {
3478 /* Already online. */
3481 global_winbindd_offline_state = false;
3487 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3488 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
3491 bool get_global_winbindd_state_offline(void)
3493 return global_winbindd_offline_state;
3496 /***********************************************************************
3497 Validate functions for all possible cache tdb keys.
3498 ***********************************************************************/
3500 static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
3501 struct tdb_validation_status *state)
3503 struct cache_entry *centry;
3505 centry = SMB_XMALLOC_P(struct cache_entry);
3506 centry->data = (unsigned char *)memdup(data.dptr, data.dsize);
3507 if (!centry->data) {
3511 centry->len = data.dsize;
3514 if (centry->len < 8) {
3515 /* huh? corrupt cache? */
3516 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr));
3517 centry_free(centry);
3518 state->bad_entry = true;
3519 state->success = false;
3523 centry->status = NT_STATUS(centry_uint32(centry));
3524 centry->sequence_number = centry_uint32(centry);
3528 static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3529 struct tdb_validation_status *state)
3531 if (dbuf.dsize != 8) {
3532 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3533 keystr, (unsigned int)dbuf.dsize ));
3534 state->bad_entry = true;
3540 static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3541 struct tdb_validation_status *state)
3543 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3548 (void)centry_uint32(centry);
3549 if (NT_STATUS_IS_OK(centry->status)) {
3551 (void)centry_sid(centry, &sid);
3554 centry_free(centry);
3556 if (!(state->success)) {
3559 DEBUG(10,("validate_ns: %s ok\n", keystr));
3563 static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3564 struct tdb_validation_status *state)
3566 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3571 if (NT_STATUS_IS_OK(centry->status)) {
3572 (void)centry_uint32(centry);
3573 (void)centry_string(centry, mem_ctx);
3574 (void)centry_string(centry, mem_ctx);
3577 centry_free(centry);
3579 if (!(state->success)) {
3582 DEBUG(10,("validate_sn: %s ok\n", keystr));
3586 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3587 struct tdb_validation_status *state)
3589 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3596 (void)centry_string(centry, mem_ctx);
3597 (void)centry_string(centry, mem_ctx);
3598 (void)centry_string(centry, mem_ctx);
3599 (void)centry_string(centry, mem_ctx);
3600 (void)centry_uint32(centry);
3601 (void)centry_sid(centry, &sid);
3602 (void)centry_sid(centry, &sid);
3604 centry_free(centry);
3606 if (!(state->success)) {
3609 DEBUG(10,("validate_u: %s ok\n", keystr));
3613 static int validate_loc_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_nttime(centry);
3623 (void)centry_nttime(centry);
3624 (void)centry_uint16(centry);
3626 centry_free(centry);
3628 if (!(state->success)) {
3631 DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
3635 static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3636 struct tdb_validation_status *state)
3638 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3644 (void)centry_uint16(centry);
3645 (void)centry_uint16(centry);
3646 (void)centry_uint32(centry);
3647 (void)centry_nttime(centry);
3648 (void)centry_nttime(centry);
3650 centry_free(centry);
3652 if (!(state->success)) {
3655 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
3659 static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3660 struct tdb_validation_status *state)
3662 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3668 (void)centry_time(centry);
3669 (void)centry_hash16(centry, mem_ctx);
3671 /* We only have 17 bytes more data in the salted cred case. */
3672 if (centry->len - centry->ofs == 17) {
3673 (void)centry_hash16(centry, mem_ctx);
3676 centry_free(centry);
3678 if (!(state->success)) {
3681 DEBUG(10,("validate_cred: %s ok\n", keystr));
3685 static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3686 struct tdb_validation_status *state)
3688 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3689 int32 num_entries, i;
3695 num_entries = (int32)centry_uint32(centry);
3697 for (i=0; i< num_entries; i++) {
3699 (void)centry_string(centry, mem_ctx);
3700 (void)centry_string(centry, mem_ctx);
3701 (void)centry_string(centry, mem_ctx);
3702 (void)centry_string(centry, mem_ctx);
3703 (void)centry_sid(centry, &sid);
3704 (void)centry_sid(centry, &sid);
3707 centry_free(centry);
3709 if (!(state->success)) {
3712 DEBUG(10,("validate_ul: %s ok\n", keystr));
3716 static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3717 struct tdb_validation_status *state)
3719 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3720 int32 num_entries, i;
3726 num_entries = centry_uint32(centry);
3728 for (i=0; i< num_entries; i++) {
3729 (void)centry_string(centry, mem_ctx);
3730 (void)centry_string(centry, mem_ctx);
3731 (void)centry_uint32(centry);
3734 centry_free(centry);
3736 if (!(state->success)) {
3739 DEBUG(10,("validate_gl: %s ok\n", keystr));
3743 static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3744 struct tdb_validation_status *state)
3746 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3747 int32 num_groups, i;
3753 num_groups = centry_uint32(centry);
3755 for (i=0; i< num_groups; i++) {
3757 centry_sid(centry, &sid);
3760 centry_free(centry);
3762 if (!(state->success)) {
3765 DEBUG(10,("validate_ug: %s ok\n", keystr));
3769 static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3770 struct tdb_validation_status *state)
3772 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3773 int32 num_aliases, i;
3779 num_aliases = centry_uint32(centry);
3781 for (i=0; i < num_aliases; i++) {
3782 (void)centry_uint32(centry);
3785 centry_free(centry);
3787 if (!(state->success)) {
3790 DEBUG(10,("validate_ua: %s ok\n", keystr));
3794 static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3795 struct tdb_validation_status *state)
3797 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3804 num_names = centry_uint32(centry);
3806 for (i=0; i< num_names; i++) {
3808 centry_sid(centry, &sid);
3809 (void)centry_string(centry, mem_ctx);
3810 (void)centry_uint32(centry);
3813 centry_free(centry);
3815 if (!(state->success)) {
3818 DEBUG(10,("validate_gm: %s ok\n", keystr));
3822 static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3823 struct tdb_validation_status *state)
3825 /* Can't say anything about this other than must be nonzero. */
3826 if (dbuf.dsize == 0) {
3827 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3829 state->bad_entry = true;
3830 state->success = false;
3834 DEBUG(10,("validate_dr: %s ok\n", keystr));
3838 static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3839 struct tdb_validation_status *state)
3841 /* Can't say anything about this other than must be nonzero. */
3842 if (dbuf.dsize == 0) {
3843 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3845 state->bad_entry = true;
3846 state->success = false;
3850 DEBUG(10,("validate_de: %s ok\n", keystr));
3854 static int validate_pwinfo(TALLOC_CTX *mem_ctx, const char *keystr,
3855 TDB_DATA dbuf, struct tdb_validation_status *state)
3857 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3863 (void)centry_string(centry, mem_ctx);
3864 (void)centry_string(centry, mem_ctx);
3865 (void)centry_string(centry, mem_ctx);
3866 (void)centry_uint32(centry);
3868 centry_free(centry);
3870 if (!(state->success)) {
3873 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3877 static int validate_nss_an(TALLOC_CTX *mem_ctx, const char *keystr,
3879 struct tdb_validation_status *state)
3881 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3887 (void)centry_string( centry, mem_ctx );
3889 centry_free(centry);
3891 if (!(state->success)) {
3894 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3898 static int validate_nss_na(TALLOC_CTX *mem_ctx, const char *keystr,
3900 struct tdb_validation_status *state)
3902 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3908 (void)centry_string( centry, mem_ctx );
3910 centry_free(centry);
3912 if (!(state->success)) {
3915 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3919 static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
3921 struct tdb_validation_status *state)
3923 if (dbuf.dsize == 0) {
3924 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3925 "key %s (len ==0) ?\n", keystr));
3926 state->bad_entry = true;
3927 state->success = false;
3931 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
3932 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3936 static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3937 struct tdb_validation_status *state)
3939 if (dbuf.dsize != 4) {
3940 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3941 keystr, (unsigned int)dbuf.dsize ));
3942 state->bad_entry = true;
3943 state->success = false;
3946 DEBUG(10,("validate_offline: %s ok\n", keystr));
3950 static int validate_ndr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3951 struct tdb_validation_status *state)
3954 * Ignore validation for now. The proper way to do this is with a
3955 * checksum. Just pure parsing does not really catch much.
3960 static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3961 struct tdb_validation_status *state)
3963 if (dbuf.dsize != 4) {
3964 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3965 "key %s (len %u != 4) ?\n",
3966 keystr, (unsigned int)dbuf.dsize));
3967 state->bad_entry = true;
3968 state->success = false;
3972 DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
3976 /***********************************************************************
3977 A list of all possible cache tdb keys with associated validation
3979 ***********************************************************************/
3981 struct key_val_struct {
3982 const char *keyname;
3983 int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
3985 {"SEQNUM/", validate_seqnum},
3986 {"NS/", validate_ns},
3987 {"SN/", validate_sn},
3989 {"LOC_POL/", validate_loc_pol},
3990 {"PWD_POL/", validate_pwd_pol},
3991 {"CRED/", validate_cred},
3992 {"UL/", validate_ul},
3993 {"GL/", validate_gl},
3994 {"UG/", validate_ug},
3995 {"UA", validate_ua},
3996 {"GM/", validate_gm},
3997 {"DR/", validate_dr},
3998 {"DE/", validate_de},
3999 {"NSS/PWINFO/", validate_pwinfo},
4000 {"TRUSTDOMCACHE/", validate_trustdomcache},
4001 {"NSS/NA/", validate_nss_na},
4002 {"NSS/AN/", validate_nss_an},
4003 {"WINBINDD_OFFLINE", validate_offline},
4004 {"NDR/", validate_ndr},
4005 {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
4009 /***********************************************************************
4010 Function to look at every entry in the tdb and validate it as far as
4012 ***********************************************************************/
4014 static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
4017 unsigned int max_key_len = 1024;
4018 struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
4020 /* Paranoia check. */
4021 if (strncmp("UA/", (const char *)kbuf.dptr, 3) == 0) {
4022 max_key_len = 1024 * 1024;
4024 if (kbuf.dsize > max_key_len) {
4025 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4027 (unsigned int)kbuf.dsize, (unsigned int)max_key_len));
4031 for (i = 0; key_val[i].keyname; i++) {
4032 size_t namelen = strlen(key_val[i].keyname);
4033 if (kbuf.dsize >= namelen && (
4034 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
4035 TALLOC_CTX *mem_ctx;
4039 keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
4043 memcpy(keystr, kbuf.dptr, kbuf.dsize);
4044 keystr[kbuf.dsize] = '\0';
4046 mem_ctx = talloc_init("validate_ctx");
4052 ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
4056 talloc_destroy(mem_ctx);
4061 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4062 dump_data(0, (uint8 *)kbuf.dptr, kbuf.dsize);
4063 DEBUG(0,("data :\n"));
4064 dump_data(0, (uint8 *)dbuf.dptr, dbuf.dsize);
4065 v_state->unknown_key = true;
4066 v_state->success = false;
4067 return 1; /* terminate. */
4070 static void validate_panic(const char *const why)
4072 DEBUG(0,("validating cache: would panic %s\n", why ));
4073 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4077 /***********************************************************************
4078 Try and validate every entry in the winbindd cache. If we fail here,
4079 delete the cache tdb and return non-zero.
4080 ***********************************************************************/
4082 int winbindd_validate_cache(void)
4085 const char *tdb_path = cache_path("winbindd_cache.tdb");
4086 TDB_CONTEXT *tdb = NULL;
4088 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4089 smb_panic_fn = validate_panic;
4092 tdb = tdb_open_log(tdb_path,
4093 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
4094 ( lp_winbind_offline_logon()
4096 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
4100 DEBUG(0, ("winbindd_validate_cache: "
4101 "error opening/initializing tdb\n"));
4106 ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
4109 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4110 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
4115 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4116 smb_panic_fn = smb_panic;
4120 /***********************************************************************
4121 Try and validate every entry in the winbindd cache.
4122 ***********************************************************************/
4124 int winbindd_validate_cache_nobackup(void)
4127 const char *tdb_path = cache_path("winbindd_cache.tdb");
4129 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4130 smb_panic_fn = validate_panic;
4133 if (wcache == NULL || wcache->tdb == NULL) {
4134 ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
4136 ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
4140 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4144 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4146 smb_panic_fn = smb_panic;
4150 bool winbindd_cache_validate_and_initialize(void)
4152 close_winbindd_cache();
4154 if (lp_winbind_offline_logon()) {
4155 if (winbindd_validate_cache() < 0) {
4156 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4157 "could be restored.\n"));
4161 return initialize_winbindd_cache();
4164 /*********************************************************************
4165 ********************************************************************/
4167 static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
4168 struct winbindd_tdc_domain **domains,
4169 size_t *num_domains )
4171 struct winbindd_tdc_domain *list = NULL;
4174 bool set_only = false;
4176 /* don't allow duplicates */
4181 for ( i=0; i< (*num_domains); i++ ) {
4182 if ( strequal( new_dom->name, list[i].domain_name ) ) {
4183 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4194 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, 1 );
4197 list = TALLOC_REALLOC_ARRAY( *domains, *domains,
4198 struct winbindd_tdc_domain,
4203 ZERO_STRUCT( list[idx] );
4209 list[idx].domain_name = talloc_strdup( list, new_dom->name );
4210 list[idx].dns_name = talloc_strdup( list, new_dom->alt_name );
4212 if ( !is_null_sid( &new_dom->sid ) ) {
4213 sid_copy( &list[idx].sid, &new_dom->sid );
4215 sid_copy(&list[idx].sid, &global_sid_NULL);
4218 if ( new_dom->domain_flags != 0x0 )
4219 list[idx].trust_flags = new_dom->domain_flags;
4221 if ( new_dom->domain_type != 0x0 )
4222 list[idx].trust_type = new_dom->domain_type;
4224 if ( new_dom->domain_trust_attribs != 0x0 )
4225 list[idx].trust_attribs = new_dom->domain_trust_attribs;
4229 *num_domains = idx + 1;
4235 /*********************************************************************
4236 ********************************************************************/
4238 static TDB_DATA make_tdc_key( const char *domain_name )
4240 char *keystr = NULL;
4241 TDB_DATA key = { NULL, 0 };
4243 if ( !domain_name ) {
4244 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4248 if (asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name ) == -1) {
4251 key = string_term_tdb_data(keystr);
4256 /*********************************************************************
4257 ********************************************************************/
4259 static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
4261 unsigned char **buf )
4263 unsigned char *buffer = NULL;
4268 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4276 /* Store the number of array items first */
4277 len += tdb_pack( buffer+len, buflen-len, "d",
4280 /* now pack each domain trust record */
4281 for ( i=0; i<num_domains; i++ ) {
4286 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4287 domains[i].domain_name,
4288 domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
4291 len += tdb_pack( buffer+len, buflen-len, "fffddd",
4292 domains[i].domain_name,
4293 domains[i].dns_name,
4294 sid_to_fstring(tmp, &domains[i].sid),
4295 domains[i].trust_flags,
4296 domains[i].trust_attribs,
4297 domains[i].trust_type );
4300 if ( buflen < len ) {
4302 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
4303 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4317 /*********************************************************************
4318 ********************************************************************/
4320 static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
4321 struct winbindd_tdc_domain **domains )
4323 fstring domain_name, dns_name, sid_string;
4324 uint32 type, attribs, flags;
4328 struct winbindd_tdc_domain *list = NULL;
4330 /* get the number of domains */
4331 len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
4333 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4337 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, num_domains );
4339 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4343 for ( i=0; i<num_domains; i++ ) {
4344 len += tdb_unpack( buf+len, buflen-len, "fffddd",
4353 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4354 TALLOC_FREE( list );
4358 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4359 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4360 domain_name, dns_name, sid_string,
4361 flags, attribs, type));
4363 list[i].domain_name = talloc_strdup( list, domain_name );
4364 list[i].dns_name = talloc_strdup( list, dns_name );
4365 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
4366 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4369 list[i].trust_flags = flags;
4370 list[i].trust_attribs = attribs;
4371 list[i].trust_type = type;
4379 /*********************************************************************
4380 ********************************************************************/
4382 static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
4384 TDB_DATA key = make_tdc_key( lp_workgroup() );
4385 TDB_DATA data = { NULL, 0 };
4391 /* See if we were asked to delete the cache entry */
4394 ret = tdb_delete( wcache->tdb, key );
4398 data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
4405 ret = tdb_store( wcache->tdb, key, data, 0 );
4408 SAFE_FREE( data.dptr );
4409 SAFE_FREE( key.dptr );
4411 return ( ret != -1 );
4414 /*********************************************************************
4415 ********************************************************************/
4417 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
4419 TDB_DATA key = make_tdc_key( lp_workgroup() );
4420 TDB_DATA data = { NULL, 0 };
4428 data = tdb_fetch( wcache->tdb, key );
4430 SAFE_FREE( key.dptr );
4435 *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
4437 SAFE_FREE( data.dptr );
4445 /*********************************************************************
4446 ********************************************************************/
4448 bool wcache_tdc_add_domain( struct winbindd_domain *domain )
4450 struct winbindd_tdc_domain *dom_list = NULL;
4451 size_t num_domains = 0;
4454 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4455 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4456 domain->name, domain->alt_name,
4457 sid_string_dbg(&domain->sid),
4458 domain->domain_flags,
4459 domain->domain_trust_attribs,
4460 domain->domain_type));
4462 if ( !init_wcache() ) {
4466 /* fetch the list */
4468 wcache_tdc_fetch_list( &dom_list, &num_domains );
4470 /* add the new domain */
4472 if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
4476 /* pack the domain */
4478 if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
4486 TALLOC_FREE( dom_list );
4491 /*********************************************************************
4492 ********************************************************************/
4494 struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
4496 struct winbindd_tdc_domain *dom_list = NULL;
4497 size_t num_domains = 0;
4499 struct winbindd_tdc_domain *d = NULL;
4501 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
4503 if ( !init_wcache() ) {
4507 /* fetch the list */
4509 wcache_tdc_fetch_list( &dom_list, &num_domains );
4511 for ( i=0; i<num_domains; i++ ) {
4512 if ( strequal(name, dom_list[i].domain_name) ||
4513 strequal(name, dom_list[i].dns_name) )
4515 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4518 d = TALLOC_P( ctx, struct winbindd_tdc_domain );
4522 d->domain_name = talloc_strdup( d, dom_list[i].domain_name );
4523 d->dns_name = talloc_strdup( d, dom_list[i].dns_name );
4524 sid_copy( &d->sid, &dom_list[i].sid );
4525 d->trust_flags = dom_list[i].trust_flags;
4526 d->trust_type = dom_list[i].trust_type;
4527 d->trust_attribs = dom_list[i].trust_attribs;
4533 TALLOC_FREE( dom_list );
4539 /*********************************************************************
4540 ********************************************************************/
4542 void wcache_tdc_clear( void )
4544 if ( !init_wcache() )
4547 wcache_tdc_store_list( NULL, 0 );
4553 /*********************************************************************
4554 ********************************************************************/
4556 static void wcache_save_user_pwinfo(struct winbindd_domain *domain,
4558 const struct dom_sid *user_sid,
4559 const char *homedir,
4564 struct cache_entry *centry;
4567 if ( (centry = centry_start(domain, status)) == NULL )
4570 centry_put_string( centry, homedir );
4571 centry_put_string( centry, shell );
4572 centry_put_string( centry, gecos );
4573 centry_put_uint32( centry, gid );
4575 centry_end(centry, "NSS/PWINFO/%s", sid_to_fstring(tmp, user_sid) );
4577 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid) ));
4579 centry_free(centry);
4582 NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
4583 const struct dom_sid *user_sid,
4585 ADS_STRUCT *ads, LDAPMessage *msg,
4586 const char **homedir, const char **shell,
4587 const char **gecos, gid_t *p_gid)
4589 struct winbind_cache *cache = get_cache(domain);
4590 struct cache_entry *centry = NULL;
4597 centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s",
4598 sid_to_fstring(tmp, user_sid));
4603 *homedir = centry_string( centry, ctx );
4604 *shell = centry_string( centry, ctx );
4605 *gecos = centry_string( centry, ctx );
4606 *p_gid = centry_uint32( centry );
4608 centry_free(centry);
4610 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4611 sid_string_dbg(user_sid)));
4613 return NT_STATUS_OK;
4617 nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg,
4618 homedir, shell, gecos, p_gid );
4620 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status)));
4622 if ( NT_STATUS_IS_OK(nt_status) ) {
4623 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir));
4624 DEBUGADD(10, ("\tshell = '%s'\n", *shell));
4625 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos));
4626 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid));
4628 wcache_save_user_pwinfo( domain, nt_status, user_sid,
4629 *homedir, *shell, *gecos, *p_gid );
4632 if ( NT_STATUS_EQUAL( nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
4633 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4635 set_domain_offline( domain );
4642 /* the cache backend methods are exposed via this structure */
4643 struct winbindd_methods cache_methods = {
4661 static bool wcache_ndr_key(TALLOC_CTX *mem_ctx, char *domain_name,
4662 uint32_t opnum, const DATA_BLOB *req,
4668 key = talloc_asprintf(mem_ctx, "NDR/%s/%d/", domain_name, (int)opnum);
4672 keylen = talloc_get_size(key) - 1;
4674 key = talloc_realloc(mem_ctx, key, char, keylen + req->length);
4678 memcpy(key + keylen, req->data, req->length);
4680 pkey->dptr = (uint8_t *)key;
4681 pkey->dsize = talloc_get_size(key);
4685 static bool wcache_opnum_cacheable(uint32_t opnum)
4688 case NDR_WBINT_PING:
4689 case NDR_WBINT_QUERYSEQUENCENUMBER:
4690 case NDR_WBINT_ALLOCATEUID:
4691 case NDR_WBINT_ALLOCATEGID:
4692 case NDR_WBINT_CHECKMACHINEACCOUNT:
4693 case NDR_WBINT_CHANGEMACHINEACCOUNT:
4694 case NDR_WBINT_PINGDC:
4700 bool wcache_fetch_ndr(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
4701 uint32_t opnum, const DATA_BLOB *req, DATA_BLOB *resp)
4706 if (!wcache_opnum_cacheable(opnum) ||
4707 is_my_own_sam_domain(domain) ||
4708 is_builtin_domain(domain)) {
4712 if (wcache->tdb == NULL) {
4716 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4719 data = tdb_fetch(wcache->tdb, key);
4720 TALLOC_FREE(key.dptr);
4722 if (data.dptr == NULL) {
4725 if (data.dsize < 4) {
4729 if (!is_domain_offline(domain)) {
4730 uint32_t entry_seqnum, dom_seqnum, last_check;
4732 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum,
4736 entry_seqnum = IVAL(data.dptr, 0);
4737 if (entry_seqnum != dom_seqnum) {
4738 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4739 (int)entry_seqnum));
4744 resp->data = (uint8_t *)talloc_memdup(mem_ctx, data.dptr + 4,
4746 if (resp->data == NULL) {
4747 DEBUG(10, ("talloc failed\n"));
4750 resp->length = data.dsize - 4;
4754 SAFE_FREE(data.dptr);
4758 void wcache_store_ndr(struct winbindd_domain *domain, uint32_t opnum,
4759 const DATA_BLOB *req, const DATA_BLOB *resp)
4762 uint32_t dom_seqnum, last_check;
4764 if (!wcache_opnum_cacheable(opnum) ||
4765 is_my_own_sam_domain(domain) ||
4766 is_builtin_domain(domain)) {
4770 if (wcache->tdb == NULL) {
4774 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum, &last_check)) {
4775 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4780 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4784 data.dsize = resp->length + 4;
4785 data.dptr = talloc_array(key.dptr, uint8_t, data.dsize);
4786 if (data.dptr == NULL) {
4790 SIVAL(data.dptr, 0, dom_seqnum);
4791 memcpy(data.dptr+4, resp->data, resp->length);
4793 tdb_store(wcache->tdb, key, data, 0);
4796 TALLOC_FREE(key.dptr);