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 const struct dom_sid *sid,
1363 const uint8 nt_pass[NT_HASH_LEN])
1365 struct cache_entry *centry;
1368 uint8 cred_salt[NT_HASH_LEN];
1369 uint8 salted_hash[NT_HASH_LEN];
1371 if (is_null_sid(sid)) {
1372 return NT_STATUS_INVALID_SID;
1375 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1376 return NT_STATUS_INVALID_SID;
1379 centry = centry_start(domain, NT_STATUS_OK);
1381 return NT_STATUS_INTERNAL_DB_ERROR;
1384 dump_data_pw("nt_pass", nt_pass, NT_HASH_LEN);
1386 centry_put_time(centry, time(NULL));
1388 /* Create a salt and then salt the hash. */
1389 generate_random_buffer(cred_salt, NT_HASH_LEN);
1390 E_md5hash(cred_salt, nt_pass, salted_hash);
1392 centry_put_hash16(centry, salted_hash);
1393 centry_put_hash16(centry, cred_salt);
1394 centry_end(centry, "CRED/%s", sid_to_fstring(sid_string, sid));
1396 DEBUG(10,("wcache_save_creds: %s\n", sid_string));
1398 centry_free(centry);
1400 return NT_STATUS_OK;
1404 /* Query display info. This is the basic user list fn */
1405 static NTSTATUS query_user_list(struct winbindd_domain *domain,
1406 TALLOC_CTX *mem_ctx,
1407 uint32 *num_entries,
1408 struct wbint_userinfo **info)
1410 struct winbind_cache *cache = get_cache(domain);
1411 struct cache_entry *centry = NULL;
1413 unsigned int i, retry;
1414 bool old_status = domain->online;
1419 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1424 *num_entries = centry_uint32(centry);
1426 if (*num_entries == 0)
1429 (*info) = TALLOC_ARRAY(mem_ctx, struct wbint_userinfo, *num_entries);
1431 smb_panic_fn("query_user_list out of memory");
1433 for (i=0; i<(*num_entries); i++) {
1434 (*info)[i].acct_name = centry_string(centry, mem_ctx);
1435 (*info)[i].full_name = centry_string(centry, mem_ctx);
1436 (*info)[i].homedir = centry_string(centry, mem_ctx);
1437 (*info)[i].shell = centry_string(centry, mem_ctx);
1438 centry_sid(centry, &(*info)[i].user_sid);
1439 centry_sid(centry, &(*info)[i].group_sid);
1443 status = centry->status;
1445 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1446 domain->name, nt_errstr(status) ));
1448 centry_free(centry);
1455 /* Return status value returned by seq number check */
1457 if (!NT_STATUS_IS_OK(domain->last_status))
1458 return domain->last_status;
1460 /* Put the query_user_list() in a retry loop. There appears to be
1461 * some bug either with Windows 2000 or Samba's handling of large
1462 * rpc replies. This manifests itself as sudden disconnection
1463 * at a random point in the enumeration of a large (60k) user list.
1464 * The retry loop simply tries the operation again. )-: It's not
1465 * pretty but an acceptable workaround until we work out what the
1466 * real problem is. */
1471 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1474 status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
1475 if (!NT_STATUS_IS_OK(status)) {
1476 DEBUG(3, ("query_user_list: returned 0x%08x, "
1477 "retrying\n", NT_STATUS_V(status)));
1479 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1480 DEBUG(3, ("query_user_list: flushing "
1481 "connection cache\n"));
1482 invalidate_cm_connection(&domain->conn);
1484 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1485 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1486 if (!domain->internal && old_status) {
1487 set_domain_offline(domain);
1489 /* store partial response. */
1490 if (*num_entries > 0) {
1492 * humm, what about the status used for cache?
1493 * Should it be NT_STATUS_OK?
1498 * domain is offline now, and there is no user entries,
1499 * try to fetch from cache again.
1501 if (cache->tdb && !domain->online && !domain->internal && old_status) {
1502 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1503 /* partial response... */
1507 goto do_fetch_cache;
1514 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
1518 refresh_sequence_number(domain, false);
1519 if (!NT_STATUS_IS_OK(status)) {
1522 centry = centry_start(domain, status);
1525 centry_put_uint32(centry, *num_entries);
1526 for (i=0; i<(*num_entries); i++) {
1527 centry_put_string(centry, (*info)[i].acct_name);
1528 centry_put_string(centry, (*info)[i].full_name);
1529 centry_put_string(centry, (*info)[i].homedir);
1530 centry_put_string(centry, (*info)[i].shell);
1531 centry_put_sid(centry, &(*info)[i].user_sid);
1532 centry_put_sid(centry, &(*info)[i].group_sid);
1533 if (domain->backend && domain->backend->consistent) {
1534 /* when the backend is consistent we can pre-prime some mappings */
1535 wcache_save_name_to_sid(domain, NT_STATUS_OK,
1537 (*info)[i].acct_name,
1538 &(*info)[i].user_sid,
1540 wcache_save_sid_to_name(domain, NT_STATUS_OK,
1541 &(*info)[i].user_sid,
1543 (*info)[i].acct_name,
1545 wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
1548 centry_end(centry, "UL/%s", domain->name);
1549 centry_free(centry);
1555 /* list all domain groups */
1556 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
1557 TALLOC_CTX *mem_ctx,
1558 uint32 *num_entries,
1559 struct acct_info **info)
1561 struct winbind_cache *cache = get_cache(domain);
1562 struct cache_entry *centry = NULL;
1567 old_status = domain->online;
1571 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1576 *num_entries = centry_uint32(centry);
1578 if (*num_entries == 0)
1581 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1583 smb_panic_fn("enum_dom_groups out of memory");
1585 for (i=0; i<(*num_entries); i++) {
1586 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1587 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1588 (*info)[i].rid = centry_uint32(centry);
1592 status = centry->status;
1594 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1595 domain->name, nt_errstr(status) ));
1597 centry_free(centry);
1604 /* Return status value returned by seq number check */
1606 if (!NT_STATUS_IS_OK(domain->last_status))
1607 return domain->last_status;
1609 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1612 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1614 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1615 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1616 if (!domain->internal && old_status) {
1617 set_domain_offline(domain);
1621 !domain->internal &&
1623 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1625 goto do_fetch_cache;
1630 refresh_sequence_number(domain, false);
1631 if (!NT_STATUS_IS_OK(status)) {
1634 centry = centry_start(domain, status);
1637 centry_put_uint32(centry, *num_entries);
1638 for (i=0; i<(*num_entries); i++) {
1639 centry_put_string(centry, (*info)[i].acct_name);
1640 centry_put_string(centry, (*info)[i].acct_desc);
1641 centry_put_uint32(centry, (*info)[i].rid);
1643 centry_end(centry, "GL/%s/domain", domain->name);
1644 centry_free(centry);
1650 /* list all domain groups */
1651 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
1652 TALLOC_CTX *mem_ctx,
1653 uint32 *num_entries,
1654 struct acct_info **info)
1656 struct winbind_cache *cache = get_cache(domain);
1657 struct cache_entry *centry = NULL;
1662 old_status = domain->online;
1666 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1671 *num_entries = centry_uint32(centry);
1673 if (*num_entries == 0)
1676 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1678 smb_panic_fn("enum_dom_groups out of memory");
1680 for (i=0; i<(*num_entries); i++) {
1681 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1682 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1683 (*info)[i].rid = centry_uint32(centry);
1688 /* If we are returning cached data and the domain controller
1689 is down then we don't know whether the data is up to date
1690 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1693 if (wcache_server_down(domain)) {
1694 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1695 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1697 status = centry->status;
1699 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1700 domain->name, nt_errstr(status) ));
1702 centry_free(centry);
1709 /* Return status value returned by seq number check */
1711 if (!NT_STATUS_IS_OK(domain->last_status))
1712 return domain->last_status;
1714 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1717 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1719 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1720 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1721 if (!domain->internal && old_status) {
1722 set_domain_offline(domain);
1725 !domain->internal &&
1728 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1730 goto do_fetch_cache;
1735 refresh_sequence_number(domain, false);
1736 if (!NT_STATUS_IS_OK(status)) {
1739 centry = centry_start(domain, status);
1742 centry_put_uint32(centry, *num_entries);
1743 for (i=0; i<(*num_entries); i++) {
1744 centry_put_string(centry, (*info)[i].acct_name);
1745 centry_put_string(centry, (*info)[i].acct_desc);
1746 centry_put_uint32(centry, (*info)[i].rid);
1748 centry_end(centry, "GL/%s/local", domain->name);
1749 centry_free(centry);
1755 NTSTATUS wcache_name_to_sid(struct winbindd_domain *domain,
1756 const char *domain_name,
1758 struct dom_sid *sid,
1759 enum lsa_SidType *type)
1761 struct winbind_cache *cache = get_cache(domain);
1762 struct cache_entry *centry;
1766 if (cache->tdb == NULL) {
1767 return NT_STATUS_NOT_FOUND;
1770 uname = talloc_strdup_upper(talloc_tos(), name);
1771 if (uname == NULL) {
1772 return NT_STATUS_NO_MEMORY;
1775 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1777 if (centry == NULL) {
1778 return NT_STATUS_NOT_FOUND;
1781 status = centry->status;
1782 if (NT_STATUS_IS_OK(status)) {
1783 *type = (enum lsa_SidType)centry_uint32(centry);
1784 centry_sid(centry, sid);
1787 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1788 "%s\n", domain->name, nt_errstr(status) ));
1790 centry_free(centry);
1794 /* convert a single name to a sid in a domain */
1795 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
1796 TALLOC_CTX *mem_ctx,
1797 const char *domain_name,
1800 struct dom_sid *sid,
1801 enum lsa_SidType *type)
1806 old_status = domain->online;
1808 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1809 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1815 /* If the seq number check indicated that there is a problem
1816 * with this DC, then return that status... except for
1817 * access_denied. This is special because the dc may be in
1818 * "restrict anonymous = 1" mode, in which case it will deny
1819 * most unauthenticated operations, but *will* allow the LSA
1820 * name-to-sid that we try as a fallback. */
1822 if (!(NT_STATUS_IS_OK(domain->last_status)
1823 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1824 return domain->last_status;
1826 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1829 status = domain->backend->name_to_sid(domain, mem_ctx, domain_name,
1830 name, flags, sid, type);
1832 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1833 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1834 if (!domain->internal && old_status) {
1835 set_domain_offline(domain);
1837 if (!domain->internal &&
1840 NTSTATUS cache_status;
1841 cache_status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1842 return cache_status;
1846 refresh_sequence_number(domain, false);
1848 if (domain->online &&
1849 (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
1850 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1852 /* Only save the reverse mapping if this was not a UPN */
1853 if (!strchr(name, '@')) {
1854 strupper_m(CONST_DISCARD(char *,domain_name));
1855 strlower_m(CONST_DISCARD(char *,name));
1856 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1863 NTSTATUS wcache_sid_to_name(struct winbindd_domain *domain,
1864 const struct dom_sid *sid,
1865 TALLOC_CTX *mem_ctx,
1868 enum lsa_SidType *type)
1870 struct winbind_cache *cache = get_cache(domain);
1871 struct cache_entry *centry;
1875 if (cache->tdb == NULL) {
1876 return NT_STATUS_NOT_FOUND;
1879 sid_string = sid_string_tos(sid);
1880 if (sid_string == NULL) {
1881 return NT_STATUS_NO_MEMORY;
1884 centry = wcache_fetch(cache, domain, "SN/%s", sid_string);
1885 TALLOC_FREE(sid_string);
1886 if (centry == NULL) {
1887 return NT_STATUS_NOT_FOUND;
1890 if (NT_STATUS_IS_OK(centry->status)) {
1891 *type = (enum lsa_SidType)centry_uint32(centry);
1892 *domain_name = centry_string(centry, mem_ctx);
1893 *name = centry_string(centry, mem_ctx);
1896 status = centry->status;
1897 centry_free(centry);
1899 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1900 "%s\n", domain->name, nt_errstr(status) ));
1905 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1907 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
1908 TALLOC_CTX *mem_ctx,
1909 const struct dom_sid *sid,
1912 enum lsa_SidType *type)
1917 old_status = domain->online;
1918 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
1920 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1925 *domain_name = NULL;
1927 /* If the seq number check indicated that there is a problem
1928 * with this DC, then return that status... except for
1929 * access_denied. This is special because the dc may be in
1930 * "restrict anonymous = 1" mode, in which case it will deny
1931 * most unauthenticated operations, but *will* allow the LSA
1932 * sid-to-name that we try as a fallback. */
1934 if (!(NT_STATUS_IS_OK(domain->last_status)
1935 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1936 return domain->last_status;
1938 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1941 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1943 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1944 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1945 if (!domain->internal && old_status) {
1946 set_domain_offline(domain);
1948 if (!domain->internal &&
1951 NTSTATUS cache_status;
1952 cache_status = wcache_sid_to_name(domain, sid, mem_ctx,
1953 domain_name, name, type);
1954 return cache_status;
1958 refresh_sequence_number(domain, false);
1959 if (!NT_STATUS_IS_OK(status)) {
1962 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1964 /* We can't save the name to sid mapping here, as with sid history a
1965 * later name2sid would give the wrong sid. */
1970 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
1971 TALLOC_CTX *mem_ctx,
1972 const struct dom_sid *domain_sid,
1977 enum lsa_SidType **types)
1979 struct winbind_cache *cache = get_cache(domain);
1981 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1986 old_status = domain->online;
1987 *domain_name = NULL;
1995 if (num_rids == 0) {
1996 return NT_STATUS_OK;
1999 *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
2000 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
2002 if ((*names == NULL) || (*types == NULL)) {
2003 result = NT_STATUS_NO_MEMORY;
2007 have_mapped = have_unmapped = false;
2009 for (i=0; i<num_rids; i++) {
2011 struct cache_entry *centry;
2014 if (!sid_compose(&sid, domain_sid, rids[i])) {
2015 result = NT_STATUS_INTERNAL_ERROR;
2019 centry = wcache_fetch(cache, domain, "SN/%s",
2020 sid_to_fstring(tmp, &sid));
2025 (*types)[i] = SID_NAME_UNKNOWN;
2026 (*names)[i] = talloc_strdup(*names, "");
2028 if (NT_STATUS_IS_OK(centry->status)) {
2031 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
2033 dom = centry_string(centry, mem_ctx);
2034 if (*domain_name == NULL) {
2040 (*names)[i] = centry_string(centry, *names);
2042 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
2043 have_unmapped = true;
2046 /* something's definitely wrong */
2047 result = centry->status;
2051 centry_free(centry);
2055 return NT_STATUS_NONE_MAPPED;
2057 if (!have_unmapped) {
2058 return NT_STATUS_OK;
2060 return STATUS_SOME_UNMAPPED;
2064 TALLOC_FREE(*names);
2065 TALLOC_FREE(*types);
2067 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
2068 rids, num_rids, domain_name,
2071 if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
2072 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2073 if (!domain->internal && old_status) {
2074 set_domain_offline(domain);
2077 !domain->internal &&
2080 have_mapped = have_unmapped = false;
2082 for (i=0; i<num_rids; i++) {
2084 struct cache_entry *centry;
2087 if (!sid_compose(&sid, domain_sid, rids[i])) {
2088 result = NT_STATUS_INTERNAL_ERROR;
2092 centry = wcache_fetch(cache, domain, "SN/%s",
2093 sid_to_fstring(tmp, &sid));
2095 (*types)[i] = SID_NAME_UNKNOWN;
2096 (*names)[i] = talloc_strdup(*names, "");
2100 (*types)[i] = SID_NAME_UNKNOWN;
2101 (*names)[i] = talloc_strdup(*names, "");
2103 if (NT_STATUS_IS_OK(centry->status)) {
2106 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
2108 dom = centry_string(centry, mem_ctx);
2109 if (*domain_name == NULL) {
2115 (*names)[i] = centry_string(centry, *names);
2117 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
2118 have_unmapped = true;
2121 /* something's definitely wrong */
2122 result = centry->status;
2126 centry_free(centry);
2130 return NT_STATUS_NONE_MAPPED;
2132 if (!have_unmapped) {
2133 return NT_STATUS_OK;
2135 return STATUS_SOME_UNMAPPED;
2139 None of the queried rids has been found so save all negative entries
2141 if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
2142 for (i = 0; i < num_rids; i++) {
2144 const char *name = "";
2145 const enum lsa_SidType type = SID_NAME_UNKNOWN;
2146 NTSTATUS status = NT_STATUS_NONE_MAPPED;
2148 if (!sid_compose(&sid, domain_sid, rids[i])) {
2149 return NT_STATUS_INTERNAL_ERROR;
2152 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2160 Some or all of the queried rids have been found.
2162 if (!NT_STATUS_IS_OK(result) &&
2163 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
2167 refresh_sequence_number(domain, false);
2169 for (i=0; i<num_rids; i++) {
2173 if (!sid_compose(&sid, domain_sid, rids[i])) {
2174 result = NT_STATUS_INTERNAL_ERROR;
2178 status = (*types)[i] == SID_NAME_UNKNOWN ?
2179 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
2181 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2182 (*names)[i], (*types)[i]);
2188 TALLOC_FREE(*names);
2189 TALLOC_FREE(*types);
2193 NTSTATUS wcache_query_user(struct winbindd_domain *domain,
2194 TALLOC_CTX *mem_ctx,
2195 const struct dom_sid *user_sid,
2196 struct wbint_userinfo *info)
2198 struct winbind_cache *cache = get_cache(domain);
2199 struct cache_entry *centry = NULL;
2203 if (cache->tdb == NULL) {
2204 return NT_STATUS_NOT_FOUND;
2207 sid_string = sid_string_tos(user_sid);
2208 if (sid_string == NULL) {
2209 return NT_STATUS_NO_MEMORY;
2212 centry = wcache_fetch(cache, domain, "U/%s", sid_string);
2213 TALLOC_FREE(sid_string);
2214 if (centry == NULL) {
2215 return NT_STATUS_NOT_FOUND;
2219 * If we have an access denied cache entry and a cached info3
2220 * in the samlogon cache then do a query. This will force the
2221 * rpc back end to return the info3 data.
2224 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED) &&
2225 netsamlogon_cache_have(user_sid)) {
2226 DEBUG(10, ("query_user: cached access denied and have cached "
2228 domain->last_status = NT_STATUS_OK;
2229 centry_free(centry);
2230 return NT_STATUS_NOT_FOUND;
2233 /* if status is not ok then this is a negative hit
2234 and the rest of the data doesn't matter */
2235 status = centry->status;
2236 if (NT_STATUS_IS_OK(status)) {
2237 info->acct_name = centry_string(centry, mem_ctx);
2238 info->full_name = centry_string(centry, mem_ctx);
2239 info->homedir = centry_string(centry, mem_ctx);
2240 info->shell = centry_string(centry, mem_ctx);
2241 info->primary_gid = centry_uint32(centry);
2242 centry_sid(centry, &info->user_sid);
2243 centry_sid(centry, &info->group_sid);
2246 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2247 "%s\n", domain->name, nt_errstr(status) ));
2249 centry_free(centry);
2253 /* Lookup user information from a rid */
2254 static NTSTATUS query_user(struct winbindd_domain *domain,
2255 TALLOC_CTX *mem_ctx,
2256 const struct dom_sid *user_sid,
2257 struct wbint_userinfo *info)
2262 old_status = domain->online;
2263 status = wcache_query_user(domain, mem_ctx, user_sid, info);
2264 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2270 /* Return status value returned by seq number check */
2272 if (!NT_STATUS_IS_OK(domain->last_status))
2273 return domain->last_status;
2275 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2278 status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
2280 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2281 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2282 if (!domain->internal && old_status) {
2283 set_domain_offline(domain);
2285 if (!domain->internal &&
2288 NTSTATUS cache_status;
2289 cache_status = wcache_query_user(domain, mem_ctx, user_sid, info);
2290 return cache_status;
2294 refresh_sequence_number(domain, false);
2295 if (!NT_STATUS_IS_OK(status)) {
2298 wcache_save_user(domain, status, info);
2303 NTSTATUS wcache_lookup_usergroups(struct winbindd_domain *domain,
2304 TALLOC_CTX *mem_ctx,
2305 const struct dom_sid *user_sid,
2306 uint32_t *pnum_sids,
2307 struct dom_sid **psids)
2309 struct winbind_cache *cache = get_cache(domain);
2310 struct cache_entry *centry = NULL;
2312 uint32_t i, num_sids;
2313 struct dom_sid *sids;
2316 if (cache->tdb == NULL) {
2317 return NT_STATUS_NOT_FOUND;
2320 centry = wcache_fetch(cache, domain, "UG/%s",
2321 sid_to_fstring(sid_string, user_sid));
2322 if (centry == NULL) {
2323 return NT_STATUS_NOT_FOUND;
2326 /* If we have an access denied cache entry and a cached info3 in the
2327 samlogon cache then do a query. This will force the rpc back end
2328 to return the info3 data. */
2330 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)
2331 && netsamlogon_cache_have(user_sid)) {
2332 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2334 domain->last_status = NT_STATUS_OK;
2335 centry_free(centry);
2336 return NT_STATUS_NOT_FOUND;
2339 num_sids = centry_uint32(centry);
2340 sids = talloc_array(mem_ctx, struct dom_sid, num_sids);
2342 centry_free(centry);
2343 return NT_STATUS_NO_MEMORY;
2346 for (i=0; i<num_sids; i++) {
2347 centry_sid(centry, &sids[i]);
2350 status = centry->status;
2352 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2353 "status: %s\n", domain->name, nt_errstr(status)));
2355 centry_free(centry);
2357 *pnum_sids = num_sids;
2362 /* Lookup groups a user is a member of. */
2363 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
2364 TALLOC_CTX *mem_ctx,
2365 const struct dom_sid *user_sid,
2366 uint32 *num_groups, struct dom_sid **user_gids)
2368 struct cache_entry *centry = NULL;
2374 old_status = domain->online;
2375 status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2376 num_groups, user_gids);
2377 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2382 (*user_gids) = NULL;
2384 /* Return status value returned by seq number check */
2386 if (!NT_STATUS_IS_OK(domain->last_status))
2387 return domain->last_status;
2389 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2392 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
2394 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2395 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2396 if (!domain->internal && old_status) {
2397 set_domain_offline(domain);
2399 if (!domain->internal &&
2402 NTSTATUS cache_status;
2403 cache_status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2404 num_groups, user_gids);
2405 return cache_status;
2408 if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
2412 refresh_sequence_number(domain, false);
2413 if (!NT_STATUS_IS_OK(status)) {
2416 centry = centry_start(domain, status);
2420 centry_put_uint32(centry, *num_groups);
2421 for (i=0; i<(*num_groups); i++) {
2422 centry_put_sid(centry, &(*user_gids)[i]);
2425 centry_end(centry, "UG/%s", sid_to_fstring(sid_string, user_sid));
2426 centry_free(centry);
2432 static char *wcache_make_sidlist(TALLOC_CTX *mem_ctx, uint32_t num_sids,
2433 const struct dom_sid *sids)
2438 sidlist = talloc_strdup(mem_ctx, "");
2439 if (sidlist == NULL) {
2442 for (i=0; i<num_sids; i++) {
2444 sidlist = talloc_asprintf_append_buffer(
2445 sidlist, "/%s", sid_to_fstring(tmp, &sids[i]));
2446 if (sidlist == NULL) {
2453 NTSTATUS wcache_lookup_useraliases(struct winbindd_domain *domain,
2454 TALLOC_CTX *mem_ctx, uint32_t num_sids,
2455 const struct dom_sid *sids,
2456 uint32_t *pnum_aliases, uint32_t **paliases)
2458 struct winbind_cache *cache = get_cache(domain);
2459 struct cache_entry *centry = NULL;
2460 uint32_t num_aliases;
2466 if (cache->tdb == NULL) {
2467 return NT_STATUS_NOT_FOUND;
2470 if (num_sids == 0) {
2473 return NT_STATUS_OK;
2476 /* We need to cache indexed by the whole list of SIDs, the aliases
2477 * resulting might come from any of the SIDs. */
2479 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2480 if (sidlist == NULL) {
2481 return NT_STATUS_NO_MEMORY;
2484 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
2485 TALLOC_FREE(sidlist);
2486 if (centry == NULL) {
2487 return NT_STATUS_NOT_FOUND;
2490 num_aliases = centry_uint32(centry);
2491 aliases = talloc_array(mem_ctx, uint32_t, num_aliases);
2492 if (aliases == NULL) {
2493 centry_free(centry);
2494 return NT_STATUS_NO_MEMORY;
2497 for (i=0; i<num_aliases; i++) {
2498 aliases[i] = centry_uint32(centry);
2501 status = centry->status;
2503 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2504 "status %s\n", domain->name, nt_errstr(status)));
2506 centry_free(centry);
2508 *pnum_aliases = num_aliases;
2509 *paliases = aliases;
2514 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
2515 TALLOC_CTX *mem_ctx,
2516 uint32 num_sids, const struct dom_sid *sids,
2517 uint32 *num_aliases, uint32 **alias_rids)
2519 struct cache_entry *centry = NULL;
2525 old_status = domain->online;
2526 status = wcache_lookup_useraliases(domain, mem_ctx, num_sids, sids,
2527 num_aliases, alias_rids);
2528 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2533 (*alias_rids) = NULL;
2535 if (!NT_STATUS_IS_OK(domain->last_status))
2536 return domain->last_status;
2538 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2539 "for domain %s\n", domain->name ));
2541 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2542 if (sidlist == NULL) {
2543 return NT_STATUS_NO_MEMORY;
2546 status = domain->backend->lookup_useraliases(domain, mem_ctx,
2548 num_aliases, alias_rids);
2550 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2551 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2552 if (!domain->internal && old_status) {
2553 set_domain_offline(domain);
2555 if (!domain->internal &&
2558 NTSTATUS cache_status;
2559 cache_status = wcache_lookup_useraliases(domain, mem_ctx, num_sids,
2560 sids, num_aliases, alias_rids);
2561 return cache_status;
2565 refresh_sequence_number(domain, false);
2566 if (!NT_STATUS_IS_OK(status)) {
2569 centry = centry_start(domain, status);
2572 centry_put_uint32(centry, *num_aliases);
2573 for (i=0; i<(*num_aliases); i++)
2574 centry_put_uint32(centry, (*alias_rids)[i]);
2575 centry_end(centry, "UA%s", sidlist);
2576 centry_free(centry);
2582 NTSTATUS wcache_lookup_groupmem(struct winbindd_domain *domain,
2583 TALLOC_CTX *mem_ctx,
2584 const struct dom_sid *group_sid,
2585 uint32_t *num_names,
2586 struct dom_sid **sid_mem, char ***names,
2587 uint32_t **name_types)
2589 struct winbind_cache *cache = get_cache(domain);
2590 struct cache_entry *centry = NULL;
2595 if (cache->tdb == NULL) {
2596 return NT_STATUS_NOT_FOUND;
2599 sid_string = sid_string_tos(group_sid);
2600 if (sid_string == NULL) {
2601 return NT_STATUS_NO_MEMORY;
2604 centry = wcache_fetch(cache, domain, "GM/%s", sid_string);
2605 TALLOC_FREE(sid_string);
2606 if (centry == NULL) {
2607 return NT_STATUS_NOT_FOUND;
2614 *num_names = centry_uint32(centry);
2615 if (*num_names == 0) {
2616 centry_free(centry);
2617 return NT_STATUS_OK;
2620 *sid_mem = talloc_array(mem_ctx, struct dom_sid, *num_names);
2621 *names = talloc_array(mem_ctx, char *, *num_names);
2622 *name_types = talloc_array(mem_ctx, uint32, *num_names);
2624 if ((*sid_mem == NULL) || (*names == NULL) || (*name_types == NULL)) {
2625 TALLOC_FREE(*sid_mem);
2626 TALLOC_FREE(*names);
2627 TALLOC_FREE(*name_types);
2628 centry_free(centry);
2629 return NT_STATUS_NO_MEMORY;
2632 for (i=0; i<(*num_names); i++) {
2633 centry_sid(centry, &(*sid_mem)[i]);
2634 (*names)[i] = centry_string(centry, mem_ctx);
2635 (*name_types)[i] = centry_uint32(centry);
2638 status = centry->status;
2640 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2641 "status: %s\n", domain->name, nt_errstr(status)));
2643 centry_free(centry);
2647 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
2648 TALLOC_CTX *mem_ctx,
2649 const struct dom_sid *group_sid,
2650 enum lsa_SidType type,
2652 struct dom_sid **sid_mem, char ***names,
2653 uint32 **name_types)
2655 struct cache_entry *centry = NULL;
2661 old_status = domain->online;
2662 status = wcache_lookup_groupmem(domain, mem_ctx, group_sid, num_names,
2663 sid_mem, names, name_types);
2664 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2671 (*name_types) = NULL;
2673 /* Return status value returned by seq number check */
2675 if (!NT_STATUS_IS_OK(domain->last_status))
2676 return domain->last_status;
2678 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2681 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid,
2683 sid_mem, names, name_types);
2685 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2686 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2687 if (!domain->internal && old_status) {
2688 set_domain_offline(domain);
2690 if (!domain->internal &&
2693 NTSTATUS cache_status;
2694 cache_status = wcache_lookup_groupmem(domain, mem_ctx, group_sid,
2695 num_names, sid_mem, names,
2697 return cache_status;
2701 refresh_sequence_number(domain, false);
2702 if (!NT_STATUS_IS_OK(status)) {
2705 centry = centry_start(domain, status);
2708 centry_put_uint32(centry, *num_names);
2709 for (i=0; i<(*num_names); i++) {
2710 centry_put_sid(centry, &(*sid_mem)[i]);
2711 centry_put_string(centry, (*names)[i]);
2712 centry_put_uint32(centry, (*name_types)[i]);
2714 centry_end(centry, "GM/%s", sid_to_fstring(sid_string, group_sid));
2715 centry_free(centry);
2721 /* find the sequence number for a domain */
2722 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
2724 refresh_sequence_number(domain, false);
2726 *seq = domain->sequence_number;
2728 return NT_STATUS_OK;
2731 /* enumerate trusted domains
2732 * (we need to have the list of trustdoms in the cache when we go offline) -
2734 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
2735 TALLOC_CTX *mem_ctx,
2736 struct netr_DomainTrustList *trusts)
2739 struct winbind_cache *cache;
2740 struct winbindd_tdc_domain *dom_list = NULL;
2741 size_t num_domains = 0;
2742 bool retval = false;
2746 old_status = domain->online;
2748 trusts->array = NULL;
2750 cache = get_cache(domain);
2751 if (!cache || !cache->tdb) {
2755 if (domain->online) {
2759 retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2760 if (!retval || !num_domains || !dom_list) {
2761 TALLOC_FREE(dom_list);
2766 trusts->array = TALLOC_ZERO_ARRAY(mem_ctx, struct netr_DomainTrust, num_domains);
2767 if (!trusts->array) {
2768 TALLOC_FREE(dom_list);
2769 return NT_STATUS_NO_MEMORY;
2772 for (i = 0; i < num_domains; i++) {
2773 struct netr_DomainTrust *trust;
2774 struct dom_sid *sid;
2775 struct winbindd_domain *dom;
2777 dom = find_domain_from_name_noinit(dom_list[i].domain_name);
2778 if (dom && dom->internal) {
2782 trust = &trusts->array[trusts->count];
2783 trust->netbios_name = talloc_strdup(trusts->array, dom_list[i].domain_name);
2784 trust->dns_name = talloc_strdup(trusts->array, dom_list[i].dns_name);
2785 sid = talloc(trusts->array, struct dom_sid);
2786 if (!trust->netbios_name || !trust->dns_name ||
2788 TALLOC_FREE(dom_list);
2789 TALLOC_FREE(trusts->array);
2790 return NT_STATUS_NO_MEMORY;
2793 trust->trust_flags = dom_list[i].trust_flags;
2794 trust->trust_attributes = dom_list[i].trust_attribs;
2795 trust->trust_type = dom_list[i].trust_type;
2796 sid_copy(sid, &dom_list[i].sid);
2801 TALLOC_FREE(dom_list);
2802 return NT_STATUS_OK;
2805 /* Return status value returned by seq number check */
2807 if (!NT_STATUS_IS_OK(domain->last_status))
2808 return domain->last_status;
2810 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2813 status = domain->backend->trusted_domains(domain, mem_ctx, trusts);
2815 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2816 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2817 if (!domain->internal && old_status) {
2818 set_domain_offline(domain);
2820 if (!domain->internal &&
2823 retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2824 if (retval && num_domains && dom_list) {
2825 TALLOC_FREE(trusts->array);
2827 goto do_fetch_cache;
2831 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2832 * so that the generic centry handling still applies correctly -
2835 if (!NT_STATUS_IS_ERR(status)) {
2836 status = NT_STATUS_OK;
2841 /* get lockout policy */
2842 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
2843 TALLOC_CTX *mem_ctx,
2844 struct samr_DomInfo12 *policy)
2846 struct winbind_cache *cache = get_cache(domain);
2847 struct cache_entry *centry = NULL;
2851 old_status = domain->online;
2855 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2861 policy->lockout_duration = centry_nttime(centry);
2862 policy->lockout_window = centry_nttime(centry);
2863 policy->lockout_threshold = centry_uint16(centry);
2865 status = centry->status;
2867 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2868 domain->name, nt_errstr(status) ));
2870 centry_free(centry);
2874 ZERO_STRUCTP(policy);
2876 /* Return status value returned by seq number check */
2878 if (!NT_STATUS_IS_OK(domain->last_status))
2879 return domain->last_status;
2881 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2884 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2886 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2887 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2888 if (!domain->internal && old_status) {
2889 set_domain_offline(domain);
2892 !domain->internal &&
2895 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2897 goto do_fetch_cache;
2902 refresh_sequence_number(domain, false);
2903 if (!NT_STATUS_IS_OK(status)) {
2906 wcache_save_lockout_policy(domain, status, policy);
2911 /* get password policy */
2912 static NTSTATUS password_policy(struct winbindd_domain *domain,
2913 TALLOC_CTX *mem_ctx,
2914 struct samr_DomInfo1 *policy)
2916 struct winbind_cache *cache = get_cache(domain);
2917 struct cache_entry *centry = NULL;
2921 old_status = domain->online;
2925 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2931 policy->min_password_length = centry_uint16(centry);
2932 policy->password_history_length = centry_uint16(centry);
2933 policy->password_properties = centry_uint32(centry);
2934 policy->max_password_age = centry_nttime(centry);
2935 policy->min_password_age = centry_nttime(centry);
2937 status = centry->status;
2939 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2940 domain->name, nt_errstr(status) ));
2942 centry_free(centry);
2946 ZERO_STRUCTP(policy);
2948 /* Return status value returned by seq number check */
2950 if (!NT_STATUS_IS_OK(domain->last_status))
2951 return domain->last_status;
2953 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2956 status = domain->backend->password_policy(domain, mem_ctx, policy);
2958 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2959 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2960 if (!domain->internal && old_status) {
2961 set_domain_offline(domain);
2964 !domain->internal &&
2967 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2969 goto do_fetch_cache;
2974 refresh_sequence_number(domain, false);
2975 if (!NT_STATUS_IS_OK(status)) {
2978 wcache_save_password_policy(domain, status, policy);
2984 /* Invalidate cached user and group lists coherently */
2986 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2989 if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
2990 strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
2991 tdb_delete(the_tdb, kbuf);
2996 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2998 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
2999 struct netr_SamInfo3 *info3)
3002 fstring key_str, sid_string;
3003 struct winbind_cache *cache;
3005 /* dont clear cached U/SID and UG/SID entries when we want to logon
3008 if (lp_winbind_offline_logon()) {
3015 cache = get_cache(domain);
3021 sid_compose(&sid, info3->base.domain_sid, info3->base.rid);
3023 /* Clear U/SID cache entry */
3024 fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, &sid));
3025 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
3026 tdb_delete(cache->tdb, string_tdb_data(key_str));
3028 /* Clear UG/SID cache entry */
3029 fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, &sid));
3030 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
3031 tdb_delete(cache->tdb, string_tdb_data(key_str));
3033 /* Samba/winbindd never needs this. */
3034 netsamlogon_clear_cached_user(info3);
3037 bool wcache_invalidate_cache(void)
3039 struct winbindd_domain *domain;
3041 for (domain = domain_list(); domain; domain = domain->next) {
3042 struct winbind_cache *cache = get_cache(domain);
3044 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3045 "entries for %s\n", domain->name));
3048 tdb_traverse(cache->tdb, traverse_fn, NULL);
3057 bool wcache_invalidate_cache_noinit(void)
3059 struct winbindd_domain *domain;
3061 for (domain = domain_list(); domain; domain = domain->next) {
3062 struct winbind_cache *cache;
3064 /* Skip uninitialized domains. */
3065 if (!domain->initialized && !domain->internal) {
3069 cache = get_cache(domain);
3071 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3072 "entries for %s\n", domain->name));
3075 tdb_traverse(cache->tdb, traverse_fn, NULL);
3077 * Flushing cache has nothing to with domains.
3078 * return here if we successfully flushed once.
3079 * To avoid unnecessary traversing the cache.
3090 bool init_wcache(void)
3092 if (wcache == NULL) {
3093 wcache = SMB_XMALLOC_P(struct winbind_cache);
3094 ZERO_STRUCTP(wcache);
3097 if (wcache->tdb != NULL)
3100 /* when working offline we must not clear the cache on restart */
3101 wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
3102 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3103 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
3104 O_RDWR|O_CREAT, 0600);
3106 if (wcache->tdb == NULL) {
3107 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3114 /************************************************************************
3115 This is called by the parent to initialize the cache file.
3116 We don't need sophisticated locking here as we know we're the
3118 ************************************************************************/
3120 bool initialize_winbindd_cache(void)
3122 bool cache_bad = true;
3125 if (!init_wcache()) {
3126 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3130 /* Check version number. */
3131 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
3132 vers == WINBINDD_CACHE_VERSION) {
3137 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3138 "and re-creating with version number %d\n",
3139 WINBINDD_CACHE_VERSION ));
3141 tdb_close(wcache->tdb);
3144 if (unlink(cache_path("winbindd_cache.tdb")) == -1) {
3145 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3146 cache_path("winbindd_cache.tdb"),
3150 if (!init_wcache()) {
3151 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3152 "init_wcache failed.\n"));
3156 /* Write the version. */
3157 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
3158 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3159 tdb_errorstr(wcache->tdb) ));
3164 tdb_close(wcache->tdb);
3169 void close_winbindd_cache(void)
3175 tdb_close(wcache->tdb);
3180 bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
3181 char **domain_name, char **name,
3182 enum lsa_SidType *type)
3184 struct winbindd_domain *domain;
3187 domain = find_lookup_domain_from_sid(sid);
3188 if (domain == NULL) {
3191 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
3193 return NT_STATUS_IS_OK(status);
3196 bool lookup_cached_name(const char *domain_name,
3198 struct dom_sid *sid,
3199 enum lsa_SidType *type)
3201 struct winbindd_domain *domain;
3203 bool original_online_state;
3205 domain = find_lookup_domain_from_name(domain_name);
3206 if (domain == NULL) {
3210 /* If we are doing a cached logon, temporarily set the domain
3211 offline so the cache won't expire the entry */
3213 original_online_state = domain->online;
3214 domain->online = false;
3215 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
3216 domain->online = original_online_state;
3218 return NT_STATUS_IS_OK(status);
3221 void cache_name2sid(struct winbindd_domain *domain,
3222 const char *domain_name, const char *name,
3223 enum lsa_SidType type, const struct dom_sid *sid)
3225 refresh_sequence_number(domain, false);
3226 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
3231 * The original idea that this cache only contains centries has
3232 * been blurred - now other stuff gets put in here. Ensure we
3233 * ignore these things on cleanup.
3236 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
3237 TDB_DATA dbuf, void *state)
3239 struct cache_entry *centry;
3241 if (is_non_centry_key(kbuf)) {
3245 centry = wcache_fetch_raw((char *)kbuf.dptr);
3250 if (!NT_STATUS_IS_OK(centry->status)) {
3251 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
3252 tdb_delete(the_tdb, kbuf);
3255 centry_free(centry);
3259 /* flush the cache */
3260 void wcache_flush_cache(void)
3265 tdb_close(wcache->tdb);
3268 if (!winbindd_use_cache()) {
3272 /* when working offline we must not clear the cache on restart */
3273 wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
3274 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3275 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
3276 O_RDWR|O_CREAT, 0600);
3279 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3283 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
3285 DEBUG(10,("wcache_flush_cache success\n"));
3288 /* Count cached creds */
3290 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3293 int *cred_count = (int*)state;
3295 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3301 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
3303 struct winbind_cache *cache = get_cache(domain);
3308 return NT_STATUS_INTERNAL_DB_ERROR;
3311 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
3313 return NT_STATUS_OK;
3317 struct cred_list *prev, *next;
3322 static struct cred_list *wcache_cred_list;
3324 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3327 struct cred_list *cred;
3329 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3331 cred = SMB_MALLOC_P(struct cred_list);
3333 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3339 /* save a copy of the key */
3341 fstrcpy(cred->name, (const char *)kbuf.dptr);
3342 DLIST_ADD(wcache_cred_list, cred);
3348 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const struct dom_sid *sid)
3350 struct winbind_cache *cache = get_cache(domain);
3353 struct cred_list *cred, *oldest = NULL;
3356 return NT_STATUS_INTERNAL_DB_ERROR;
3359 /* we possibly already have an entry */
3360 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
3362 fstring key_str, tmp;
3364 DEBUG(11,("we already have an entry, deleting that\n"));
3366 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
3368 tdb_delete(cache->tdb, string_tdb_data(key_str));
3370 return NT_STATUS_OK;
3373 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
3375 return NT_STATUS_OK;
3376 } else if ((ret == -1) || (wcache_cred_list == NULL)) {
3377 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3380 ZERO_STRUCTP(oldest);
3382 for (cred = wcache_cred_list; cred; cred = cred->next) {
3387 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
3389 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3391 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
3395 t = IVAL(data.dptr, 0);
3396 SAFE_FREE(data.dptr);
3399 oldest = SMB_MALLOC_P(struct cred_list);
3400 if (oldest == NULL) {
3401 status = NT_STATUS_NO_MEMORY;
3405 fstrcpy(oldest->name, cred->name);
3406 oldest->created = t;
3410 if (t < oldest->created) {
3411 fstrcpy(oldest->name, cred->name);
3412 oldest->created = t;
3416 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
3417 status = NT_STATUS_OK;
3419 status = NT_STATUS_UNSUCCESSFUL;
3422 SAFE_FREE(wcache_cred_list);
3428 /* Change the global online/offline state. */
3429 bool set_global_winbindd_state_offline(void)
3433 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3435 /* Only go offline if someone has created
3436 the key "WINBINDD_OFFLINE" in the cache tdb. */
3438 if (wcache == NULL || wcache->tdb == NULL) {
3439 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3443 if (!lp_winbind_offline_logon()) {
3444 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3448 if (global_winbindd_offline_state) {
3449 /* Already offline. */
3453 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
3455 if (!data.dptr || data.dsize != 4) {
3456 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3457 SAFE_FREE(data.dptr);
3460 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3461 global_winbindd_offline_state = true;
3462 SAFE_FREE(data.dptr);
3467 void set_global_winbindd_state_online(void)
3469 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3471 if (!lp_winbind_offline_logon()) {
3472 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3476 if (!global_winbindd_offline_state) {
3477 /* Already online. */
3480 global_winbindd_offline_state = false;
3486 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3487 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
3490 bool get_global_winbindd_state_offline(void)
3492 return global_winbindd_offline_state;
3495 /***********************************************************************
3496 Validate functions for all possible cache tdb keys.
3497 ***********************************************************************/
3499 static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
3500 struct tdb_validation_status *state)
3502 struct cache_entry *centry;
3504 centry = SMB_XMALLOC_P(struct cache_entry);
3505 centry->data = (unsigned char *)memdup(data.dptr, data.dsize);
3506 if (!centry->data) {
3510 centry->len = data.dsize;
3513 if (centry->len < 8) {
3514 /* huh? corrupt cache? */
3515 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr));
3516 centry_free(centry);
3517 state->bad_entry = true;
3518 state->success = false;
3522 centry->status = NT_STATUS(centry_uint32(centry));
3523 centry->sequence_number = centry_uint32(centry);
3527 static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3528 struct tdb_validation_status *state)
3530 if (dbuf.dsize != 8) {
3531 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3532 keystr, (unsigned int)dbuf.dsize ));
3533 state->bad_entry = true;
3539 static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3540 struct tdb_validation_status *state)
3542 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3547 (void)centry_uint32(centry);
3548 if (NT_STATUS_IS_OK(centry->status)) {
3550 (void)centry_sid(centry, &sid);
3553 centry_free(centry);
3555 if (!(state->success)) {
3558 DEBUG(10,("validate_ns: %s ok\n", keystr));
3562 static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3563 struct tdb_validation_status *state)
3565 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3570 if (NT_STATUS_IS_OK(centry->status)) {
3571 (void)centry_uint32(centry);
3572 (void)centry_string(centry, mem_ctx);
3573 (void)centry_string(centry, mem_ctx);
3576 centry_free(centry);
3578 if (!(state->success)) {
3581 DEBUG(10,("validate_sn: %s ok\n", keystr));
3585 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3586 struct tdb_validation_status *state)
3588 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3595 (void)centry_string(centry, mem_ctx);
3596 (void)centry_string(centry, mem_ctx);
3597 (void)centry_string(centry, mem_ctx);
3598 (void)centry_string(centry, mem_ctx);
3599 (void)centry_uint32(centry);
3600 (void)centry_sid(centry, &sid);
3601 (void)centry_sid(centry, &sid);
3603 centry_free(centry);
3605 if (!(state->success)) {
3608 DEBUG(10,("validate_u: %s ok\n", keystr));
3612 static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3613 struct tdb_validation_status *state)
3615 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3621 (void)centry_nttime(centry);
3622 (void)centry_nttime(centry);
3623 (void)centry_uint16(centry);
3625 centry_free(centry);
3627 if (!(state->success)) {
3630 DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
3634 static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3635 struct tdb_validation_status *state)
3637 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3643 (void)centry_uint16(centry);
3644 (void)centry_uint16(centry);
3645 (void)centry_uint32(centry);
3646 (void)centry_nttime(centry);
3647 (void)centry_nttime(centry);
3649 centry_free(centry);
3651 if (!(state->success)) {
3654 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
3658 static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3659 struct tdb_validation_status *state)
3661 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3667 (void)centry_time(centry);
3668 (void)centry_hash16(centry, mem_ctx);
3670 /* We only have 17 bytes more data in the salted cred case. */
3671 if (centry->len - centry->ofs == 17) {
3672 (void)centry_hash16(centry, mem_ctx);
3675 centry_free(centry);
3677 if (!(state->success)) {
3680 DEBUG(10,("validate_cred: %s ok\n", keystr));
3684 static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3685 struct tdb_validation_status *state)
3687 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3688 int32 num_entries, i;
3694 num_entries = (int32)centry_uint32(centry);
3696 for (i=0; i< num_entries; i++) {
3698 (void)centry_string(centry, mem_ctx);
3699 (void)centry_string(centry, mem_ctx);
3700 (void)centry_string(centry, mem_ctx);
3701 (void)centry_string(centry, mem_ctx);
3702 (void)centry_sid(centry, &sid);
3703 (void)centry_sid(centry, &sid);
3706 centry_free(centry);
3708 if (!(state->success)) {
3711 DEBUG(10,("validate_ul: %s ok\n", keystr));
3715 static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3716 struct tdb_validation_status *state)
3718 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3719 int32 num_entries, i;
3725 num_entries = centry_uint32(centry);
3727 for (i=0; i< num_entries; i++) {
3728 (void)centry_string(centry, mem_ctx);
3729 (void)centry_string(centry, mem_ctx);
3730 (void)centry_uint32(centry);
3733 centry_free(centry);
3735 if (!(state->success)) {
3738 DEBUG(10,("validate_gl: %s ok\n", keystr));
3742 static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3743 struct tdb_validation_status *state)
3745 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3746 int32 num_groups, i;
3752 num_groups = centry_uint32(centry);
3754 for (i=0; i< num_groups; i++) {
3756 centry_sid(centry, &sid);
3759 centry_free(centry);
3761 if (!(state->success)) {
3764 DEBUG(10,("validate_ug: %s ok\n", keystr));
3768 static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3769 struct tdb_validation_status *state)
3771 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3772 int32 num_aliases, i;
3778 num_aliases = centry_uint32(centry);
3780 for (i=0; i < num_aliases; i++) {
3781 (void)centry_uint32(centry);
3784 centry_free(centry);
3786 if (!(state->success)) {
3789 DEBUG(10,("validate_ua: %s ok\n", keystr));
3793 static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3794 struct tdb_validation_status *state)
3796 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3803 num_names = centry_uint32(centry);
3805 for (i=0; i< num_names; i++) {
3807 centry_sid(centry, &sid);
3808 (void)centry_string(centry, mem_ctx);
3809 (void)centry_uint32(centry);
3812 centry_free(centry);
3814 if (!(state->success)) {
3817 DEBUG(10,("validate_gm: %s ok\n", keystr));
3821 static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3822 struct tdb_validation_status *state)
3824 /* Can't say anything about this other than must be nonzero. */
3825 if (dbuf.dsize == 0) {
3826 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3828 state->bad_entry = true;
3829 state->success = false;
3833 DEBUG(10,("validate_dr: %s ok\n", keystr));
3837 static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3838 struct tdb_validation_status *state)
3840 /* Can't say anything about this other than must be nonzero. */
3841 if (dbuf.dsize == 0) {
3842 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3844 state->bad_entry = true;
3845 state->success = false;
3849 DEBUG(10,("validate_de: %s ok\n", keystr));
3853 static int validate_pwinfo(TALLOC_CTX *mem_ctx, const char *keystr,
3854 TDB_DATA dbuf, struct tdb_validation_status *state)
3856 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3862 (void)centry_string(centry, mem_ctx);
3863 (void)centry_string(centry, mem_ctx);
3864 (void)centry_string(centry, mem_ctx);
3865 (void)centry_uint32(centry);
3867 centry_free(centry);
3869 if (!(state->success)) {
3872 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3876 static int validate_nss_an(TALLOC_CTX *mem_ctx, const char *keystr,
3878 struct tdb_validation_status *state)
3880 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3886 (void)centry_string( centry, mem_ctx );
3888 centry_free(centry);
3890 if (!(state->success)) {
3893 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3897 static int validate_nss_na(TALLOC_CTX *mem_ctx, const char *keystr,
3899 struct tdb_validation_status *state)
3901 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3907 (void)centry_string( centry, mem_ctx );
3909 centry_free(centry);
3911 if (!(state->success)) {
3914 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3918 static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
3920 struct tdb_validation_status *state)
3922 if (dbuf.dsize == 0) {
3923 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3924 "key %s (len ==0) ?\n", keystr));
3925 state->bad_entry = true;
3926 state->success = false;
3930 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
3931 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3935 static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3936 struct tdb_validation_status *state)
3938 if (dbuf.dsize != 4) {
3939 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3940 keystr, (unsigned int)dbuf.dsize ));
3941 state->bad_entry = true;
3942 state->success = false;
3945 DEBUG(10,("validate_offline: %s ok\n", keystr));
3949 static int validate_ndr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3950 struct tdb_validation_status *state)
3953 * Ignore validation for now. The proper way to do this is with a
3954 * checksum. Just pure parsing does not really catch much.
3959 static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3960 struct tdb_validation_status *state)
3962 if (dbuf.dsize != 4) {
3963 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3964 "key %s (len %u != 4) ?\n",
3965 keystr, (unsigned int)dbuf.dsize));
3966 state->bad_entry = true;
3967 state->success = false;
3971 DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
3975 /***********************************************************************
3976 A list of all possible cache tdb keys with associated validation
3978 ***********************************************************************/
3980 struct key_val_struct {
3981 const char *keyname;
3982 int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
3984 {"SEQNUM/", validate_seqnum},
3985 {"NS/", validate_ns},
3986 {"SN/", validate_sn},
3988 {"LOC_POL/", validate_loc_pol},
3989 {"PWD_POL/", validate_pwd_pol},
3990 {"CRED/", validate_cred},
3991 {"UL/", validate_ul},
3992 {"GL/", validate_gl},
3993 {"UG/", validate_ug},
3994 {"UA", validate_ua},
3995 {"GM/", validate_gm},
3996 {"DR/", validate_dr},
3997 {"DE/", validate_de},
3998 {"NSS/PWINFO/", validate_pwinfo},
3999 {"TRUSTDOMCACHE/", validate_trustdomcache},
4000 {"NSS/NA/", validate_nss_na},
4001 {"NSS/AN/", validate_nss_an},
4002 {"WINBINDD_OFFLINE", validate_offline},
4003 {"NDR/", validate_ndr},
4004 {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
4008 /***********************************************************************
4009 Function to look at every entry in the tdb and validate it as far as
4011 ***********************************************************************/
4013 static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
4016 unsigned int max_key_len = 1024;
4017 struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
4019 /* Paranoia check. */
4020 if (strncmp("UA/", (const char *)kbuf.dptr, 3) == 0) {
4021 max_key_len = 1024 * 1024;
4023 if (kbuf.dsize > max_key_len) {
4024 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4026 (unsigned int)kbuf.dsize, (unsigned int)max_key_len));
4030 for (i = 0; key_val[i].keyname; i++) {
4031 size_t namelen = strlen(key_val[i].keyname);
4032 if (kbuf.dsize >= namelen && (
4033 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
4034 TALLOC_CTX *mem_ctx;
4038 keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
4042 memcpy(keystr, kbuf.dptr, kbuf.dsize);
4043 keystr[kbuf.dsize] = '\0';
4045 mem_ctx = talloc_init("validate_ctx");
4051 ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
4055 talloc_destroy(mem_ctx);
4060 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4061 dump_data(0, (uint8 *)kbuf.dptr, kbuf.dsize);
4062 DEBUG(0,("data :\n"));
4063 dump_data(0, (uint8 *)dbuf.dptr, dbuf.dsize);
4064 v_state->unknown_key = true;
4065 v_state->success = false;
4066 return 1; /* terminate. */
4069 static void validate_panic(const char *const why)
4071 DEBUG(0,("validating cache: would panic %s\n", why ));
4072 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4076 /***********************************************************************
4077 Try and validate every entry in the winbindd cache. If we fail here,
4078 delete the cache tdb and return non-zero.
4079 ***********************************************************************/
4081 int winbindd_validate_cache(void)
4084 const char *tdb_path = cache_path("winbindd_cache.tdb");
4085 TDB_CONTEXT *tdb = NULL;
4087 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4088 smb_panic_fn = validate_panic;
4091 tdb = tdb_open_log(tdb_path,
4092 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
4093 ( lp_winbind_offline_logon()
4095 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
4099 DEBUG(0, ("winbindd_validate_cache: "
4100 "error opening/initializing tdb\n"));
4105 ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
4108 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4109 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
4114 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4115 smb_panic_fn = smb_panic;
4119 /***********************************************************************
4120 Try and validate every entry in the winbindd cache.
4121 ***********************************************************************/
4123 int winbindd_validate_cache_nobackup(void)
4126 const char *tdb_path = cache_path("winbindd_cache.tdb");
4128 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4129 smb_panic_fn = validate_panic;
4132 if (wcache == NULL || wcache->tdb == NULL) {
4133 ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
4135 ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
4139 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4143 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4145 smb_panic_fn = smb_panic;
4149 bool winbindd_cache_validate_and_initialize(void)
4151 close_winbindd_cache();
4153 if (lp_winbind_offline_logon()) {
4154 if (winbindd_validate_cache() < 0) {
4155 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4156 "could be restored.\n"));
4160 return initialize_winbindd_cache();
4163 /*********************************************************************
4164 ********************************************************************/
4166 static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
4167 struct winbindd_tdc_domain **domains,
4168 size_t *num_domains )
4170 struct winbindd_tdc_domain *list = NULL;
4173 bool set_only = false;
4175 /* don't allow duplicates */
4180 for ( i=0; i< (*num_domains); i++ ) {
4181 if ( strequal( new_dom->name, list[i].domain_name ) ) {
4182 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4193 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, 1 );
4196 list = TALLOC_REALLOC_ARRAY( *domains, *domains,
4197 struct winbindd_tdc_domain,
4202 ZERO_STRUCT( list[idx] );
4208 list[idx].domain_name = talloc_strdup( list, new_dom->name );
4209 list[idx].dns_name = talloc_strdup( list, new_dom->alt_name );
4211 if ( !is_null_sid( &new_dom->sid ) ) {
4212 sid_copy( &list[idx].sid, &new_dom->sid );
4214 sid_copy(&list[idx].sid, &global_sid_NULL);
4217 if ( new_dom->domain_flags != 0x0 )
4218 list[idx].trust_flags = new_dom->domain_flags;
4220 if ( new_dom->domain_type != 0x0 )
4221 list[idx].trust_type = new_dom->domain_type;
4223 if ( new_dom->domain_trust_attribs != 0x0 )
4224 list[idx].trust_attribs = new_dom->domain_trust_attribs;
4228 *num_domains = idx + 1;
4234 /*********************************************************************
4235 ********************************************************************/
4237 static TDB_DATA make_tdc_key( const char *domain_name )
4239 char *keystr = NULL;
4240 TDB_DATA key = { NULL, 0 };
4242 if ( !domain_name ) {
4243 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4247 if (asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name ) == -1) {
4250 key = string_term_tdb_data(keystr);
4255 /*********************************************************************
4256 ********************************************************************/
4258 static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
4260 unsigned char **buf )
4262 unsigned char *buffer = NULL;
4267 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4275 /* Store the number of array items first */
4276 len += tdb_pack( buffer+len, buflen-len, "d",
4279 /* now pack each domain trust record */
4280 for ( i=0; i<num_domains; i++ ) {
4285 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4286 domains[i].domain_name,
4287 domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
4290 len += tdb_pack( buffer+len, buflen-len, "fffddd",
4291 domains[i].domain_name,
4292 domains[i].dns_name,
4293 sid_to_fstring(tmp, &domains[i].sid),
4294 domains[i].trust_flags,
4295 domains[i].trust_attribs,
4296 domains[i].trust_type );
4299 if ( buflen < len ) {
4301 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
4302 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4316 /*********************************************************************
4317 ********************************************************************/
4319 static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
4320 struct winbindd_tdc_domain **domains )
4322 fstring domain_name, dns_name, sid_string;
4323 uint32 type, attribs, flags;
4327 struct winbindd_tdc_domain *list = NULL;
4329 /* get the number of domains */
4330 len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
4332 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4336 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, num_domains );
4338 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4342 for ( i=0; i<num_domains; i++ ) {
4343 len += tdb_unpack( buf+len, buflen-len, "fffddd",
4352 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4353 TALLOC_FREE( list );
4357 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4358 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4359 domain_name, dns_name, sid_string,
4360 flags, attribs, type));
4362 list[i].domain_name = talloc_strdup( list, domain_name );
4363 list[i].dns_name = talloc_strdup( list, dns_name );
4364 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
4365 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4368 list[i].trust_flags = flags;
4369 list[i].trust_attribs = attribs;
4370 list[i].trust_type = type;
4378 /*********************************************************************
4379 ********************************************************************/
4381 static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
4383 TDB_DATA key = make_tdc_key( lp_workgroup() );
4384 TDB_DATA data = { NULL, 0 };
4390 /* See if we were asked to delete the cache entry */
4393 ret = tdb_delete( wcache->tdb, key );
4397 data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
4404 ret = tdb_store( wcache->tdb, key, data, 0 );
4407 SAFE_FREE( data.dptr );
4408 SAFE_FREE( key.dptr );
4410 return ( ret != -1 );
4413 /*********************************************************************
4414 ********************************************************************/
4416 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
4418 TDB_DATA key = make_tdc_key( lp_workgroup() );
4419 TDB_DATA data = { NULL, 0 };
4427 data = tdb_fetch( wcache->tdb, key );
4429 SAFE_FREE( key.dptr );
4434 *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
4436 SAFE_FREE( data.dptr );
4444 /*********************************************************************
4445 ********************************************************************/
4447 bool wcache_tdc_add_domain( struct winbindd_domain *domain )
4449 struct winbindd_tdc_domain *dom_list = NULL;
4450 size_t num_domains = 0;
4453 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4454 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4455 domain->name, domain->alt_name,
4456 sid_string_dbg(&domain->sid),
4457 domain->domain_flags,
4458 domain->domain_trust_attribs,
4459 domain->domain_type));
4461 if ( !init_wcache() ) {
4465 /* fetch the list */
4467 wcache_tdc_fetch_list( &dom_list, &num_domains );
4469 /* add the new domain */
4471 if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
4475 /* pack the domain */
4477 if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
4485 TALLOC_FREE( dom_list );
4490 /*********************************************************************
4491 ********************************************************************/
4493 struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
4495 struct winbindd_tdc_domain *dom_list = NULL;
4496 size_t num_domains = 0;
4498 struct winbindd_tdc_domain *d = NULL;
4500 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
4502 if ( !init_wcache() ) {
4506 /* fetch the list */
4508 wcache_tdc_fetch_list( &dom_list, &num_domains );
4510 for ( i=0; i<num_domains; i++ ) {
4511 if ( strequal(name, dom_list[i].domain_name) ||
4512 strequal(name, dom_list[i].dns_name) )
4514 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4517 d = TALLOC_P( ctx, struct winbindd_tdc_domain );
4521 d->domain_name = talloc_strdup( d, dom_list[i].domain_name );
4522 d->dns_name = talloc_strdup( d, dom_list[i].dns_name );
4523 sid_copy( &d->sid, &dom_list[i].sid );
4524 d->trust_flags = dom_list[i].trust_flags;
4525 d->trust_type = dom_list[i].trust_type;
4526 d->trust_attribs = dom_list[i].trust_attribs;
4532 TALLOC_FREE( dom_list );
4538 /*********************************************************************
4539 ********************************************************************/
4541 void wcache_tdc_clear( void )
4543 if ( !init_wcache() )
4546 wcache_tdc_store_list( NULL, 0 );
4552 /*********************************************************************
4553 ********************************************************************/
4555 static void wcache_save_user_pwinfo(struct winbindd_domain *domain,
4557 const struct dom_sid *user_sid,
4558 const char *homedir,
4563 struct cache_entry *centry;
4566 if ( (centry = centry_start(domain, status)) == NULL )
4569 centry_put_string( centry, homedir );
4570 centry_put_string( centry, shell );
4571 centry_put_string( centry, gecos );
4572 centry_put_uint32( centry, gid );
4574 centry_end(centry, "NSS/PWINFO/%s", sid_to_fstring(tmp, user_sid) );
4576 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid) ));
4578 centry_free(centry);
4581 NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
4582 const struct dom_sid *user_sid,
4584 ADS_STRUCT *ads, LDAPMessage *msg,
4585 const char **homedir, const char **shell,
4586 const char **gecos, gid_t *p_gid)
4588 struct winbind_cache *cache = get_cache(domain);
4589 struct cache_entry *centry = NULL;
4596 centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s",
4597 sid_to_fstring(tmp, user_sid));
4602 *homedir = centry_string( centry, ctx );
4603 *shell = centry_string( centry, ctx );
4604 *gecos = centry_string( centry, ctx );
4605 *p_gid = centry_uint32( centry );
4607 centry_free(centry);
4609 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4610 sid_string_dbg(user_sid)));
4612 return NT_STATUS_OK;
4616 nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg,
4617 homedir, shell, gecos, p_gid );
4619 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status)));
4621 if ( NT_STATUS_IS_OK(nt_status) ) {
4622 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir));
4623 DEBUGADD(10, ("\tshell = '%s'\n", *shell));
4624 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos));
4625 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid));
4627 wcache_save_user_pwinfo( domain, nt_status, user_sid,
4628 *homedir, *shell, *gecos, *p_gid );
4631 if ( NT_STATUS_EQUAL( nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
4632 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4634 set_domain_offline( domain );
4641 /* the cache backend methods are exposed via this structure */
4642 struct winbindd_methods cache_methods = {
4660 static bool wcache_ndr_key(TALLOC_CTX *mem_ctx, char *domain_name,
4661 uint32_t opnum, const DATA_BLOB *req,
4667 key = talloc_asprintf(mem_ctx, "NDR/%s/%d/", domain_name, (int)opnum);
4671 keylen = talloc_get_size(key) - 1;
4673 key = talloc_realloc(mem_ctx, key, char, keylen + req->length);
4677 memcpy(key + keylen, req->data, req->length);
4679 pkey->dptr = (uint8_t *)key;
4680 pkey->dsize = talloc_get_size(key);
4684 static bool wcache_opnum_cacheable(uint32_t opnum)
4687 case NDR_WBINT_PING:
4688 case NDR_WBINT_QUERYSEQUENCENUMBER:
4689 case NDR_WBINT_ALLOCATEUID:
4690 case NDR_WBINT_ALLOCATEGID:
4691 case NDR_WBINT_CHECKMACHINEACCOUNT:
4692 case NDR_WBINT_CHANGEMACHINEACCOUNT:
4693 case NDR_WBINT_PINGDC:
4699 bool wcache_fetch_ndr(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
4700 uint32_t opnum, const DATA_BLOB *req, DATA_BLOB *resp)
4705 if (!wcache_opnum_cacheable(opnum) ||
4706 is_my_own_sam_domain(domain) ||
4707 is_builtin_domain(domain)) {
4711 if (wcache->tdb == NULL) {
4715 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4718 data = tdb_fetch(wcache->tdb, key);
4719 TALLOC_FREE(key.dptr);
4721 if (data.dptr == NULL) {
4724 if (data.dsize < 4) {
4728 if (!is_domain_offline(domain)) {
4729 uint32_t entry_seqnum, dom_seqnum, last_check;
4731 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum,
4735 entry_seqnum = IVAL(data.dptr, 0);
4736 if (entry_seqnum != dom_seqnum) {
4737 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4738 (int)entry_seqnum));
4743 resp->data = (uint8_t *)talloc_memdup(mem_ctx, data.dptr + 4,
4745 if (resp->data == NULL) {
4746 DEBUG(10, ("talloc failed\n"));
4749 resp->length = data.dsize - 4;
4753 SAFE_FREE(data.dptr);
4757 void wcache_store_ndr(struct winbindd_domain *domain, uint32_t opnum,
4758 const DATA_BLOB *req, const DATA_BLOB *resp)
4761 uint32_t dom_seqnum, last_check;
4763 if (!wcache_opnum_cacheable(opnum) ||
4764 is_my_own_sam_domain(domain) ||
4765 is_builtin_domain(domain)) {
4769 if (wcache->tdb == NULL) {
4773 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum, &last_check)) {
4774 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4779 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4783 data.dsize = resp->length + 4;
4784 data.dptr = talloc_array(key.dptr, uint8_t, data.dsize);
4785 if (data.dptr == NULL) {
4789 SIVAL(data.dptr, 0, dom_seqnum);
4790 memcpy(data.dptr+4, resp->data, resp->length);
4792 tdb_store(wcache->tdb, key, data, 0);
4795 TALLOC_FREE(key.dptr);