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/>.
30 #define DBGC_CLASS DBGC_WINBIND
32 #define WINBINDD_CACHE_VERSION 1
33 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
35 extern struct winbindd_methods reconnect_methods;
36 extern bool opt_nocache;
38 extern struct winbindd_methods ads_methods;
40 extern struct winbindd_methods builtin_passdb_methods;
43 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
44 * Here are the list of entry types that are *not* stored
45 * as form struct cache_entry in the cache.
48 static const char *non_centry_keys[] = {
53 WINBINDD_CACHE_VERSION_KEYSTR,
57 /************************************************************************
58 Is this key a non-centry type ?
59 ************************************************************************/
61 static bool is_non_centry_key(TDB_DATA kbuf)
65 if (kbuf.dptr == NULL || kbuf.dsize == 0) {
68 for (i = 0; non_centry_keys[i] != NULL; i++) {
69 size_t namelen = strlen(non_centry_keys[i]);
70 if (kbuf.dsize < namelen) {
73 if (strncmp(non_centry_keys[i], (const char *)kbuf.dptr, namelen) == 0) {
80 /* Global online/offline state - False when online. winbindd starts up online
81 and sets this to true if the first query fails and there's an entry in
82 the cache tdb telling us to stay offline. */
84 static bool global_winbindd_offline_state;
86 struct winbind_cache {
92 uint32 sequence_number;
97 void (*smb_panic_fn)(const char *const why) = smb_panic;
99 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
101 static struct winbind_cache *wcache;
103 void winbindd_check_cache_size(time_t t)
105 static time_t last_check_time;
108 if (last_check_time == (time_t)0)
111 if (t - last_check_time < 60 && t - last_check_time > 0)
114 if (wcache == NULL || wcache->tdb == NULL) {
115 DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
119 if (fstat(tdb_fd(wcache->tdb), &st) == -1) {
120 DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno) ));
124 if (st.st_size > WINBINDD_MAX_CACHE_SIZE) {
125 DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
126 (unsigned long)st.st_size,
127 (unsigned long)WINBINDD_MAX_CACHE_SIZE));
128 wcache_flush_cache();
132 /* get the winbind_cache structure */
133 static struct winbind_cache *get_cache(struct winbindd_domain *domain)
135 struct winbind_cache *ret = wcache;
137 /* We have to know what type of domain we are dealing with first. */
139 if (domain->internal) {
140 domain->backend = &builtin_passdb_methods;
141 domain->initialized = True;
143 if ( !domain->initialized ) {
144 init_dc_connection( domain );
148 OK. listen up becasue I'm only going to say this once.
149 We have the following scenarios to consider
150 (a) trusted AD domains on a Samba DC,
151 (b) trusted AD domains and we are joined to a non-kerberos domain
152 (c) trusted AD domains and we are joined to a kerberos (AD) domain
154 For (a) we can always contact the trusted domain using krb5
155 since we have the domain trust account password
157 For (b) we can only use RPC since we have no way of
158 getting a krb5 ticket in our own domain
160 For (c) we can always use krb5 since we have a kerberos trust
165 if (!domain->backend) {
167 struct winbindd_domain *our_domain = domain;
169 /* find our domain first so we can figure out if we
170 are joined to a kerberized domain */
172 if ( !domain->primary )
173 our_domain = find_our_domain();
175 if ((our_domain->active_directory || IS_DC)
176 && domain->active_directory
177 && !lp_winbind_rpc_only()) {
178 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain->name));
179 domain->backend = &ads_methods;
181 #endif /* HAVE_ADS */
182 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain->name));
183 domain->backend = &reconnect_methods;
186 #endif /* HAVE_ADS */
192 ret = SMB_XMALLOC_P(struct winbind_cache);
196 wcache_flush_cache();
202 free a centry structure
204 static void centry_free(struct cache_entry *centry)
208 SAFE_FREE(centry->data);
212 static bool centry_check_bytes(struct cache_entry *centry, size_t nbytes)
214 if (centry->len - centry->ofs < nbytes) {
215 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
216 (unsigned int)nbytes,
217 centry->len - centry->ofs));
224 pull a uint32 from a cache entry
226 static uint32 centry_uint32(struct cache_entry *centry)
230 if (!centry_check_bytes(centry, 4)) {
231 smb_panic_fn("centry_uint32");
233 ret = IVAL(centry->data, centry->ofs);
239 pull a uint16 from a cache entry
241 static uint16 centry_uint16(struct cache_entry *centry)
244 if (!centry_check_bytes(centry, 2)) {
245 smb_panic_fn("centry_uint16");
247 ret = CVAL(centry->data, centry->ofs);
253 pull a uint8 from a cache entry
255 static uint8 centry_uint8(struct cache_entry *centry)
258 if (!centry_check_bytes(centry, 1)) {
259 smb_panic_fn("centry_uint8");
261 ret = CVAL(centry->data, centry->ofs);
267 pull a NTTIME from a cache entry
269 static NTTIME centry_nttime(struct cache_entry *centry)
272 if (!centry_check_bytes(centry, 8)) {
273 smb_panic_fn("centry_nttime");
275 ret = IVAL(centry->data, centry->ofs);
277 ret += (uint64_t)IVAL(centry->data, centry->ofs) << 32;
283 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
285 static time_t centry_time(struct cache_entry *centry)
287 return (time_t)centry_nttime(centry);
290 /* pull a string from a cache entry, using the supplied
293 static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
298 len = centry_uint8(centry);
301 /* a deliberate NULL string */
305 if (!centry_check_bytes(centry, (size_t)len)) {
306 smb_panic_fn("centry_string");
309 ret = TALLOC_ARRAY(mem_ctx, char, len+1);
311 smb_panic_fn("centry_string out of memory\n");
313 memcpy(ret,centry->data + centry->ofs, len);
319 /* pull a hash16 from a cache entry, using the supplied
322 static char *centry_hash16(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
327 len = centry_uint8(centry);
330 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
335 if (!centry_check_bytes(centry, 16)) {
339 ret = TALLOC_ARRAY(mem_ctx, char, 16);
341 smb_panic_fn("centry_hash out of memory\n");
343 memcpy(ret,centry->data + centry->ofs, 16);
348 /* pull a sid from a cache entry, using the supplied
351 static bool centry_sid(struct cache_entry *centry, TALLOC_CTX *mem_ctx, DOM_SID *sid)
354 sid_string = centry_string(centry, mem_ctx);
355 if ((sid_string == NULL) || (!string_to_sid(sid, sid_string))) {
363 pull a NTSTATUS from a cache entry
365 static NTSTATUS centry_ntstatus(struct cache_entry *centry)
369 status = NT_STATUS(centry_uint32(centry));
374 /* the server is considered down if it can't give us a sequence number */
375 static bool wcache_server_down(struct winbindd_domain *domain)
382 ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
385 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
390 static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
397 DEBUG(10,("fetch_cache_seqnum: tdb == NULL\n"));
398 return NT_STATUS_UNSUCCESSFUL;
401 fstr_sprintf( key, "SEQNUM/%s", domain->name );
403 data = tdb_fetch_bystring( wcache->tdb, key );
404 if ( !data.dptr || data.dsize!=8 ) {
405 DEBUG(10,("fetch_cache_seqnum: invalid data size key [%s]\n", key ));
406 return NT_STATUS_UNSUCCESSFUL;
409 domain->sequence_number = IVAL(data.dptr, 0);
410 domain->last_seq_check = IVAL(data.dptr, 4);
412 SAFE_FREE(data.dptr);
414 /* have we expired? */
416 time_diff = now - domain->last_seq_check;
417 if ( time_diff > lp_winbind_cache_time() ) {
418 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
419 domain->name, domain->sequence_number,
420 (uint32)domain->last_seq_check));
421 return NT_STATUS_UNSUCCESSFUL;
424 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
425 domain->name, domain->sequence_number,
426 (uint32)domain->last_seq_check));
431 static NTSTATUS store_cache_seqnum( struct winbindd_domain *domain )
438 DEBUG(10,("store_cache_seqnum: tdb == NULL\n"));
439 return NT_STATUS_UNSUCCESSFUL;
442 fstr_sprintf( key_str, "SEQNUM/%s", domain->name );
444 SIVAL(buf, 0, domain->sequence_number);
445 SIVAL(buf, 4, domain->last_seq_check);
449 if ( tdb_store_bystring( wcache->tdb, key_str, data, TDB_REPLACE) == -1 ) {
450 DEBUG(10,("store_cache_seqnum: tdb_store fail key [%s]\n", key_str ));
451 return NT_STATUS_UNSUCCESSFUL;
454 DEBUG(10,("store_cache_seqnum: success [%s][%u @ %u]\n",
455 domain->name, domain->sequence_number,
456 (uint32)domain->last_seq_check));
462 refresh the domain sequence number. If force is true
463 then always refresh it, no matter how recently we fetched it
466 static void refresh_sequence_number(struct winbindd_domain *domain, bool force)
470 time_t t = time(NULL);
471 unsigned cache_time = lp_winbind_cache_time();
473 if ( IS_DOMAIN_OFFLINE(domain) ) {
479 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
480 /* trying to reconnect is expensive, don't do it too often */
481 if (domain->sequence_number == DOM_SEQUENCE_NONE) {
486 time_diff = t - domain->last_seq_check;
488 /* see if we have to refetch the domain sequence number */
489 if (!force && (time_diff < cache_time)) {
490 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
494 /* try to get the sequence number from the tdb cache first */
495 /* this will update the timestamp as well */
497 status = fetch_cache_seqnum( domain, t );
498 if ( NT_STATUS_IS_OK(status) )
501 /* important! make sure that we know if this is a native
502 mode domain or not. And that we can contact it. */
504 if ( winbindd_can_contact_domain( domain ) ) {
505 status = domain->backend->sequence_number(domain,
506 &domain->sequence_number);
508 /* just use the current time */
509 status = NT_STATUS_OK;
510 domain->sequence_number = time(NULL);
514 /* the above call could have set our domain->backend to NULL when
515 * coming from offline to online mode, make sure to reinitialize the
516 * backend - Guenther */
519 if (!NT_STATUS_IS_OK(status)) {
520 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status)));
521 domain->sequence_number = DOM_SEQUENCE_NONE;
524 domain->last_status = status;
525 domain->last_seq_check = time(NULL);
527 /* save the new sequence number in the cache */
528 store_cache_seqnum( domain );
531 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
532 domain->name, domain->sequence_number));
538 decide if a cache entry has expired
540 static bool centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
542 /* If we've been told to be offline - stay in that state... */
543 if (lp_winbind_offline_logon() && global_winbindd_offline_state) {
544 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
545 keystr, domain->name ));
549 /* when the domain is offline return the cached entry.
550 * This deals with transient offline states... */
552 if (!domain->online) {
553 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
554 keystr, domain->name ));
558 /* if the server is OK and our cache entry came from when it was down then
559 the entry is invalid */
560 if ((domain->sequence_number != DOM_SEQUENCE_NONE) &&
561 (centry->sequence_number == DOM_SEQUENCE_NONE)) {
562 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
563 keystr, domain->name ));
567 /* if the server is down or the cache entry is not older than the
568 current sequence number then it is OK */
569 if (wcache_server_down(domain) ||
570 centry->sequence_number == domain->sequence_number) {
571 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
572 keystr, domain->name ));
576 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
577 keystr, domain->name ));
583 static struct cache_entry *wcache_fetch_raw(char *kstr)
586 struct cache_entry *centry;
589 key = string_tdb_data(kstr);
590 data = tdb_fetch(wcache->tdb, key);
596 centry = SMB_XMALLOC_P(struct cache_entry);
597 centry->data = (unsigned char *)data.dptr;
598 centry->len = data.dsize;
601 if (centry->len < 8) {
602 /* huh? corrupt cache? */
603 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr));
608 centry->status = centry_ntstatus(centry);
609 centry->sequence_number = centry_uint32(centry);
615 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
616 number and return status
618 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
619 struct winbindd_domain *domain,
620 const char *format, ...) PRINTF_ATTRIBUTE(3,4);
621 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
622 struct winbindd_domain *domain,
623 const char *format, ...)
627 struct cache_entry *centry;
633 refresh_sequence_number(domain, false);
635 va_start(ap, format);
636 smb_xvasprintf(&kstr, format, ap);
639 centry = wcache_fetch_raw(kstr);
640 if (centry == NULL) {
645 if (centry_expired(domain, kstr, centry)) {
647 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
648 kstr, domain->name ));
655 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
656 kstr, domain->name ));
662 static void wcache_delete(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
663 static void wcache_delete(const char *format, ...)
669 va_start(ap, format);
670 smb_xvasprintf(&kstr, format, ap);
673 key = string_tdb_data(kstr);
675 tdb_delete(wcache->tdb, key);
680 make sure we have at least len bytes available in a centry
682 static void centry_expand(struct cache_entry *centry, uint32 len)
684 if (centry->len - centry->ofs >= len)
687 centry->data = SMB_REALLOC_ARRAY(centry->data, unsigned char,
690 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
691 smb_panic_fn("out of memory in centry_expand");
696 push a uint32 into a centry
698 static void centry_put_uint32(struct cache_entry *centry, uint32 v)
700 centry_expand(centry, 4);
701 SIVAL(centry->data, centry->ofs, v);
706 push a uint16 into a centry
708 static void centry_put_uint16(struct cache_entry *centry, uint16 v)
710 centry_expand(centry, 2);
711 SIVAL(centry->data, centry->ofs, v);
716 push a uint8 into a centry
718 static void centry_put_uint8(struct cache_entry *centry, uint8 v)
720 centry_expand(centry, 1);
721 SCVAL(centry->data, centry->ofs, v);
726 push a string into a centry
728 static void centry_put_string(struct cache_entry *centry, const char *s)
733 /* null strings are marked as len 0xFFFF */
734 centry_put_uint8(centry, 0xFF);
739 /* can't handle more than 254 char strings. Truncating is probably best */
741 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len));
744 centry_put_uint8(centry, len);
745 centry_expand(centry, len);
746 memcpy(centry->data + centry->ofs, s, len);
751 push a 16 byte hash into a centry - treat as 16 byte string.
753 static void centry_put_hash16(struct cache_entry *centry, const uint8 val[16])
755 centry_put_uint8(centry, 16);
756 centry_expand(centry, 16);
757 memcpy(centry->data + centry->ofs, val, 16);
761 static void centry_put_sid(struct cache_entry *centry, const DOM_SID *sid)
764 centry_put_string(centry, sid_to_fstring(sid_string, sid));
769 put NTSTATUS into a centry
771 static void centry_put_ntstatus(struct cache_entry *centry, NTSTATUS status)
773 uint32 status_value = NT_STATUS_V(status);
774 centry_put_uint32(centry, status_value);
779 push a NTTIME into a centry
781 static void centry_put_nttime(struct cache_entry *centry, NTTIME nt)
783 centry_expand(centry, 8);
784 SIVAL(centry->data, centry->ofs, nt & 0xFFFFFFFF);
786 SIVAL(centry->data, centry->ofs, nt >> 32);
791 push a time_t into a centry - use a 64 bit size.
792 NTTIME here is being used as a convenient 64-bit size.
794 static void centry_put_time(struct cache_entry *centry, time_t t)
796 NTTIME nt = (NTTIME)t;
797 centry_put_nttime(centry, nt);
801 start a centry for output. When finished, call centry_end()
803 struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status)
805 struct cache_entry *centry;
810 centry = SMB_XMALLOC_P(struct cache_entry);
812 centry->len = 8192; /* reasonable default */
813 centry->data = SMB_XMALLOC_ARRAY(uint8, centry->len);
815 centry->sequence_number = domain->sequence_number;
816 centry_put_ntstatus(centry, status);
817 centry_put_uint32(centry, centry->sequence_number);
822 finish a centry and write it to the tdb
824 static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
825 static void centry_end(struct cache_entry *centry, const char *format, ...)
835 va_start(ap, format);
836 smb_xvasprintf(&kstr, format, ap);
839 key = string_tdb_data(kstr);
840 data.dptr = centry->data;
841 data.dsize = centry->ofs;
843 tdb_store(wcache->tdb, key, data, TDB_REPLACE);
847 static void wcache_save_name_to_sid(struct winbindd_domain *domain,
848 NTSTATUS status, const char *domain_name,
849 const char *name, const DOM_SID *sid,
850 enum lsa_SidType type)
852 struct cache_entry *centry;
855 centry = centry_start(domain, status);
858 centry_put_uint32(centry, type);
859 centry_put_sid(centry, sid);
860 fstrcpy(uname, name);
862 centry_end(centry, "NS/%s/%s", domain_name, uname);
863 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name,
864 uname, sid_string_dbg(sid), nt_errstr(status)));
868 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
869 const DOM_SID *sid, const char *domain_name, const char *name, enum lsa_SidType type)
871 struct cache_entry *centry;
874 centry = centry_start(domain, status);
878 if (NT_STATUS_IS_OK(status)) {
879 centry_put_uint32(centry, type);
880 centry_put_string(centry, domain_name);
881 centry_put_string(centry, name);
884 centry_end(centry, "SN/%s", sid_to_fstring(sid_string, sid));
885 DEBUG(10,("wcache_save_sid_to_name: %s -> %s (%s)\n", sid_string,
886 name, nt_errstr(status)));
891 static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status, WINBIND_USERINFO *info)
893 struct cache_entry *centry;
896 if (is_null_sid(&info->user_sid)) {
900 centry = centry_start(domain, status);
903 centry_put_string(centry, info->acct_name);
904 centry_put_string(centry, info->full_name);
905 centry_put_string(centry, info->homedir);
906 centry_put_string(centry, info->shell);
907 centry_put_uint32(centry, info->primary_gid);
908 centry_put_sid(centry, &info->user_sid);
909 centry_put_sid(centry, &info->group_sid);
910 centry_end(centry, "U/%s", sid_to_fstring(sid_string,
912 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
916 static void wcache_save_lockout_policy(struct winbindd_domain *domain,
918 struct samr_DomInfo12 *lockout_policy)
920 struct cache_entry *centry;
922 centry = centry_start(domain, status);
926 centry_put_nttime(centry, lockout_policy->lockout_duration);
927 centry_put_nttime(centry, lockout_policy->lockout_window);
928 centry_put_uint16(centry, lockout_policy->lockout_threshold);
930 centry_end(centry, "LOC_POL/%s", domain->name);
932 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
937 static void wcache_save_password_policy(struct winbindd_domain *domain,
939 struct samr_DomInfo1 *policy)
941 struct cache_entry *centry;
943 centry = centry_start(domain, status);
947 centry_put_uint16(centry, policy->min_password_length);
948 centry_put_uint16(centry, policy->password_history_length);
949 centry_put_uint32(centry, policy->password_properties);
950 centry_put_nttime(centry, policy->max_password_age);
951 centry_put_nttime(centry, policy->min_password_age);
953 centry_end(centry, "PWD_POL/%s", domain->name);
955 DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
960 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const DOM_SID *sid)
962 struct winbind_cache *cache = get_cache(domain);
964 fstring key_str, tmp;
968 return NT_STATUS_INTERNAL_DB_ERROR;
971 if (is_null_sid(sid)) {
972 return NT_STATUS_INVALID_SID;
975 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
976 return NT_STATUS_INVALID_SID;
979 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
981 data = tdb_fetch(cache->tdb, string_tdb_data(key_str));
983 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
986 SAFE_FREE(data.dptr);
990 /* Lookup creds for a SID - copes with old (unsalted) creds as well
991 as new salted ones. */
993 NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
996 const uint8 **cached_nt_pass,
997 const uint8 **cached_salt)
999 struct winbind_cache *cache = get_cache(domain);
1000 struct cache_entry *centry = NULL;
1007 return NT_STATUS_INTERNAL_DB_ERROR;
1010 if (is_null_sid(sid)) {
1011 return NT_STATUS_INVALID_SID;
1014 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1015 return NT_STATUS_INVALID_SID;
1018 /* Try and get a salted cred first. If we can't
1019 fall back to an unsalted cred. */
1021 centry = wcache_fetch(cache, domain, "CRED/%s",
1022 sid_to_fstring(tmp, sid));
1024 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1025 sid_string_dbg(sid)));
1026 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1029 t = centry_time(centry);
1031 /* In the salted case this isn't actually the nt_hash itself,
1032 but the MD5 of the salt + nt_hash. Let the caller
1033 sort this out. It can tell as we only return the cached_salt
1034 if we are returning a salted cred. */
1036 *cached_nt_pass = (const uint8 *)centry_hash16(centry, mem_ctx);
1037 if (*cached_nt_pass == NULL) {
1040 sid_to_fstring(sidstr, sid);
1042 /* Bad (old) cred cache. Delete and pretend we
1044 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1046 wcache_delete("CRED/%s", sidstr);
1047 centry_free(centry);
1048 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1051 /* We only have 17 bytes more data in the salted cred case. */
1052 if (centry->len - centry->ofs == 17) {
1053 *cached_salt = (const uint8 *)centry_hash16(centry, mem_ctx);
1055 *cached_salt = NULL;
1058 dump_data_pw("cached_nt_pass", *cached_nt_pass, NT_HASH_LEN);
1060 dump_data_pw("cached_salt", *cached_salt, NT_HASH_LEN);
1063 status = centry->status;
1065 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1066 sid_string_dbg(sid), nt_errstr(status) ));
1068 centry_free(centry);
1072 /* Store creds for a SID - only writes out new salted ones. */
1074 NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
1075 TALLOC_CTX *mem_ctx,
1077 const uint8 nt_pass[NT_HASH_LEN])
1079 struct cache_entry *centry;
1082 uint8 cred_salt[NT_HASH_LEN];
1083 uint8 salted_hash[NT_HASH_LEN];
1085 if (is_null_sid(sid)) {
1086 return NT_STATUS_INVALID_SID;
1089 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1090 return NT_STATUS_INVALID_SID;
1093 centry = centry_start(domain, NT_STATUS_OK);
1095 return NT_STATUS_INTERNAL_DB_ERROR;
1098 dump_data_pw("nt_pass", nt_pass, NT_HASH_LEN);
1100 centry_put_time(centry, time(NULL));
1102 /* Create a salt and then salt the hash. */
1103 generate_random_buffer(cred_salt, NT_HASH_LEN);
1104 E_md5hash(cred_salt, nt_pass, salted_hash);
1106 centry_put_hash16(centry, salted_hash);
1107 centry_put_hash16(centry, cred_salt);
1108 centry_end(centry, "CRED/%s", sid_to_fstring(sid_string, sid));
1110 DEBUG(10,("wcache_save_creds: %s\n", sid_string));
1112 centry_free(centry);
1114 return NT_STATUS_OK;
1118 /* Query display info. This is the basic user list fn */
1119 static NTSTATUS query_user_list(struct winbindd_domain *domain,
1120 TALLOC_CTX *mem_ctx,
1121 uint32 *num_entries,
1122 WINBIND_USERINFO **info)
1124 struct winbind_cache *cache = get_cache(domain);
1125 struct cache_entry *centry = NULL;
1127 unsigned int i, retry;
1132 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1136 *num_entries = centry_uint32(centry);
1138 if (*num_entries == 0)
1141 (*info) = TALLOC_ARRAY(mem_ctx, WINBIND_USERINFO, *num_entries);
1143 smb_panic_fn("query_user_list out of memory");
1145 for (i=0; i<(*num_entries); i++) {
1146 (*info)[i].acct_name = centry_string(centry, mem_ctx);
1147 (*info)[i].full_name = centry_string(centry, mem_ctx);
1148 (*info)[i].homedir = centry_string(centry, mem_ctx);
1149 (*info)[i].shell = centry_string(centry, mem_ctx);
1150 centry_sid(centry, mem_ctx, &(*info)[i].user_sid);
1151 centry_sid(centry, mem_ctx, &(*info)[i].group_sid);
1155 status = centry->status;
1157 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1158 domain->name, nt_errstr(status) ));
1160 centry_free(centry);
1167 /* Return status value returned by seq number check */
1169 if (!NT_STATUS_IS_OK(domain->last_status))
1170 return domain->last_status;
1172 /* Put the query_user_list() in a retry loop. There appears to be
1173 * some bug either with Windows 2000 or Samba's handling of large
1174 * rpc replies. This manifests itself as sudden disconnection
1175 * at a random point in the enumeration of a large (60k) user list.
1176 * The retry loop simply tries the operation again. )-: It's not
1177 * pretty but an acceptable workaround until we work out what the
1178 * real problem is. */
1183 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1186 status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
1187 if (!NT_STATUS_IS_OK(status)) {
1188 DEBUG(3, ("query_user_list: returned 0x%08x, "
1189 "retrying\n", NT_STATUS_V(status)));
1191 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1192 DEBUG(3, ("query_user_list: flushing "
1193 "connection cache\n"));
1194 invalidate_cm_connection(&domain->conn);
1197 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
1201 refresh_sequence_number(domain, false);
1202 centry = centry_start(domain, status);
1205 centry_put_uint32(centry, *num_entries);
1206 for (i=0; i<(*num_entries); i++) {
1207 centry_put_string(centry, (*info)[i].acct_name);
1208 centry_put_string(centry, (*info)[i].full_name);
1209 centry_put_string(centry, (*info)[i].homedir);
1210 centry_put_string(centry, (*info)[i].shell);
1211 centry_put_sid(centry, &(*info)[i].user_sid);
1212 centry_put_sid(centry, &(*info)[i].group_sid);
1213 if (domain->backend && domain->backend->consistent) {
1214 /* when the backend is consistent we can pre-prime some mappings */
1215 wcache_save_name_to_sid(domain, NT_STATUS_OK,
1217 (*info)[i].acct_name,
1218 &(*info)[i].user_sid,
1220 wcache_save_sid_to_name(domain, NT_STATUS_OK,
1221 &(*info)[i].user_sid,
1223 (*info)[i].acct_name,
1225 wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
1228 centry_end(centry, "UL/%s", domain->name);
1229 centry_free(centry);
1235 /* list all domain groups */
1236 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
1237 TALLOC_CTX *mem_ctx,
1238 uint32 *num_entries,
1239 struct acct_info **info)
1241 struct winbind_cache *cache = get_cache(domain);
1242 struct cache_entry *centry = NULL;
1249 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1253 *num_entries = centry_uint32(centry);
1255 if (*num_entries == 0)
1258 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1260 smb_panic_fn("enum_dom_groups out of memory");
1262 for (i=0; i<(*num_entries); i++) {
1263 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1264 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1265 (*info)[i].rid = centry_uint32(centry);
1269 status = centry->status;
1271 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1272 domain->name, nt_errstr(status) ));
1274 centry_free(centry);
1281 /* Return status value returned by seq number check */
1283 if (!NT_STATUS_IS_OK(domain->last_status))
1284 return domain->last_status;
1286 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1289 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1292 refresh_sequence_number(domain, false);
1293 centry = centry_start(domain, status);
1296 centry_put_uint32(centry, *num_entries);
1297 for (i=0; i<(*num_entries); i++) {
1298 centry_put_string(centry, (*info)[i].acct_name);
1299 centry_put_string(centry, (*info)[i].acct_desc);
1300 centry_put_uint32(centry, (*info)[i].rid);
1302 centry_end(centry, "GL/%s/domain", domain->name);
1303 centry_free(centry);
1309 /* list all domain groups */
1310 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
1311 TALLOC_CTX *mem_ctx,
1312 uint32 *num_entries,
1313 struct acct_info **info)
1315 struct winbind_cache *cache = get_cache(domain);
1316 struct cache_entry *centry = NULL;
1323 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1327 *num_entries = centry_uint32(centry);
1329 if (*num_entries == 0)
1332 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1334 smb_panic_fn("enum_dom_groups out of memory");
1336 for (i=0; i<(*num_entries); i++) {
1337 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1338 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1339 (*info)[i].rid = centry_uint32(centry);
1344 /* If we are returning cached data and the domain controller
1345 is down then we don't know whether the data is up to date
1346 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1349 if (wcache_server_down(domain)) {
1350 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1351 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1353 status = centry->status;
1355 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1356 domain->name, nt_errstr(status) ));
1358 centry_free(centry);
1365 /* Return status value returned by seq number check */
1367 if (!NT_STATUS_IS_OK(domain->last_status))
1368 return domain->last_status;
1370 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1373 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1376 refresh_sequence_number(domain, false);
1377 centry = centry_start(domain, status);
1380 centry_put_uint32(centry, *num_entries);
1381 for (i=0; i<(*num_entries); i++) {
1382 centry_put_string(centry, (*info)[i].acct_name);
1383 centry_put_string(centry, (*info)[i].acct_desc);
1384 centry_put_uint32(centry, (*info)[i].rid);
1386 centry_end(centry, "GL/%s/local", domain->name);
1387 centry_free(centry);
1393 /* convert a single name to a sid in a domain */
1394 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
1395 TALLOC_CTX *mem_ctx,
1396 enum winbindd_cmd orig_cmd,
1397 const char *domain_name,
1400 enum lsa_SidType *type)
1402 struct winbind_cache *cache = get_cache(domain);
1403 struct cache_entry *centry = NULL;
1410 fstrcpy(uname, name);
1412 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1416 status = centry->status;
1417 if (NT_STATUS_IS_OK(status)) {
1418 *type = (enum lsa_SidType)centry_uint32(centry);
1419 centry_sid(centry, mem_ctx, sid);
1422 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: %s\n",
1423 domain->name, nt_errstr(status) ));
1425 centry_free(centry);
1431 /* If the seq number check indicated that there is a problem
1432 * with this DC, then return that status... except for
1433 * access_denied. This is special because the dc may be in
1434 * "restrict anonymous = 1" mode, in which case it will deny
1435 * most unauthenticated operations, but *will* allow the LSA
1436 * name-to-sid that we try as a fallback. */
1438 if (!(NT_STATUS_IS_OK(domain->last_status)
1439 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1440 return domain->last_status;
1442 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1445 status = domain->backend->name_to_sid(domain, mem_ctx, orig_cmd,
1446 domain_name, name, sid, type);
1449 refresh_sequence_number(domain, false);
1451 if (domain->online &&
1452 (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
1453 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1455 /* Only save the reverse mapping if this was not a UPN */
1456 if (!strchr(name, '@')) {
1457 strupper_m(CONST_DISCARD(char *,domain_name));
1458 strlower_m(CONST_DISCARD(char *,name));
1459 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1466 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1468 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
1469 TALLOC_CTX *mem_ctx,
1473 enum lsa_SidType *type)
1475 struct winbind_cache *cache = get_cache(domain);
1476 struct cache_entry *centry = NULL;
1483 centry = wcache_fetch(cache, domain, "SN/%s",
1484 sid_to_fstring(sid_string, sid));
1488 status = centry->status;
1489 if (NT_STATUS_IS_OK(status)) {
1490 *type = (enum lsa_SidType)centry_uint32(centry);
1491 *domain_name = centry_string(centry, mem_ctx);
1492 *name = centry_string(centry, mem_ctx);
1495 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: %s\n",
1496 domain->name, nt_errstr(status) ));
1498 centry_free(centry);
1503 *domain_name = NULL;
1505 /* If the seq number check indicated that there is a problem
1506 * with this DC, then return that status... except for
1507 * access_denied. This is special because the dc may be in
1508 * "restrict anonymous = 1" mode, in which case it will deny
1509 * most unauthenticated operations, but *will* allow the LSA
1510 * sid-to-name that we try as a fallback. */
1512 if (!(NT_STATUS_IS_OK(domain->last_status)
1513 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1514 return domain->last_status;
1516 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1519 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1522 refresh_sequence_number(domain, false);
1523 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1525 /* We can't save the name to sid mapping here, as with sid history a
1526 * later name2sid would give the wrong sid. */
1531 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
1532 TALLOC_CTX *mem_ctx,
1533 const DOM_SID *domain_sid,
1538 enum lsa_SidType **types)
1540 struct winbind_cache *cache = get_cache(domain);
1542 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1546 *domain_name = NULL;
1554 if (num_rids == 0) {
1555 return NT_STATUS_OK;
1558 *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
1559 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
1561 if ((*names == NULL) || (*types == NULL)) {
1562 result = NT_STATUS_NO_MEMORY;
1566 have_mapped = have_unmapped = false;
1568 for (i=0; i<num_rids; i++) {
1570 struct cache_entry *centry;
1573 if (!sid_compose(&sid, domain_sid, rids[i])) {
1574 result = NT_STATUS_INTERNAL_ERROR;
1578 centry = wcache_fetch(cache, domain, "SN/%s",
1579 sid_to_fstring(tmp, &sid));
1584 (*types)[i] = SID_NAME_UNKNOWN;
1585 (*names)[i] = talloc_strdup(*names, "");
1587 if (NT_STATUS_IS_OK(centry->status)) {
1590 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
1592 dom = centry_string(centry, mem_ctx);
1593 if (*domain_name == NULL) {
1599 (*names)[i] = centry_string(centry, *names);
1601 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
1602 have_unmapped = true;
1605 /* something's definitely wrong */
1606 result = centry->status;
1610 centry_free(centry);
1614 return NT_STATUS_NONE_MAPPED;
1616 if (!have_unmapped) {
1617 return NT_STATUS_OK;
1619 return STATUS_SOME_UNMAPPED;
1623 TALLOC_FREE(*names);
1624 TALLOC_FREE(*types);
1626 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
1627 rids, num_rids, domain_name,
1631 None of the queried rids has been found so save all negative entries
1633 if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
1634 for (i = 0; i < num_rids; i++) {
1636 const char *name = "";
1637 const enum lsa_SidType type = SID_NAME_UNKNOWN;
1638 NTSTATUS status = NT_STATUS_NONE_MAPPED;
1640 if (!sid_compose(&sid, domain_sid, rids[i])) {
1641 return NT_STATUS_INTERNAL_ERROR;
1644 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
1652 Some or all of the queried rids have been found.
1654 if (!NT_STATUS_IS_OK(result) &&
1655 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
1659 refresh_sequence_number(domain, false);
1661 for (i=0; i<num_rids; i++) {
1665 if (!sid_compose(&sid, domain_sid, rids[i])) {
1666 result = NT_STATUS_INTERNAL_ERROR;
1670 status = (*types)[i] == SID_NAME_UNKNOWN ?
1671 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
1673 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
1674 (*names)[i], (*types)[i]);
1681 TALLOC_FREE(*names);
1682 TALLOC_FREE(*types);
1686 /* Lookup user information from a rid */
1687 static NTSTATUS query_user(struct winbindd_domain *domain,
1688 TALLOC_CTX *mem_ctx,
1689 const DOM_SID *user_sid,
1690 WINBIND_USERINFO *info)
1692 struct winbind_cache *cache = get_cache(domain);
1693 struct cache_entry *centry = NULL;
1700 centry = wcache_fetch(cache, domain, "U/%s",
1701 sid_to_fstring(tmp, user_sid));
1703 /* If we have an access denied cache entry and a cached info3 in the
1704 samlogon cache then do a query. This will force the rpc back end
1705 to return the info3 data. */
1707 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1708 netsamlogon_cache_have(user_sid)) {
1709 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1710 domain->last_status = NT_STATUS_OK;
1711 centry_free(centry);
1718 /* if status is not ok then this is a negative hit
1719 and the rest of the data doesn't matter */
1720 status = centry->status;
1721 if (NT_STATUS_IS_OK(status)) {
1722 info->acct_name = centry_string(centry, mem_ctx);
1723 info->full_name = centry_string(centry, mem_ctx);
1724 info->homedir = centry_string(centry, mem_ctx);
1725 info->shell = centry_string(centry, mem_ctx);
1726 info->primary_gid = centry_uint32(centry);
1727 centry_sid(centry, mem_ctx, &info->user_sid);
1728 centry_sid(centry, mem_ctx, &info->group_sid);
1731 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: %s\n",
1732 domain->name, nt_errstr(status) ));
1734 centry_free(centry);
1740 /* Return status value returned by seq number check */
1742 if (!NT_STATUS_IS_OK(domain->last_status))
1743 return domain->last_status;
1745 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
1748 status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
1751 refresh_sequence_number(domain, false);
1752 wcache_save_user(domain, status, info);
1758 /* Lookup groups a user is a member of. */
1759 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
1760 TALLOC_CTX *mem_ctx,
1761 const DOM_SID *user_sid,
1762 uint32 *num_groups, DOM_SID **user_gids)
1764 struct winbind_cache *cache = get_cache(domain);
1765 struct cache_entry *centry = NULL;
1773 centry = wcache_fetch(cache, domain, "UG/%s",
1774 sid_to_fstring(sid_string, user_sid));
1776 /* If we have an access denied cache entry and a cached info3 in the
1777 samlogon cache then do a query. This will force the rpc back end
1778 to return the info3 data. */
1780 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1781 netsamlogon_cache_have(user_sid)) {
1782 DEBUG(10, ("lookup_usergroups: cached access denied and have cached info3\n"));
1783 domain->last_status = NT_STATUS_OK;
1784 centry_free(centry);
1791 *num_groups = centry_uint32(centry);
1793 if (*num_groups == 0)
1796 (*user_gids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
1797 if (! (*user_gids)) {
1798 smb_panic_fn("lookup_usergroups out of memory");
1800 for (i=0; i<(*num_groups); i++) {
1801 centry_sid(centry, mem_ctx, &(*user_gids)[i]);
1805 status = centry->status;
1807 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status: %s\n",
1808 domain->name, nt_errstr(status) ));
1810 centry_free(centry);
1815 (*user_gids) = NULL;
1817 /* Return status value returned by seq number check */
1819 if (!NT_STATUS_IS_OK(domain->last_status))
1820 return domain->last_status;
1822 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
1825 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
1827 if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
1831 refresh_sequence_number(domain, false);
1832 centry = centry_start(domain, status);
1836 centry_put_uint32(centry, *num_groups);
1837 for (i=0; i<(*num_groups); i++) {
1838 centry_put_sid(centry, &(*user_gids)[i]);
1841 centry_end(centry, "UG/%s", sid_to_fstring(sid_string, user_sid));
1842 centry_free(centry);
1848 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
1849 TALLOC_CTX *mem_ctx,
1850 uint32 num_sids, const DOM_SID *sids,
1851 uint32 *num_aliases, uint32 **alias_rids)
1853 struct winbind_cache *cache = get_cache(domain);
1854 struct cache_entry *centry = NULL;
1856 char *sidlist = talloc_strdup(mem_ctx, "");
1862 if (num_sids == 0) {
1865 return NT_STATUS_OK;
1868 /* We need to cache indexed by the whole list of SIDs, the aliases
1869 * resulting might come from any of the SIDs. */
1871 for (i=0; i<num_sids; i++) {
1873 sidlist = talloc_asprintf(mem_ctx, "%s/%s", sidlist,
1874 sid_to_fstring(tmp, &sids[i]));
1875 if (sidlist == NULL)
1876 return NT_STATUS_NO_MEMORY;
1879 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
1884 *num_aliases = centry_uint32(centry);
1888 (*alias_rids) = TALLOC_ARRAY(mem_ctx, uint32, *num_aliases);
1890 if ((*alias_rids) == NULL) {
1891 centry_free(centry);
1892 return NT_STATUS_NO_MEMORY;
1895 (*alias_rids) = NULL;
1898 for (i=0; i<(*num_aliases); i++)
1899 (*alias_rids)[i] = centry_uint32(centry);
1901 status = centry->status;
1903 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
1904 "status %s\n", domain->name, nt_errstr(status)));
1906 centry_free(centry);
1911 (*alias_rids) = NULL;
1913 if (!NT_STATUS_IS_OK(domain->last_status))
1914 return domain->last_status;
1916 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
1917 "for domain %s\n", domain->name ));
1919 status = domain->backend->lookup_useraliases(domain, mem_ctx,
1921 num_aliases, alias_rids);
1924 refresh_sequence_number(domain, false);
1925 centry = centry_start(domain, status);
1928 centry_put_uint32(centry, *num_aliases);
1929 for (i=0; i<(*num_aliases); i++)
1930 centry_put_uint32(centry, (*alias_rids)[i]);
1931 centry_end(centry, "UA%s", sidlist);
1932 centry_free(centry);
1939 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1940 TALLOC_CTX *mem_ctx,
1941 const DOM_SID *group_sid, uint32 *num_names,
1942 DOM_SID **sid_mem, char ***names,
1943 uint32 **name_types)
1945 struct winbind_cache *cache = get_cache(domain);
1946 struct cache_entry *centry = NULL;
1954 centry = wcache_fetch(cache, domain, "GM/%s",
1955 sid_to_fstring(sid_string, group_sid));
1959 *num_names = centry_uint32(centry);
1961 if (*num_names == 0)
1964 (*sid_mem) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_names);
1965 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_names);
1966 (*name_types) = TALLOC_ARRAY(mem_ctx, uint32, *num_names);
1968 if (! (*sid_mem) || ! (*names) || ! (*name_types)) {
1969 smb_panic_fn("lookup_groupmem out of memory");
1972 for (i=0; i<(*num_names); i++) {
1973 centry_sid(centry, mem_ctx, &(*sid_mem)[i]);
1974 (*names)[i] = centry_string(centry, mem_ctx);
1975 (*name_types)[i] = centry_uint32(centry);
1979 status = centry->status;
1981 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status: %s\n",
1982 domain->name, nt_errstr(status)));
1984 centry_free(centry);
1991 (*name_types) = NULL;
1993 /* Return status value returned by seq number check */
1995 if (!NT_STATUS_IS_OK(domain->last_status))
1996 return domain->last_status;
1998 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2001 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid, num_names,
2002 sid_mem, names, name_types);
2005 refresh_sequence_number(domain, false);
2006 centry = centry_start(domain, status);
2009 centry_put_uint32(centry, *num_names);
2010 for (i=0; i<(*num_names); i++) {
2011 centry_put_sid(centry, &(*sid_mem)[i]);
2012 centry_put_string(centry, (*names)[i]);
2013 centry_put_uint32(centry, (*name_types)[i]);
2015 centry_end(centry, "GM/%s", sid_to_fstring(sid_string, group_sid));
2016 centry_free(centry);
2022 /* find the sequence number for a domain */
2023 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
2025 refresh_sequence_number(domain, false);
2027 *seq = domain->sequence_number;
2029 return NT_STATUS_OK;
2032 /* enumerate trusted domains
2033 * (we need to have the list of trustdoms in the cache when we go offline) -
2035 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
2036 TALLOC_CTX *mem_ctx,
2037 uint32 *num_domains,
2042 struct winbind_cache *cache = get_cache(domain);
2043 struct cache_entry *centry = NULL;
2050 centry = wcache_fetch(cache, domain, "TRUSTDOMS/%s", domain->name);
2056 *num_domains = centry_uint32(centry);
2059 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
2060 (*alt_names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
2061 (*dom_sids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
2063 if (! (*dom_sids) || ! (*names) || ! (*alt_names)) {
2064 smb_panic_fn("trusted_domains out of memory");
2068 (*alt_names) = NULL;
2072 for (i=0; i<(*num_domains); i++) {
2073 (*names)[i] = centry_string(centry, mem_ctx);
2074 (*alt_names)[i] = centry_string(centry, mem_ctx);
2075 if (!centry_sid(centry, mem_ctx, &(*dom_sids)[i])) {
2076 sid_copy(&(*dom_sids)[i], &global_sid_NULL);
2080 status = centry->status;
2082 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
2083 domain->name, *num_domains, nt_errstr(status) ));
2085 centry_free(centry);
2092 (*alt_names) = NULL;
2094 /* Return status value returned by seq number check */
2096 if (!NT_STATUS_IS_OK(domain->last_status))
2097 return domain->last_status;
2099 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2102 status = domain->backend->trusted_domains(domain, mem_ctx, num_domains,
2103 names, alt_names, dom_sids);
2105 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2106 * so that the generic centry handling still applies correctly -
2109 if (!NT_STATUS_IS_ERR(status)) {
2110 status = NT_STATUS_OK;
2114 #if 0 /* Disabled as we want the trust dom list to be managed by
2115 the main parent and always to make the query. --jerry */
2118 refresh_sequence_number(domain, false);
2120 centry = centry_start(domain, status);
2124 centry_put_uint32(centry, *num_domains);
2126 for (i=0; i<(*num_domains); i++) {
2127 centry_put_string(centry, (*names)[i]);
2128 centry_put_string(centry, (*alt_names)[i]);
2129 centry_put_sid(centry, &(*dom_sids)[i]);
2132 centry_end(centry, "TRUSTDOMS/%s", domain->name);
2134 centry_free(centry);
2142 /* get lockout policy */
2143 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
2144 TALLOC_CTX *mem_ctx,
2145 struct samr_DomInfo12 *policy)
2147 struct winbind_cache *cache = get_cache(domain);
2148 struct cache_entry *centry = NULL;
2154 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2159 policy->lockout_duration = centry_nttime(centry);
2160 policy->lockout_window = centry_nttime(centry);
2161 policy->lockout_threshold = centry_uint16(centry);
2163 status = centry->status;
2165 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2166 domain->name, nt_errstr(status) ));
2168 centry_free(centry);
2172 ZERO_STRUCTP(policy);
2174 /* Return status value returned by seq number check */
2176 if (!NT_STATUS_IS_OK(domain->last_status))
2177 return domain->last_status;
2179 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2182 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2185 refresh_sequence_number(domain, false);
2186 wcache_save_lockout_policy(domain, status, policy);
2191 /* get password policy */
2192 static NTSTATUS password_policy(struct winbindd_domain *domain,
2193 TALLOC_CTX *mem_ctx,
2194 struct samr_DomInfo1 *policy)
2196 struct winbind_cache *cache = get_cache(domain);
2197 struct cache_entry *centry = NULL;
2203 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2208 policy->min_password_length = centry_uint16(centry);
2209 policy->password_history_length = centry_uint16(centry);
2210 policy->password_properties = centry_uint32(centry);
2211 policy->max_password_age = centry_nttime(centry);
2212 policy->min_password_age = centry_nttime(centry);
2214 status = centry->status;
2216 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2217 domain->name, nt_errstr(status) ));
2219 centry_free(centry);
2223 ZERO_STRUCTP(policy);
2225 /* Return status value returned by seq number check */
2227 if (!NT_STATUS_IS_OK(domain->last_status))
2228 return domain->last_status;
2230 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2233 status = domain->backend->password_policy(domain, mem_ctx, policy);
2236 refresh_sequence_number(domain, false);
2237 if (NT_STATUS_IS_OK(status)) {
2238 wcache_save_password_policy(domain, status, policy);
2245 /* Invalidate cached user and group lists coherently */
2247 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2250 if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
2251 strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
2252 tdb_delete(the_tdb, kbuf);
2257 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2259 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
2260 struct netr_SamInfo3 *info3)
2262 struct winbind_cache *cache;
2264 /* dont clear cached U/SID and UG/SID entries when we want to logon
2267 if (lp_winbind_offline_logon()) {
2274 cache = get_cache(domain);
2275 netsamlogon_clear_cached_user(cache->tdb, info3);
2278 bool wcache_invalidate_cache(void)
2280 struct winbindd_domain *domain;
2282 for (domain = domain_list(); domain; domain = domain->next) {
2283 struct winbind_cache *cache = get_cache(domain);
2285 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2286 "entries for %s\n", domain->name));
2289 tdb_traverse(cache->tdb, traverse_fn, NULL);
2298 bool init_wcache(void)
2300 if (wcache == NULL) {
2301 wcache = SMB_XMALLOC_P(struct winbind_cache);
2302 ZERO_STRUCTP(wcache);
2305 if (wcache->tdb != NULL)
2308 /* when working offline we must not clear the cache on restart */
2309 wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
2310 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2311 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
2312 O_RDWR|O_CREAT, 0600);
2314 if (wcache->tdb == NULL) {
2315 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2322 /************************************************************************
2323 This is called by the parent to initialize the cache file.
2324 We don't need sophisticated locking here as we know we're the
2326 ************************************************************************/
2328 bool initialize_winbindd_cache(void)
2330 bool cache_bad = true;
2333 if (!init_wcache()) {
2334 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
2338 /* Check version number. */
2339 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
2340 vers == WINBINDD_CACHE_VERSION) {
2345 DEBUG(0,("initialize_winbindd_cache: clearing cache "
2346 "and re-creating with version number %d\n",
2347 WINBINDD_CACHE_VERSION ));
2349 tdb_close(wcache->tdb);
2352 if (unlink(lock_path("winbindd_cache.tdb")) == -1) {
2353 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
2354 lock_path("winbindd_cache.tdb"),
2358 if (!init_wcache()) {
2359 DEBUG(0,("initialize_winbindd_cache: re-initialization "
2360 "init_wcache failed.\n"));
2364 /* Write the version. */
2365 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
2366 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
2367 tdb_errorstr(wcache->tdb) ));
2372 tdb_close(wcache->tdb);
2377 void close_winbindd_cache(void)
2383 tdb_close(wcache->tdb);
2388 void cache_store_response(pid_t pid, struct winbindd_response *response)
2395 DEBUG(10, ("Storing response for pid %d, len %d\n",
2396 pid, response->length));
2398 fstr_sprintf(key_str, "DR/%d", pid);
2399 if (tdb_store(wcache->tdb, string_tdb_data(key_str),
2400 make_tdb_data((uint8 *)response, sizeof(*response)),
2404 if (response->length == sizeof(*response))
2407 /* There's extra data */
2409 DEBUG(10, ("Storing extra data: len=%d\n",
2410 (int)(response->length - sizeof(*response))));
2412 fstr_sprintf(key_str, "DE/%d", pid);
2413 if (tdb_store(wcache->tdb, string_tdb_data(key_str),
2414 make_tdb_data((uint8 *)response->extra_data.data,
2415 response->length - sizeof(*response)),
2419 /* We could not store the extra data, make sure the tdb does not
2420 * contain a main record with wrong dangling extra data */
2422 fstr_sprintf(key_str, "DR/%d", pid);
2423 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2428 bool cache_retrieve_response(pid_t pid, struct winbindd_response * response)
2436 DEBUG(10, ("Retrieving response for pid %d\n", pid));
2438 fstr_sprintf(key_str, "DR/%d", pid);
2439 data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
2441 if (data.dptr == NULL)
2444 if (data.dsize != sizeof(*response))
2447 memcpy(response, data.dptr, data.dsize);
2448 SAFE_FREE(data.dptr);
2450 if (response->length == sizeof(*response)) {
2451 response->extra_data.data = NULL;
2455 /* There's extra data */
2457 DEBUG(10, ("Retrieving extra data length=%d\n",
2458 (int)(response->length - sizeof(*response))));
2460 fstr_sprintf(key_str, "DE/%d", pid);
2461 data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
2463 if (data.dptr == NULL) {
2464 DEBUG(0, ("Did not find extra data\n"));
2468 if (data.dsize != (response->length - sizeof(*response))) {
2469 DEBUG(0, ("Invalid extra data length: %d\n", (int)data.dsize));
2470 SAFE_FREE(data.dptr);
2474 dump_data(11, (uint8 *)data.dptr, data.dsize);
2476 response->extra_data.data = data.dptr;
2480 void cache_cleanup_response(pid_t pid)
2487 fstr_sprintf(key_str, "DR/%d", pid);
2488 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2490 fstr_sprintf(key_str, "DE/%d", pid);
2491 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2497 bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
2498 char **domain_name, char **name,
2499 enum lsa_SidType *type)
2501 struct winbindd_domain *domain;
2502 struct winbind_cache *cache;
2503 struct cache_entry *centry = NULL;
2507 domain = find_lookup_domain_from_sid(sid);
2508 if (domain == NULL) {
2512 cache = get_cache(domain);
2514 if (cache->tdb == NULL) {
2518 centry = wcache_fetch(cache, domain, "SN/%s",
2519 sid_to_fstring(tmp, sid));
2520 if (centry == NULL) {
2524 if (NT_STATUS_IS_OK(centry->status)) {
2525 *type = (enum lsa_SidType)centry_uint32(centry);
2526 *domain_name = centry_string(centry, mem_ctx);
2527 *name = centry_string(centry, mem_ctx);
2530 status = centry->status;
2531 centry_free(centry);
2532 return NT_STATUS_IS_OK(status);
2535 bool lookup_cached_name(TALLOC_CTX *mem_ctx,
2536 const char *domain_name,
2539 enum lsa_SidType *type)
2541 struct winbindd_domain *domain;
2542 struct winbind_cache *cache;
2543 struct cache_entry *centry = NULL;
2546 bool original_online_state;
2548 domain = find_lookup_domain_from_name(domain_name);
2549 if (domain == NULL) {
2553 cache = get_cache(domain);
2555 if (cache->tdb == NULL) {
2559 fstrcpy(uname, name);
2562 /* If we are doing a cached logon, temporarily set the domain
2563 offline so the cache won't expire the entry */
2565 original_online_state = domain->online;
2566 domain->online = false;
2567 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
2568 domain->online = original_online_state;
2570 if (centry == NULL) {
2574 if (NT_STATUS_IS_OK(centry->status)) {
2575 *type = (enum lsa_SidType)centry_uint32(centry);
2576 centry_sid(centry, mem_ctx, sid);
2579 status = centry->status;
2580 centry_free(centry);
2582 return NT_STATUS_IS_OK(status);
2585 void cache_name2sid(struct winbindd_domain *domain,
2586 const char *domain_name, const char *name,
2587 enum lsa_SidType type, const DOM_SID *sid)
2589 refresh_sequence_number(domain, false);
2590 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
2595 * The original idea that this cache only contains centries has
2596 * been blurred - now other stuff gets put in here. Ensure we
2597 * ignore these things on cleanup.
2600 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
2601 TDB_DATA dbuf, void *state)
2603 struct cache_entry *centry;
2605 if (is_non_centry_key(kbuf)) {
2609 centry = wcache_fetch_raw((char *)kbuf.dptr);
2614 if (!NT_STATUS_IS_OK(centry->status)) {
2615 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
2616 tdb_delete(the_tdb, kbuf);
2619 centry_free(centry);
2623 /* flush the cache */
2624 void wcache_flush_cache(void)
2629 tdb_close(wcache->tdb);
2635 /* when working offline we must not clear the cache on restart */
2636 wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
2637 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2638 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
2639 O_RDWR|O_CREAT, 0600);
2642 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2646 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
2648 DEBUG(10,("wcache_flush_cache success\n"));
2651 /* Count cached creds */
2653 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2656 int *cred_count = (int*)state;
2658 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
2664 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
2666 struct winbind_cache *cache = get_cache(domain);
2671 return NT_STATUS_INTERNAL_DB_ERROR;
2674 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
2676 return NT_STATUS_OK;
2680 struct cred_list *prev, *next;
2685 static struct cred_list *wcache_cred_list;
2687 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2690 struct cred_list *cred;
2692 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
2694 cred = SMB_MALLOC_P(struct cred_list);
2696 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2702 /* save a copy of the key */
2704 fstrcpy(cred->name, (const char *)kbuf.dptr);
2705 DLIST_ADD(wcache_cred_list, cred);
2711 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const DOM_SID *sid)
2713 struct winbind_cache *cache = get_cache(domain);
2716 struct cred_list *cred, *oldest = NULL;
2719 return NT_STATUS_INTERNAL_DB_ERROR;
2722 /* we possibly already have an entry */
2723 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
2725 fstring key_str, tmp;
2727 DEBUG(11,("we already have an entry, deleting that\n"));
2729 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
2731 tdb_delete(cache->tdb, string_tdb_data(key_str));
2733 return NT_STATUS_OK;
2736 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
2738 return NT_STATUS_OK;
2739 } else if ((ret == -1) || (wcache_cred_list == NULL)) {
2740 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2743 ZERO_STRUCTP(oldest);
2745 for (cred = wcache_cred_list; cred; cred = cred->next) {
2750 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
2752 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
2754 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
2758 t = IVAL(data.dptr, 0);
2759 SAFE_FREE(data.dptr);
2762 oldest = SMB_MALLOC_P(struct cred_list);
2763 if (oldest == NULL) {
2764 status = NT_STATUS_NO_MEMORY;
2768 fstrcpy(oldest->name, cred->name);
2769 oldest->created = t;
2773 if (t < oldest->created) {
2774 fstrcpy(oldest->name, cred->name);
2775 oldest->created = t;
2779 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
2780 status = NT_STATUS_OK;
2782 status = NT_STATUS_UNSUCCESSFUL;
2785 SAFE_FREE(wcache_cred_list);
2791 /* Change the global online/offline state. */
2792 bool set_global_winbindd_state_offline(void)
2796 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
2798 /* Only go offline if someone has created
2799 the key "WINBINDD_OFFLINE" in the cache tdb. */
2801 if (wcache == NULL || wcache->tdb == NULL) {
2802 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
2806 if (!lp_winbind_offline_logon()) {
2807 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
2811 if (global_winbindd_offline_state) {
2812 /* Already offline. */
2816 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
2818 if (!data.dptr || data.dsize != 4) {
2819 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
2820 SAFE_FREE(data.dptr);
2823 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
2824 global_winbindd_offline_state = true;
2825 SAFE_FREE(data.dptr);
2830 void set_global_winbindd_state_online(void)
2832 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
2834 if (!lp_winbind_offline_logon()) {
2835 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
2839 if (!global_winbindd_offline_state) {
2840 /* Already online. */
2843 global_winbindd_offline_state = false;
2849 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
2850 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
2853 bool get_global_winbindd_state_offline(void)
2855 return global_winbindd_offline_state;
2858 /***********************************************************************
2859 Validate functions for all possible cache tdb keys.
2860 ***********************************************************************/
2862 static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
2863 struct tdb_validation_status *state)
2865 struct cache_entry *centry;
2867 centry = SMB_XMALLOC_P(struct cache_entry);
2868 centry->data = (unsigned char *)memdup(data.dptr, data.dsize);
2869 if (!centry->data) {
2873 centry->len = data.dsize;
2876 if (centry->len < 8) {
2877 /* huh? corrupt cache? */
2878 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr));
2879 centry_free(centry);
2880 state->bad_entry = true;
2881 state->success = false;
2885 centry->status = NT_STATUS(centry_uint32(centry));
2886 centry->sequence_number = centry_uint32(centry);
2890 static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2891 struct tdb_validation_status *state)
2893 if (dbuf.dsize != 8) {
2894 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
2895 keystr, (unsigned int)dbuf.dsize ));
2896 state->bad_entry = true;
2902 static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2903 struct tdb_validation_status *state)
2905 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2910 (void)centry_uint32(centry);
2911 if (NT_STATUS_IS_OK(centry->status)) {
2913 (void)centry_sid(centry, mem_ctx, &sid);
2916 centry_free(centry);
2918 if (!(state->success)) {
2921 DEBUG(10,("validate_ns: %s ok\n", keystr));
2925 static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2926 struct tdb_validation_status *state)
2928 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2933 if (NT_STATUS_IS_OK(centry->status)) {
2934 (void)centry_uint32(centry);
2935 (void)centry_string(centry, mem_ctx);
2936 (void)centry_string(centry, mem_ctx);
2939 centry_free(centry);
2941 if (!(state->success)) {
2944 DEBUG(10,("validate_sn: %s ok\n", keystr));
2948 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2949 struct tdb_validation_status *state)
2951 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2958 (void)centry_string(centry, mem_ctx);
2959 (void)centry_string(centry, mem_ctx);
2960 (void)centry_string(centry, mem_ctx);
2961 (void)centry_string(centry, mem_ctx);
2962 (void)centry_uint32(centry);
2963 (void)centry_sid(centry, mem_ctx, &sid);
2964 (void)centry_sid(centry, mem_ctx, &sid);
2966 centry_free(centry);
2968 if (!(state->success)) {
2971 DEBUG(10,("validate_u: %s ok\n", keystr));
2975 static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2976 struct tdb_validation_status *state)
2978 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2984 (void)centry_nttime(centry);
2985 (void)centry_nttime(centry);
2986 (void)centry_uint16(centry);
2988 centry_free(centry);
2990 if (!(state->success)) {
2993 DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
2997 static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2998 struct tdb_validation_status *state)
3000 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3006 (void)centry_uint16(centry);
3007 (void)centry_uint16(centry);
3008 (void)centry_uint32(centry);
3009 (void)centry_nttime(centry);
3010 (void)centry_nttime(centry);
3012 centry_free(centry);
3014 if (!(state->success)) {
3017 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
3021 static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3022 struct tdb_validation_status *state)
3024 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3030 (void)centry_time(centry);
3031 (void)centry_hash16(centry, mem_ctx);
3033 /* We only have 17 bytes more data in the salted cred case. */
3034 if (centry->len - centry->ofs == 17) {
3035 (void)centry_hash16(centry, mem_ctx);
3038 centry_free(centry);
3040 if (!(state->success)) {
3043 DEBUG(10,("validate_cred: %s ok\n", keystr));
3047 static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3048 struct tdb_validation_status *state)
3050 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3051 int32 num_entries, i;
3057 num_entries = (int32)centry_uint32(centry);
3059 for (i=0; i< num_entries; i++) {
3061 (void)centry_string(centry, mem_ctx);
3062 (void)centry_string(centry, mem_ctx);
3063 (void)centry_string(centry, mem_ctx);
3064 (void)centry_string(centry, mem_ctx);
3065 (void)centry_sid(centry, mem_ctx, &sid);
3066 (void)centry_sid(centry, mem_ctx, &sid);
3069 centry_free(centry);
3071 if (!(state->success)) {
3074 DEBUG(10,("validate_ul: %s ok\n", keystr));
3078 static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3079 struct tdb_validation_status *state)
3081 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3082 int32 num_entries, i;
3088 num_entries = centry_uint32(centry);
3090 for (i=0; i< num_entries; i++) {
3091 (void)centry_string(centry, mem_ctx);
3092 (void)centry_string(centry, mem_ctx);
3093 (void)centry_uint32(centry);
3096 centry_free(centry);
3098 if (!(state->success)) {
3101 DEBUG(10,("validate_gl: %s ok\n", keystr));
3105 static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3106 struct tdb_validation_status *state)
3108 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3109 int32 num_groups, i;
3115 num_groups = centry_uint32(centry);
3117 for (i=0; i< num_groups; i++) {
3119 centry_sid(centry, mem_ctx, &sid);
3122 centry_free(centry);
3124 if (!(state->success)) {
3127 DEBUG(10,("validate_ug: %s ok\n", keystr));
3131 static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3132 struct tdb_validation_status *state)
3134 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3135 int32 num_aliases, i;
3141 num_aliases = centry_uint32(centry);
3143 for (i=0; i < num_aliases; i++) {
3144 (void)centry_uint32(centry);
3147 centry_free(centry);
3149 if (!(state->success)) {
3152 DEBUG(10,("validate_ua: %s ok\n", keystr));
3156 static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3157 struct tdb_validation_status *state)
3159 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3166 num_names = centry_uint32(centry);
3168 for (i=0; i< num_names; i++) {
3170 centry_sid(centry, mem_ctx, &sid);
3171 (void)centry_string(centry, mem_ctx);
3172 (void)centry_uint32(centry);
3175 centry_free(centry);
3177 if (!(state->success)) {
3180 DEBUG(10,("validate_gm: %s ok\n", keystr));
3184 static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3185 struct tdb_validation_status *state)
3187 /* Can't say anything about this other than must be nonzero. */
3188 if (dbuf.dsize == 0) {
3189 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3191 state->bad_entry = true;
3192 state->success = false;
3196 DEBUG(10,("validate_dr: %s ok\n", keystr));
3200 static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3201 struct tdb_validation_status *state)
3203 /* Can't say anything about this other than must be nonzero. */
3204 if (dbuf.dsize == 0) {
3205 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3207 state->bad_entry = true;
3208 state->success = false;
3212 DEBUG(10,("validate_de: %s ok\n", keystr));
3216 static int validate_pwinfo(TALLOC_CTX *mem_ctx, const char *keystr,
3217 TDB_DATA dbuf, struct tdb_validation_status *state)
3219 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3225 (void)centry_string(centry, mem_ctx);
3226 (void)centry_string(centry, mem_ctx);
3227 (void)centry_string(centry, mem_ctx);
3228 (void)centry_uint32(centry);
3230 centry_free(centry);
3232 if (!(state->success)) {
3235 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3239 static int validate_trustdoms(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3240 struct tdb_validation_status *state)
3242 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3243 int32 num_domains, i;
3249 num_domains = centry_uint32(centry);
3251 for (i=0; i< num_domains; i++) {
3253 (void)centry_string(centry, mem_ctx);
3254 (void)centry_string(centry, mem_ctx);
3255 (void)centry_sid(centry, mem_ctx, &sid);
3258 centry_free(centry);
3260 if (!(state->success)) {
3263 DEBUG(10,("validate_trustdoms: %s ok\n", keystr));
3267 static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
3269 struct tdb_validation_status *state)
3271 if (dbuf.dsize == 0) {
3272 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3273 "key %s (len ==0) ?\n", keystr));
3274 state->bad_entry = true;
3275 state->success = false;
3279 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
3280 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3284 static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3285 struct tdb_validation_status *state)
3287 if (dbuf.dsize != 4) {
3288 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3289 keystr, (unsigned int)dbuf.dsize ));
3290 state->bad_entry = true;
3291 state->success = false;
3294 DEBUG(10,("validate_offline: %s ok\n", keystr));
3298 static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3299 struct tdb_validation_status *state)
3301 if (dbuf.dsize != 4) {
3302 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3303 "key %s (len %u != 4) ?\n",
3304 keystr, (unsigned int)dbuf.dsize));
3305 state->bad_entry = true;
3306 state->success = false;
3310 DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
3314 /***********************************************************************
3315 A list of all possible cache tdb keys with associated validation
3317 ***********************************************************************/
3319 struct key_val_struct {
3320 const char *keyname;
3321 int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
3323 {"SEQNUM/", validate_seqnum},
3324 {"NS/", validate_ns},
3325 {"SN/", validate_sn},
3327 {"LOC_POL/", validate_loc_pol},
3328 {"PWD_POL/", validate_pwd_pol},
3329 {"CRED/", validate_cred},
3330 {"UL/", validate_ul},
3331 {"GL/", validate_gl},
3332 {"UG/", validate_ug},
3333 {"UA", validate_ua},
3334 {"GM/", validate_gm},
3335 {"DR/", validate_dr},
3336 {"DE/", validate_de},
3337 {"NSS/PWINFO/", validate_pwinfo},
3338 {"TRUSTDOMS/", validate_trustdoms},
3339 {"TRUSTDOMCACHE/", validate_trustdomcache},
3340 {"WINBINDD_OFFLINE", validate_offline},
3341 {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
3345 /***********************************************************************
3346 Function to look at every entry in the tdb and validate it as far as
3348 ***********************************************************************/
3350 static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
3353 unsigned int max_key_len = 1024;
3354 struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
3356 /* Paranoia check. */
3357 if (strncmp("UA/", (const char *)kbuf.dptr, 3) == 0) {
3358 max_key_len = 1024 * 1024;
3360 if (kbuf.dsize > max_key_len) {
3361 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
3363 (unsigned int)kbuf.dsize, (unsigned int)max_key_len));
3367 for (i = 0; key_val[i].keyname; i++) {
3368 size_t namelen = strlen(key_val[i].keyname);
3369 if (kbuf.dsize >= namelen && (
3370 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
3371 TALLOC_CTX *mem_ctx;
3375 keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
3379 memcpy(keystr, kbuf.dptr, kbuf.dsize);
3380 keystr[kbuf.dsize] = '\0';
3382 mem_ctx = talloc_init("validate_ctx");
3388 ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
3392 talloc_destroy(mem_ctx);
3397 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
3398 dump_data(0, (uint8 *)kbuf.dptr, kbuf.dsize);
3399 DEBUG(0,("data :\n"));
3400 dump_data(0, (uint8 *)dbuf.dptr, dbuf.dsize);
3401 v_state->unknown_key = true;
3402 v_state->success = false;
3403 return 1; /* terminate. */
3406 static void validate_panic(const char *const why)
3408 DEBUG(0,("validating cache: would panic %s\n", why ));
3409 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
3413 /***********************************************************************
3414 Try and validate every entry in the winbindd cache. If we fail here,
3415 delete the cache tdb and return non-zero.
3416 ***********************************************************************/
3418 int winbindd_validate_cache(void)
3421 const char *tdb_path = lock_path("winbindd_cache.tdb");
3422 TDB_CONTEXT *tdb = NULL;
3424 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3425 smb_panic_fn = validate_panic;
3428 tdb = tdb_open_log(tdb_path,
3429 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3430 ( lp_winbind_offline_logon()
3432 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
3436 DEBUG(0, ("winbindd_validate_cache: "
3437 "error opening/initializing tdb\n"));
3442 ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
3445 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
3446 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
3451 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
3452 smb_panic_fn = smb_panic;
3456 /***********************************************************************
3457 Try and validate every entry in the winbindd cache.
3458 ***********************************************************************/
3460 int winbindd_validate_cache_nobackup(void)
3463 const char *tdb_path = lock_path("winbindd_cache.tdb");
3465 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3466 smb_panic_fn = validate_panic;
3469 if (wcache == NULL || wcache->tdb == NULL) {
3470 ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
3472 ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
3476 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
3480 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
3482 smb_panic_fn = smb_panic;
3486 bool winbindd_cache_validate_and_initialize(void)
3488 close_winbindd_cache();
3490 if (lp_winbind_offline_logon()) {
3491 if (winbindd_validate_cache() < 0) {
3492 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
3493 "could be restored.\n"));
3497 return initialize_winbindd_cache();
3500 /*********************************************************************
3501 ********************************************************************/
3503 static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
3504 struct winbindd_tdc_domain **domains,
3505 size_t *num_domains )
3507 struct winbindd_tdc_domain *list = NULL;
3510 bool set_only = false;
3512 /* don't allow duplicates */
3517 for ( i=0; i< (*num_domains); i++ ) {
3518 if ( strequal( new_dom->name, list[i].domain_name ) ) {
3519 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
3530 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, 1 );
3533 list = TALLOC_REALLOC_ARRAY( *domains, *domains,
3534 struct winbindd_tdc_domain,
3539 ZERO_STRUCT( list[idx] );
3545 list[idx].domain_name = talloc_strdup( list, new_dom->name );
3546 list[idx].dns_name = talloc_strdup( list, new_dom->alt_name );
3548 if ( !is_null_sid( &new_dom->sid ) ) {
3549 sid_copy( &list[idx].sid, &new_dom->sid );
3551 sid_copy(&list[idx].sid, &global_sid_NULL);
3554 if ( new_dom->domain_flags != 0x0 )
3555 list[idx].trust_flags = new_dom->domain_flags;
3557 if ( new_dom->domain_type != 0x0 )
3558 list[idx].trust_type = new_dom->domain_type;
3560 if ( new_dom->domain_trust_attribs != 0x0 )
3561 list[idx].trust_attribs = new_dom->domain_trust_attribs;
3565 *num_domains = idx + 1;
3571 /*********************************************************************
3572 ********************************************************************/
3574 static TDB_DATA make_tdc_key( const char *domain_name )
3576 char *keystr = NULL;
3577 TDB_DATA key = { NULL, 0 };
3579 if ( !domain_name ) {
3580 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
3585 asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name );
3586 key = string_term_tdb_data(keystr);
3591 /*********************************************************************
3592 ********************************************************************/
3594 static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
3596 unsigned char **buf )
3598 unsigned char *buffer = NULL;
3603 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
3611 /* Store the number of array items first */
3612 len += tdb_pack( buffer+len, buflen-len, "d",
3615 /* now pack each domain trust record */
3616 for ( i=0; i<num_domains; i++ ) {
3621 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
3622 domains[i].domain_name,
3623 domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
3626 len += tdb_pack( buffer+len, buflen-len, "fffddd",
3627 domains[i].domain_name,
3628 domains[i].dns_name,
3629 sid_to_fstring(tmp, &domains[i].sid),
3630 domains[i].trust_flags,
3631 domains[i].trust_attribs,
3632 domains[i].trust_type );
3635 if ( buflen < len ) {
3637 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
3638 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
3652 /*********************************************************************
3653 ********************************************************************/
3655 static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
3656 struct winbindd_tdc_domain **domains )
3658 fstring domain_name, dns_name, sid_string;
3659 uint32 type, attribs, flags;
3663 struct winbindd_tdc_domain *list = NULL;
3665 /* get the number of domains */
3666 len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
3668 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3672 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, num_domains );
3674 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
3678 for ( i=0; i<num_domains; i++ ) {
3679 len += tdb_unpack( buf+len, buflen-len, "fffddd",
3688 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3689 TALLOC_FREE( list );
3693 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
3694 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
3695 domain_name, dns_name, sid_string,
3696 flags, attribs, type));
3698 list[i].domain_name = talloc_strdup( list, domain_name );
3699 list[i].dns_name = talloc_strdup( list, dns_name );
3700 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
3701 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
3704 list[i].trust_flags = flags;
3705 list[i].trust_attribs = attribs;
3706 list[i].trust_type = type;
3714 /*********************************************************************
3715 ********************************************************************/
3717 static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
3719 TDB_DATA key = make_tdc_key( lp_workgroup() );
3720 TDB_DATA data = { NULL, 0 };
3726 /* See if we were asked to delete the cache entry */
3729 ret = tdb_delete( wcache->tdb, key );
3733 data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
3740 ret = tdb_store( wcache->tdb, key, data, 0 );
3743 SAFE_FREE( data.dptr );
3744 SAFE_FREE( key.dptr );
3746 return ( ret != -1 );
3749 /*********************************************************************
3750 ********************************************************************/
3752 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
3754 TDB_DATA key = make_tdc_key( lp_workgroup() );
3755 TDB_DATA data = { NULL, 0 };
3763 data = tdb_fetch( wcache->tdb, key );
3765 SAFE_FREE( key.dptr );
3770 *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
3772 SAFE_FREE( data.dptr );
3780 /*********************************************************************
3781 ********************************************************************/
3783 bool wcache_tdc_add_domain( struct winbindd_domain *domain )
3785 struct winbindd_tdc_domain *dom_list = NULL;
3786 size_t num_domains = 0;
3789 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
3790 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
3791 domain->name, domain->alt_name,
3792 sid_string_dbg(&domain->sid),
3793 domain->domain_flags,
3794 domain->domain_trust_attribs,
3795 domain->domain_type));
3797 if ( !init_wcache() ) {
3801 /* fetch the list */
3803 wcache_tdc_fetch_list( &dom_list, &num_domains );
3805 /* add the new domain */
3807 if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
3811 /* pack the domain */
3813 if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
3821 TALLOC_FREE( dom_list );
3826 /*********************************************************************
3827 ********************************************************************/
3829 struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
3831 struct winbindd_tdc_domain *dom_list = NULL;
3832 size_t num_domains = 0;
3834 struct winbindd_tdc_domain *d = NULL;
3836 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
3838 if ( !init_wcache() ) {
3842 /* fetch the list */
3844 wcache_tdc_fetch_list( &dom_list, &num_domains );
3846 for ( i=0; i<num_domains; i++ ) {
3847 if ( strequal(name, dom_list[i].domain_name) ||
3848 strequal(name, dom_list[i].dns_name) )
3850 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
3853 d = TALLOC_P( ctx, struct winbindd_tdc_domain );
3857 d->domain_name = talloc_strdup( d, dom_list[i].domain_name );
3858 d->dns_name = talloc_strdup( d, dom_list[i].dns_name );
3859 sid_copy( &d->sid, &dom_list[i].sid );
3860 d->trust_flags = dom_list[i].trust_flags;
3861 d->trust_type = dom_list[i].trust_type;
3862 d->trust_attribs = dom_list[i].trust_attribs;
3868 TALLOC_FREE( dom_list );
3874 /*********************************************************************
3875 ********************************************************************/
3877 void wcache_tdc_clear( void )
3879 if ( !init_wcache() )
3882 wcache_tdc_store_list( NULL, 0 );
3888 /*********************************************************************
3889 ********************************************************************/
3891 static void wcache_save_user_pwinfo(struct winbindd_domain *domain,
3893 const DOM_SID *user_sid,
3894 const char *homedir,
3899 struct cache_entry *centry;
3902 if ( (centry = centry_start(domain, status)) == NULL )
3905 centry_put_string( centry, homedir );
3906 centry_put_string( centry, shell );
3907 centry_put_string( centry, gecos );
3908 centry_put_uint32( centry, gid );
3910 centry_end(centry, "NSS/PWINFO/%s", sid_to_fstring(tmp, user_sid) );
3912 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid) ));
3914 centry_free(centry);
3917 NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
3918 const DOM_SID *user_sid,
3920 ADS_STRUCT *ads, LDAPMessage *msg,
3921 char **homedir, char **shell, char **gecos,
3924 struct winbind_cache *cache = get_cache(domain);
3925 struct cache_entry *centry = NULL;
3932 centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s",
3933 sid_to_fstring(tmp, user_sid));
3938 *homedir = centry_string( centry, ctx );
3939 *shell = centry_string( centry, ctx );
3940 *gecos = centry_string( centry, ctx );
3941 *p_gid = centry_uint32( centry );
3943 centry_free(centry);
3945 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
3946 sid_string_dbg(user_sid)));
3948 return NT_STATUS_OK;
3952 nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg,
3953 homedir, shell, gecos, p_gid );
3955 if ( NT_STATUS_IS_OK(nt_status) ) {
3956 wcache_save_user_pwinfo( domain, nt_status, user_sid,
3957 *homedir, *shell, *gecos, *p_gid );
3960 if ( NT_STATUS_EQUAL( nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
3961 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
3963 set_domain_offline( domain );
3970 /* the cache backend methods are exposed via this structure */
3971 struct winbindd_methods cache_methods = {