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;
42 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
43 * Here are the list of entry types that are *not* stored
44 * as form struct cache_entry in the cache.
47 static const char *non_centry_keys[] = {
52 WINBINDD_CACHE_VERSION_KEYSTR,
56 /************************************************************************
57 Is this key a non-centry type ?
58 ************************************************************************/
60 static bool is_non_centry_key(TDB_DATA kbuf)
64 if (kbuf.dptr == NULL || kbuf.dsize == 0) {
67 for (i = 0; non_centry_keys[i] != NULL; i++) {
68 size_t namelen = strlen(non_centry_keys[i]);
69 if (kbuf.dsize < namelen) {
72 if (strncmp(non_centry_keys[i], (const char *)kbuf.dptr, namelen) == 0) {
79 /* Global online/offline state - False when online. winbindd starts up online
80 and sets this to true if the first query fails and there's an entry in
81 the cache tdb telling us to stay offline. */
83 static bool global_winbindd_offline_state;
85 struct winbind_cache {
91 uint32 sequence_number;
96 void (*smb_panic_fn)(const char *const why) = smb_panic;
98 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
100 static struct winbind_cache *wcache;
102 void winbindd_check_cache_size(time_t t)
104 static time_t last_check_time;
107 if (last_check_time == (time_t)0)
110 if (t - last_check_time < 60 && t - last_check_time > 0)
113 if (wcache == NULL || wcache->tdb == NULL) {
114 DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
118 if (fstat(tdb_fd(wcache->tdb), &st) == -1) {
119 DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno) ));
123 if (st.st_size > WINBINDD_MAX_CACHE_SIZE) {
124 DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
125 (unsigned long)st.st_size,
126 (unsigned long)WINBINDD_MAX_CACHE_SIZE));
127 wcache_flush_cache();
131 /* get the winbind_cache structure */
132 static struct winbind_cache *get_cache(struct winbindd_domain *domain)
134 struct winbind_cache *ret = wcache;
136 /* We have to know what type of domain we are dealing with first. */
138 if ( !domain->initialized ) {
139 init_dc_connection( domain );
143 OK. listen up becasue I'm only going to say this once.
144 We have the following scenarios to consider
145 (a) trusted AD domains on a Samba DC,
146 (b) trusted AD domains and we are joined to a non-kerberos domain
147 (c) trusted AD domains and we are joined to a kerberos (AD) domain
149 For (a) we can always contact the trusted domain using krb5
150 since we have the domain trust account password
152 For (b) we can only use RPC since we have no way of
153 getting a krb5 ticket in our own domain
155 For (c) we can always use krb5 since we have a kerberos trust
160 if (!domain->backend) {
162 struct winbindd_domain *our_domain = domain;
164 /* find our domain first so we can figure out if we
165 are joined to a kerberized domain */
167 if ( !domain->primary )
168 our_domain = find_our_domain();
170 if ((our_domain->active_directory || IS_DC)
171 && domain->active_directory
172 && !lp_winbind_rpc_only()) {
173 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain->name));
174 domain->backend = &ads_methods;
176 #endif /* HAVE_ADS */
177 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain->name));
178 domain->backend = &reconnect_methods;
181 #endif /* HAVE_ADS */
187 ret = SMB_XMALLOC_P(struct winbind_cache);
191 wcache_flush_cache();
197 free a centry structure
199 static void centry_free(struct cache_entry *centry)
203 SAFE_FREE(centry->data);
207 static bool centry_check_bytes(struct cache_entry *centry, size_t nbytes)
209 if (centry->len - centry->ofs < nbytes) {
210 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
211 (unsigned int)nbytes,
212 centry->len - centry->ofs));
219 pull a uint32 from a cache entry
221 static uint32 centry_uint32(struct cache_entry *centry)
225 if (!centry_check_bytes(centry, 4)) {
226 smb_panic_fn("centry_uint32");
228 ret = IVAL(centry->data, centry->ofs);
234 pull a uint16 from a cache entry
236 static uint16 centry_uint16(struct cache_entry *centry)
239 if (!centry_check_bytes(centry, 2)) {
240 smb_panic_fn("centry_uint16");
242 ret = CVAL(centry->data, centry->ofs);
248 pull a uint8 from a cache entry
250 static uint8 centry_uint8(struct cache_entry *centry)
253 if (!centry_check_bytes(centry, 1)) {
254 smb_panic_fn("centry_uint8");
256 ret = CVAL(centry->data, centry->ofs);
262 pull a NTTIME from a cache entry
264 static NTTIME centry_nttime(struct cache_entry *centry)
267 if (!centry_check_bytes(centry, 8)) {
268 smb_panic_fn("centry_nttime");
270 ret = IVAL(centry->data, centry->ofs);
272 ret += (uint64_t)IVAL(centry->data, centry->ofs) << 32;
278 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
280 static time_t centry_time(struct cache_entry *centry)
282 return (time_t)centry_nttime(centry);
285 /* pull a string from a cache entry, using the supplied
288 static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
293 len = centry_uint8(centry);
296 /* a deliberate NULL string */
300 if (!centry_check_bytes(centry, (size_t)len)) {
301 smb_panic_fn("centry_string");
304 ret = TALLOC_ARRAY(mem_ctx, char, len+1);
306 smb_panic_fn("centry_string out of memory\n");
308 memcpy(ret,centry->data + centry->ofs, len);
314 /* pull a hash16 from a cache entry, using the supplied
317 static char *centry_hash16(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
322 len = centry_uint8(centry);
325 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
330 if (!centry_check_bytes(centry, 16)) {
334 ret = TALLOC_ARRAY(mem_ctx, char, 16);
336 smb_panic_fn("centry_hash out of memory\n");
338 memcpy(ret,centry->data + centry->ofs, 16);
343 /* pull a sid from a cache entry, using the supplied
346 static bool centry_sid(struct cache_entry *centry, TALLOC_CTX *mem_ctx, DOM_SID *sid)
349 sid_string = centry_string(centry, mem_ctx);
350 if ((sid_string == NULL) || (!string_to_sid(sid, sid_string))) {
358 pull a NTSTATUS from a cache entry
360 static NTSTATUS centry_ntstatus(struct cache_entry *centry)
364 status = NT_STATUS(centry_uint32(centry));
369 /* the server is considered down if it can't give us a sequence number */
370 static bool wcache_server_down(struct winbindd_domain *domain)
377 ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
380 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
385 static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
392 DEBUG(10,("fetch_cache_seqnum: tdb == NULL\n"));
393 return NT_STATUS_UNSUCCESSFUL;
396 fstr_sprintf( key, "SEQNUM/%s", domain->name );
398 data = tdb_fetch_bystring( wcache->tdb, key );
399 if ( !data.dptr || data.dsize!=8 ) {
400 DEBUG(10,("fetch_cache_seqnum: invalid data size key [%s]\n", key ));
401 return NT_STATUS_UNSUCCESSFUL;
404 domain->sequence_number = IVAL(data.dptr, 0);
405 domain->last_seq_check = IVAL(data.dptr, 4);
407 SAFE_FREE(data.dptr);
409 /* have we expired? */
411 time_diff = now - domain->last_seq_check;
412 if ( time_diff > lp_winbind_cache_time() ) {
413 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
414 domain->name, domain->sequence_number,
415 (uint32)domain->last_seq_check));
416 return NT_STATUS_UNSUCCESSFUL;
419 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
420 domain->name, domain->sequence_number,
421 (uint32)domain->last_seq_check));
426 static NTSTATUS store_cache_seqnum( struct winbindd_domain *domain )
433 DEBUG(10,("store_cache_seqnum: tdb == NULL\n"));
434 return NT_STATUS_UNSUCCESSFUL;
437 fstr_sprintf( key_str, "SEQNUM/%s", domain->name );
439 SIVAL(buf, 0, domain->sequence_number);
440 SIVAL(buf, 4, domain->last_seq_check);
444 if ( tdb_store_bystring( wcache->tdb, key_str, data, TDB_REPLACE) == -1 ) {
445 DEBUG(10,("store_cache_seqnum: tdb_store fail key [%s]\n", key_str ));
446 return NT_STATUS_UNSUCCESSFUL;
449 DEBUG(10,("store_cache_seqnum: success [%s][%u @ %u]\n",
450 domain->name, domain->sequence_number,
451 (uint32)domain->last_seq_check));
457 refresh the domain sequence number. If force is true
458 then always refresh it, no matter how recently we fetched it
461 static void refresh_sequence_number(struct winbindd_domain *domain, bool force)
465 time_t t = time(NULL);
466 unsigned cache_time = lp_winbind_cache_time();
468 if ( IS_DOMAIN_OFFLINE(domain) ) {
474 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
475 /* trying to reconnect is expensive, don't do it too often */
476 if (domain->sequence_number == DOM_SEQUENCE_NONE) {
481 time_diff = t - domain->last_seq_check;
483 /* see if we have to refetch the domain sequence number */
484 if (!force && (time_diff < cache_time)) {
485 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
489 /* try to get the sequence number from the tdb cache first */
490 /* this will update the timestamp as well */
492 status = fetch_cache_seqnum( domain, t );
493 if ( NT_STATUS_IS_OK(status) )
496 /* important! make sure that we know if this is a native
497 mode domain or not. And that we can contact it. */
499 if ( winbindd_can_contact_domain( domain ) ) {
500 status = domain->backend->sequence_number(domain,
501 &domain->sequence_number);
503 /* just use the current time */
504 status = NT_STATUS_OK;
505 domain->sequence_number = time(NULL);
509 /* the above call could have set our domain->backend to NULL when
510 * coming from offline to online mode, make sure to reinitialize the
511 * backend - Guenther */
514 if (!NT_STATUS_IS_OK(status)) {
515 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status)));
516 domain->sequence_number = DOM_SEQUENCE_NONE;
519 domain->last_status = status;
520 domain->last_seq_check = time(NULL);
522 /* save the new sequence number ni the cache */
523 store_cache_seqnum( domain );
526 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
527 domain->name, domain->sequence_number));
533 decide if a cache entry has expired
535 static bool centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
537 /* If we've been told to be offline - stay in that state... */
538 if (lp_winbind_offline_logon() && global_winbindd_offline_state) {
539 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
540 keystr, domain->name ));
544 /* when the domain is offline return the cached entry.
545 * This deals with transient offline states... */
547 if (!domain->online) {
548 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
549 keystr, domain->name ));
553 /* if the server is OK and our cache entry came from when it was down then
554 the entry is invalid */
555 if ((domain->sequence_number != DOM_SEQUENCE_NONE) &&
556 (centry->sequence_number == DOM_SEQUENCE_NONE)) {
557 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
558 keystr, domain->name ));
562 /* if the server is down or the cache entry is not older than the
563 current sequence number then it is OK */
564 if (wcache_server_down(domain) ||
565 centry->sequence_number == domain->sequence_number) {
566 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
567 keystr, domain->name ));
571 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
572 keystr, domain->name ));
578 static struct cache_entry *wcache_fetch_raw(char *kstr)
581 struct cache_entry *centry;
584 key = string_tdb_data(kstr);
585 data = tdb_fetch(wcache->tdb, key);
591 centry = SMB_XMALLOC_P(struct cache_entry);
592 centry->data = (unsigned char *)data.dptr;
593 centry->len = data.dsize;
596 if (centry->len < 8) {
597 /* huh? corrupt cache? */
598 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr));
603 centry->status = centry_ntstatus(centry);
604 centry->sequence_number = centry_uint32(centry);
610 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
611 number and return status
613 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
614 struct winbindd_domain *domain,
615 const char *format, ...) PRINTF_ATTRIBUTE(3,4);
616 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
617 struct winbindd_domain *domain,
618 const char *format, ...)
622 struct cache_entry *centry;
628 refresh_sequence_number(domain, false);
630 va_start(ap, format);
631 smb_xvasprintf(&kstr, format, ap);
634 centry = wcache_fetch_raw(kstr);
635 if (centry == NULL) {
640 if (centry_expired(domain, kstr, centry)) {
642 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
643 kstr, domain->name ));
650 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
651 kstr, domain->name ));
657 static void wcache_delete(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
658 static void wcache_delete(const char *format, ...)
664 va_start(ap, format);
665 smb_xvasprintf(&kstr, format, ap);
668 key = string_tdb_data(kstr);
670 tdb_delete(wcache->tdb, key);
675 make sure we have at least len bytes available in a centry
677 static void centry_expand(struct cache_entry *centry, uint32 len)
679 if (centry->len - centry->ofs >= len)
682 centry->data = SMB_REALLOC_ARRAY(centry->data, unsigned char,
685 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
686 smb_panic_fn("out of memory in centry_expand");
691 push a uint32 into a centry
693 static void centry_put_uint32(struct cache_entry *centry, uint32 v)
695 centry_expand(centry, 4);
696 SIVAL(centry->data, centry->ofs, v);
701 push a uint16 into a centry
703 static void centry_put_uint16(struct cache_entry *centry, uint16 v)
705 centry_expand(centry, 2);
706 SIVAL(centry->data, centry->ofs, v);
711 push a uint8 into a centry
713 static void centry_put_uint8(struct cache_entry *centry, uint8 v)
715 centry_expand(centry, 1);
716 SCVAL(centry->data, centry->ofs, v);
721 push a string into a centry
723 static void centry_put_string(struct cache_entry *centry, const char *s)
728 /* null strings are marked as len 0xFFFF */
729 centry_put_uint8(centry, 0xFF);
734 /* can't handle more than 254 char strings. Truncating is probably best */
736 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len));
739 centry_put_uint8(centry, len);
740 centry_expand(centry, len);
741 memcpy(centry->data + centry->ofs, s, len);
746 push a 16 byte hash into a centry - treat as 16 byte string.
748 static void centry_put_hash16(struct cache_entry *centry, const uint8 val[16])
750 centry_put_uint8(centry, 16);
751 centry_expand(centry, 16);
752 memcpy(centry->data + centry->ofs, val, 16);
756 static void centry_put_sid(struct cache_entry *centry, const DOM_SID *sid)
759 centry_put_string(centry, sid_to_fstring(sid_string, sid));
764 put NTSTATUS into a centry
766 static void centry_put_ntstatus(struct cache_entry *centry, NTSTATUS status)
768 uint32 status_value = NT_STATUS_V(status);
769 centry_put_uint32(centry, status_value);
774 push a NTTIME into a centry
776 static void centry_put_nttime(struct cache_entry *centry, NTTIME nt)
778 centry_expand(centry, 8);
779 SIVAL(centry->data, centry->ofs, nt & 0xFFFFFFFF);
781 SIVAL(centry->data, centry->ofs, nt >> 32);
786 push a time_t into a centry - use a 64 bit size.
787 NTTIME here is being used as a convenient 64-bit size.
789 static void centry_put_time(struct cache_entry *centry, time_t t)
791 NTTIME nt = (NTTIME)t;
792 centry_put_nttime(centry, nt);
796 start a centry for output. When finished, call centry_end()
798 struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status)
800 struct cache_entry *centry;
805 centry = SMB_XMALLOC_P(struct cache_entry);
807 centry->len = 8192; /* reasonable default */
808 centry->data = SMB_XMALLOC_ARRAY(uint8, centry->len);
810 centry->sequence_number = domain->sequence_number;
811 centry_put_ntstatus(centry, status);
812 centry_put_uint32(centry, centry->sequence_number);
817 finish a centry and write it to the tdb
819 static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
820 static void centry_end(struct cache_entry *centry, const char *format, ...)
830 va_start(ap, format);
831 smb_xvasprintf(&kstr, format, ap);
834 key = string_tdb_data(kstr);
835 data.dptr = centry->data;
836 data.dsize = centry->ofs;
838 tdb_store(wcache->tdb, key, data, TDB_REPLACE);
842 static void wcache_save_name_to_sid(struct winbindd_domain *domain,
843 NTSTATUS status, const char *domain_name,
844 const char *name, const DOM_SID *sid,
845 enum lsa_SidType type)
847 struct cache_entry *centry;
850 centry = centry_start(domain, status);
853 centry_put_uint32(centry, type);
854 centry_put_sid(centry, sid);
855 fstrcpy(uname, name);
857 centry_end(centry, "NS/%s/%s", domain_name, uname);
858 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name,
859 uname, sid_string_dbg(sid), nt_errstr(status)));
863 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
864 const DOM_SID *sid, const char *domain_name, const char *name, enum lsa_SidType type)
866 struct cache_entry *centry;
869 centry = centry_start(domain, status);
873 if (NT_STATUS_IS_OK(status)) {
874 centry_put_uint32(centry, type);
875 centry_put_string(centry, domain_name);
876 centry_put_string(centry, name);
879 centry_end(centry, "SN/%s", sid_to_fstring(sid_string, sid));
880 DEBUG(10,("wcache_save_sid_to_name: %s -> %s (%s)\n", sid_string,
881 name, nt_errstr(status)));
886 static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status, WINBIND_USERINFO *info)
888 struct cache_entry *centry;
891 if (is_null_sid(&info->user_sid)) {
895 centry = centry_start(domain, status);
898 centry_put_string(centry, info->acct_name);
899 centry_put_string(centry, info->full_name);
900 centry_put_string(centry, info->homedir);
901 centry_put_string(centry, info->shell);
902 centry_put_uint32(centry, info->primary_gid);
903 centry_put_sid(centry, &info->user_sid);
904 centry_put_sid(centry, &info->group_sid);
905 centry_end(centry, "U/%s", sid_to_fstring(sid_string,
907 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
911 static void wcache_save_lockout_policy(struct winbindd_domain *domain,
913 struct samr_DomInfo12 *lockout_policy)
915 struct cache_entry *centry;
917 centry = centry_start(domain, status);
921 centry_put_nttime(centry, lockout_policy->lockout_duration);
922 centry_put_nttime(centry, lockout_policy->lockout_window);
923 centry_put_uint16(centry, lockout_policy->lockout_threshold);
925 centry_end(centry, "LOC_POL/%s", domain->name);
927 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
932 static void wcache_save_password_policy(struct winbindd_domain *domain,
934 struct samr_DomInfo1 *policy)
936 struct cache_entry *centry;
938 centry = centry_start(domain, status);
942 centry_put_uint16(centry, policy->min_password_length);
943 centry_put_uint16(centry, policy->password_history_length);
944 centry_put_uint32(centry, policy->password_properties);
945 centry_put_nttime(centry, policy->max_password_age);
946 centry_put_nttime(centry, policy->min_password_age);
948 centry_end(centry, "PWD_POL/%s", domain->name);
950 DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
955 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const DOM_SID *sid)
957 struct winbind_cache *cache = get_cache(domain);
959 fstring key_str, tmp;
963 return NT_STATUS_INTERNAL_DB_ERROR;
966 if (is_null_sid(sid)) {
967 return NT_STATUS_INVALID_SID;
970 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
971 return NT_STATUS_INVALID_SID;
974 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
976 data = tdb_fetch(cache->tdb, string_tdb_data(key_str));
978 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
981 SAFE_FREE(data.dptr);
985 /* Lookup creds for a SID - copes with old (unsalted) creds as well
986 as new salted ones. */
988 NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
991 const uint8 **cached_nt_pass,
992 const uint8 **cached_salt)
994 struct winbind_cache *cache = get_cache(domain);
995 struct cache_entry *centry = NULL;
1002 return NT_STATUS_INTERNAL_DB_ERROR;
1005 if (is_null_sid(sid)) {
1006 return NT_STATUS_INVALID_SID;
1009 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1010 return NT_STATUS_INVALID_SID;
1013 /* Try and get a salted cred first. If we can't
1014 fall back to an unsalted cred. */
1016 centry = wcache_fetch(cache, domain, "CRED/%s",
1017 sid_to_fstring(tmp, sid));
1019 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1020 sid_string_dbg(sid)));
1021 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1024 t = centry_time(centry);
1026 /* In the salted case this isn't actually the nt_hash itself,
1027 but the MD5 of the salt + nt_hash. Let the caller
1028 sort this out. It can tell as we only return the cached_salt
1029 if we are returning a salted cred. */
1031 *cached_nt_pass = (const uint8 *)centry_hash16(centry, mem_ctx);
1032 if (*cached_nt_pass == NULL) {
1035 sid_to_fstring(sidstr, sid);
1037 /* Bad (old) cred cache. Delete and pretend we
1039 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1041 wcache_delete("CRED/%s", sidstr);
1042 centry_free(centry);
1043 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1046 /* We only have 17 bytes more data in the salted cred case. */
1047 if (centry->len - centry->ofs == 17) {
1048 *cached_salt = (const uint8 *)centry_hash16(centry, mem_ctx);
1050 *cached_salt = NULL;
1053 dump_data_pw("cached_nt_pass", *cached_nt_pass, NT_HASH_LEN);
1055 dump_data_pw("cached_salt", *cached_salt, NT_HASH_LEN);
1058 status = centry->status;
1060 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1061 sid_string_dbg(sid), nt_errstr(status) ));
1063 centry_free(centry);
1067 /* Store creds for a SID - only writes out new salted ones. */
1069 NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
1070 TALLOC_CTX *mem_ctx,
1072 const uint8 nt_pass[NT_HASH_LEN])
1074 struct cache_entry *centry;
1077 uint8 cred_salt[NT_HASH_LEN];
1078 uint8 salted_hash[NT_HASH_LEN];
1080 if (is_null_sid(sid)) {
1081 return NT_STATUS_INVALID_SID;
1084 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1085 return NT_STATUS_INVALID_SID;
1088 centry = centry_start(domain, NT_STATUS_OK);
1090 return NT_STATUS_INTERNAL_DB_ERROR;
1093 dump_data_pw("nt_pass", nt_pass, NT_HASH_LEN);
1095 centry_put_time(centry, time(NULL));
1097 /* Create a salt and then salt the hash. */
1098 generate_random_buffer(cred_salt, NT_HASH_LEN);
1099 E_md5hash(cred_salt, nt_pass, salted_hash);
1101 centry_put_hash16(centry, salted_hash);
1102 centry_put_hash16(centry, cred_salt);
1103 centry_end(centry, "CRED/%s", sid_to_fstring(sid_string, sid));
1105 DEBUG(10,("wcache_save_creds: %s\n", sid_string));
1107 centry_free(centry);
1109 return NT_STATUS_OK;
1113 /* Query display info. This is the basic user list fn */
1114 static NTSTATUS query_user_list(struct winbindd_domain *domain,
1115 TALLOC_CTX *mem_ctx,
1116 uint32 *num_entries,
1117 WINBIND_USERINFO **info)
1119 struct winbind_cache *cache = get_cache(domain);
1120 struct cache_entry *centry = NULL;
1122 unsigned int i, retry;
1127 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1131 *num_entries = centry_uint32(centry);
1133 if (*num_entries == 0)
1136 (*info) = TALLOC_ARRAY(mem_ctx, WINBIND_USERINFO, *num_entries);
1138 smb_panic_fn("query_user_list out of memory");
1140 for (i=0; i<(*num_entries); i++) {
1141 (*info)[i].acct_name = centry_string(centry, mem_ctx);
1142 (*info)[i].full_name = centry_string(centry, mem_ctx);
1143 (*info)[i].homedir = centry_string(centry, mem_ctx);
1144 (*info)[i].shell = centry_string(centry, mem_ctx);
1145 centry_sid(centry, mem_ctx, &(*info)[i].user_sid);
1146 centry_sid(centry, mem_ctx, &(*info)[i].group_sid);
1150 status = centry->status;
1152 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1153 domain->name, nt_errstr(status) ));
1155 centry_free(centry);
1162 /* Return status value returned by seq number check */
1164 if (!NT_STATUS_IS_OK(domain->last_status))
1165 return domain->last_status;
1167 /* Put the query_user_list() in a retry loop. There appears to be
1168 * some bug either with Windows 2000 or Samba's handling of large
1169 * rpc replies. This manifests itself as sudden disconnection
1170 * at a random point in the enumeration of a large (60k) user list.
1171 * The retry loop simply tries the operation again. )-: It's not
1172 * pretty but an acceptable workaround until we work out what the
1173 * real problem is. */
1178 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1181 status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
1182 if (!NT_STATUS_IS_OK(status)) {
1183 DEBUG(3, ("query_user_list: returned 0x%08x, "
1184 "retrying\n", NT_STATUS_V(status)));
1186 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1187 DEBUG(3, ("query_user_list: flushing "
1188 "connection cache\n"));
1189 invalidate_cm_connection(&domain->conn);
1192 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
1196 refresh_sequence_number(domain, false);
1197 centry = centry_start(domain, status);
1200 centry_put_uint32(centry, *num_entries);
1201 for (i=0; i<(*num_entries); i++) {
1202 centry_put_string(centry, (*info)[i].acct_name);
1203 centry_put_string(centry, (*info)[i].full_name);
1204 centry_put_string(centry, (*info)[i].homedir);
1205 centry_put_string(centry, (*info)[i].shell);
1206 centry_put_sid(centry, &(*info)[i].user_sid);
1207 centry_put_sid(centry, &(*info)[i].group_sid);
1208 if (domain->backend && domain->backend->consistent) {
1209 /* when the backend is consistent we can pre-prime some mappings */
1210 wcache_save_name_to_sid(domain, NT_STATUS_OK,
1212 (*info)[i].acct_name,
1213 &(*info)[i].user_sid,
1215 wcache_save_sid_to_name(domain, NT_STATUS_OK,
1216 &(*info)[i].user_sid,
1218 (*info)[i].acct_name,
1220 wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
1223 centry_end(centry, "UL/%s", domain->name);
1224 centry_free(centry);
1230 /* list all domain groups */
1231 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
1232 TALLOC_CTX *mem_ctx,
1233 uint32 *num_entries,
1234 struct acct_info **info)
1236 struct winbind_cache *cache = get_cache(domain);
1237 struct cache_entry *centry = NULL;
1244 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1248 *num_entries = centry_uint32(centry);
1250 if (*num_entries == 0)
1253 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1255 smb_panic_fn("enum_dom_groups out of memory");
1257 for (i=0; i<(*num_entries); i++) {
1258 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1259 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1260 (*info)[i].rid = centry_uint32(centry);
1264 status = centry->status;
1266 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1267 domain->name, nt_errstr(status) ));
1269 centry_free(centry);
1276 /* Return status value returned by seq number check */
1278 if (!NT_STATUS_IS_OK(domain->last_status))
1279 return domain->last_status;
1281 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1284 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1287 refresh_sequence_number(domain, false);
1288 centry = centry_start(domain, status);
1291 centry_put_uint32(centry, *num_entries);
1292 for (i=0; i<(*num_entries); i++) {
1293 centry_put_string(centry, (*info)[i].acct_name);
1294 centry_put_string(centry, (*info)[i].acct_desc);
1295 centry_put_uint32(centry, (*info)[i].rid);
1297 centry_end(centry, "GL/%s/domain", domain->name);
1298 centry_free(centry);
1304 /* list all domain groups */
1305 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
1306 TALLOC_CTX *mem_ctx,
1307 uint32 *num_entries,
1308 struct acct_info **info)
1310 struct winbind_cache *cache = get_cache(domain);
1311 struct cache_entry *centry = NULL;
1318 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1322 *num_entries = centry_uint32(centry);
1324 if (*num_entries == 0)
1327 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1329 smb_panic_fn("enum_dom_groups out of memory");
1331 for (i=0; i<(*num_entries); i++) {
1332 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1333 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1334 (*info)[i].rid = centry_uint32(centry);
1339 /* If we are returning cached data and the domain controller
1340 is down then we don't know whether the data is up to date
1341 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1344 if (wcache_server_down(domain)) {
1345 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1346 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1348 status = centry->status;
1350 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1351 domain->name, nt_errstr(status) ));
1353 centry_free(centry);
1360 /* Return status value returned by seq number check */
1362 if (!NT_STATUS_IS_OK(domain->last_status))
1363 return domain->last_status;
1365 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1368 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1371 refresh_sequence_number(domain, false);
1372 centry = centry_start(domain, status);
1375 centry_put_uint32(centry, *num_entries);
1376 for (i=0; i<(*num_entries); i++) {
1377 centry_put_string(centry, (*info)[i].acct_name);
1378 centry_put_string(centry, (*info)[i].acct_desc);
1379 centry_put_uint32(centry, (*info)[i].rid);
1381 centry_end(centry, "GL/%s/local", domain->name);
1382 centry_free(centry);
1388 /* convert a single name to a sid in a domain */
1389 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
1390 TALLOC_CTX *mem_ctx,
1391 enum winbindd_cmd orig_cmd,
1392 const char *domain_name,
1395 enum lsa_SidType *type)
1397 struct winbind_cache *cache = get_cache(domain);
1398 struct cache_entry *centry = NULL;
1405 fstrcpy(uname, name);
1407 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1411 status = centry->status;
1412 if (NT_STATUS_IS_OK(status)) {
1413 *type = (enum lsa_SidType)centry_uint32(centry);
1414 centry_sid(centry, mem_ctx, sid);
1417 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: %s\n",
1418 domain->name, nt_errstr(status) ));
1420 centry_free(centry);
1426 /* If the seq number check indicated that there is a problem
1427 * with this DC, then return that status... except for
1428 * access_denied. This is special because the dc may be in
1429 * "restrict anonymous = 1" mode, in which case it will deny
1430 * most unauthenticated operations, but *will* allow the LSA
1431 * name-to-sid that we try as a fallback. */
1433 if (!(NT_STATUS_IS_OK(domain->last_status)
1434 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1435 return domain->last_status;
1437 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1440 status = domain->backend->name_to_sid(domain, mem_ctx, orig_cmd,
1441 domain_name, name, sid, type);
1444 refresh_sequence_number(domain, false);
1446 if (domain->online &&
1447 (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
1448 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1450 /* Only save the reverse mapping if this was not a UPN */
1451 if (!strchr(name, '@')) {
1452 strupper_m(CONST_DISCARD(char *,domain_name));
1453 strlower_m(CONST_DISCARD(char *,name));
1454 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1461 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1463 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
1464 TALLOC_CTX *mem_ctx,
1468 enum lsa_SidType *type)
1470 struct winbind_cache *cache = get_cache(domain);
1471 struct cache_entry *centry = NULL;
1478 centry = wcache_fetch(cache, domain, "SN/%s",
1479 sid_to_fstring(sid_string, sid));
1483 status = centry->status;
1484 if (NT_STATUS_IS_OK(status)) {
1485 *type = (enum lsa_SidType)centry_uint32(centry);
1486 *domain_name = centry_string(centry, mem_ctx);
1487 *name = centry_string(centry, mem_ctx);
1490 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: %s\n",
1491 domain->name, nt_errstr(status) ));
1493 centry_free(centry);
1498 *domain_name = NULL;
1500 /* If the seq number check indicated that there is a problem
1501 * with this DC, then return that status... except for
1502 * access_denied. This is special because the dc may be in
1503 * "restrict anonymous = 1" mode, in which case it will deny
1504 * most unauthenticated operations, but *will* allow the LSA
1505 * sid-to-name that we try as a fallback. */
1507 if (!(NT_STATUS_IS_OK(domain->last_status)
1508 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1509 return domain->last_status;
1511 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1514 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1517 refresh_sequence_number(domain, false);
1518 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1520 /* We can't save the name to sid mapping here, as with sid history a
1521 * later name2sid would give the wrong sid. */
1526 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
1527 TALLOC_CTX *mem_ctx,
1528 const DOM_SID *domain_sid,
1533 enum lsa_SidType **types)
1535 struct winbind_cache *cache = get_cache(domain);
1537 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1541 *domain_name = NULL;
1549 if (num_rids == 0) {
1550 return NT_STATUS_OK;
1553 *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
1554 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
1556 if ((*names == NULL) || (*types == NULL)) {
1557 result = NT_STATUS_NO_MEMORY;
1561 have_mapped = have_unmapped = false;
1563 for (i=0; i<num_rids; i++) {
1565 struct cache_entry *centry;
1568 if (!sid_compose(&sid, domain_sid, rids[i])) {
1569 result = NT_STATUS_INTERNAL_ERROR;
1573 centry = wcache_fetch(cache, domain, "SN/%s",
1574 sid_to_fstring(tmp, &sid));
1579 (*types)[i] = SID_NAME_UNKNOWN;
1580 (*names)[i] = talloc_strdup(*names, "");
1582 if (NT_STATUS_IS_OK(centry->status)) {
1585 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
1587 dom = centry_string(centry, mem_ctx);
1588 if (*domain_name == NULL) {
1594 (*names)[i] = centry_string(centry, *names);
1596 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
1597 have_unmapped = true;
1600 /* something's definitely wrong */
1601 result = centry->status;
1605 centry_free(centry);
1609 return NT_STATUS_NONE_MAPPED;
1611 if (!have_unmapped) {
1612 return NT_STATUS_OK;
1614 return STATUS_SOME_UNMAPPED;
1618 TALLOC_FREE(*names);
1619 TALLOC_FREE(*types);
1621 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
1622 rids, num_rids, domain_name,
1626 None of the queried rids has been found so save all negative entries
1628 if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
1629 for (i = 0; i < num_rids; i++) {
1631 const char *name = "";
1632 const enum lsa_SidType type = SID_NAME_UNKNOWN;
1633 NTSTATUS status = NT_STATUS_NONE_MAPPED;
1635 if (!sid_compose(&sid, domain_sid, rids[i])) {
1636 return NT_STATUS_INTERNAL_ERROR;
1639 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
1647 Some or all of the queried rids have been found.
1649 if (!NT_STATUS_IS_OK(result) &&
1650 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
1654 refresh_sequence_number(domain, false);
1656 for (i=0; i<num_rids; i++) {
1660 if (!sid_compose(&sid, domain_sid, rids[i])) {
1661 result = NT_STATUS_INTERNAL_ERROR;
1665 status = (*types)[i] == SID_NAME_UNKNOWN ?
1666 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
1668 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
1669 (*names)[i], (*types)[i]);
1676 TALLOC_FREE(*names);
1677 TALLOC_FREE(*types);
1681 /* Lookup user information from a rid */
1682 static NTSTATUS query_user(struct winbindd_domain *domain,
1683 TALLOC_CTX *mem_ctx,
1684 const DOM_SID *user_sid,
1685 WINBIND_USERINFO *info)
1687 struct winbind_cache *cache = get_cache(domain);
1688 struct cache_entry *centry = NULL;
1695 centry = wcache_fetch(cache, domain, "U/%s",
1696 sid_to_fstring(tmp, user_sid));
1698 /* If we have an access denied cache entry and a cached info3 in the
1699 samlogon cache then do a query. This will force the rpc back end
1700 to return the info3 data. */
1702 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1703 netsamlogon_cache_have(user_sid)) {
1704 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1705 domain->last_status = NT_STATUS_OK;
1706 centry_free(centry);
1713 /* if status is not ok then this is a negative hit
1714 and the rest of the data doesn't matter */
1715 status = centry->status;
1716 if (NT_STATUS_IS_OK(status)) {
1717 info->acct_name = centry_string(centry, mem_ctx);
1718 info->full_name = centry_string(centry, mem_ctx);
1719 info->homedir = centry_string(centry, mem_ctx);
1720 info->shell = centry_string(centry, mem_ctx);
1721 info->primary_gid = centry_uint32(centry);
1722 centry_sid(centry, mem_ctx, &info->user_sid);
1723 centry_sid(centry, mem_ctx, &info->group_sid);
1726 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: %s\n",
1727 domain->name, nt_errstr(status) ));
1729 centry_free(centry);
1735 /* Return status value returned by seq number check */
1737 if (!NT_STATUS_IS_OK(domain->last_status))
1738 return domain->last_status;
1740 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
1743 status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
1746 refresh_sequence_number(domain, false);
1747 wcache_save_user(domain, status, info);
1753 /* Lookup groups a user is a member of. */
1754 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
1755 TALLOC_CTX *mem_ctx,
1756 const DOM_SID *user_sid,
1757 uint32 *num_groups, DOM_SID **user_gids)
1759 struct winbind_cache *cache = get_cache(domain);
1760 struct cache_entry *centry = NULL;
1768 centry = wcache_fetch(cache, domain, "UG/%s",
1769 sid_to_fstring(sid_string, user_sid));
1771 /* If we have an access denied cache entry and a cached info3 in the
1772 samlogon cache then do a query. This will force the rpc back end
1773 to return the info3 data. */
1775 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1776 netsamlogon_cache_have(user_sid)) {
1777 DEBUG(10, ("lookup_usergroups: cached access denied and have cached info3\n"));
1778 domain->last_status = NT_STATUS_OK;
1779 centry_free(centry);
1786 *num_groups = centry_uint32(centry);
1788 if (*num_groups == 0)
1791 (*user_gids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
1792 if (! (*user_gids)) {
1793 smb_panic_fn("lookup_usergroups out of memory");
1795 for (i=0; i<(*num_groups); i++) {
1796 centry_sid(centry, mem_ctx, &(*user_gids)[i]);
1800 status = centry->status;
1802 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status: %s\n",
1803 domain->name, nt_errstr(status) ));
1805 centry_free(centry);
1810 (*user_gids) = NULL;
1812 /* Return status value returned by seq number check */
1814 if (!NT_STATUS_IS_OK(domain->last_status))
1815 return domain->last_status;
1817 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
1820 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
1822 if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
1826 refresh_sequence_number(domain, false);
1827 centry = centry_start(domain, status);
1831 centry_put_uint32(centry, *num_groups);
1832 for (i=0; i<(*num_groups); i++) {
1833 centry_put_sid(centry, &(*user_gids)[i]);
1836 centry_end(centry, "UG/%s", sid_to_fstring(sid_string, user_sid));
1837 centry_free(centry);
1843 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
1844 TALLOC_CTX *mem_ctx,
1845 uint32 num_sids, const DOM_SID *sids,
1846 uint32 *num_aliases, uint32 **alias_rids)
1848 struct winbind_cache *cache = get_cache(domain);
1849 struct cache_entry *centry = NULL;
1851 char *sidlist = talloc_strdup(mem_ctx, "");
1857 if (num_sids == 0) {
1860 return NT_STATUS_OK;
1863 /* We need to cache indexed by the whole list of SIDs, the aliases
1864 * resulting might come from any of the SIDs. */
1866 for (i=0; i<num_sids; i++) {
1868 sidlist = talloc_asprintf(mem_ctx, "%s/%s", sidlist,
1869 sid_to_fstring(tmp, &sids[i]));
1870 if (sidlist == NULL)
1871 return NT_STATUS_NO_MEMORY;
1874 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
1879 *num_aliases = centry_uint32(centry);
1883 (*alias_rids) = TALLOC_ARRAY(mem_ctx, uint32, *num_aliases);
1885 if ((*alias_rids) == NULL) {
1886 centry_free(centry);
1887 return NT_STATUS_NO_MEMORY;
1890 (*alias_rids) = NULL;
1893 for (i=0; i<(*num_aliases); i++)
1894 (*alias_rids)[i] = centry_uint32(centry);
1896 status = centry->status;
1898 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
1899 "status %s\n", domain->name, nt_errstr(status)));
1901 centry_free(centry);
1906 (*alias_rids) = NULL;
1908 if (!NT_STATUS_IS_OK(domain->last_status))
1909 return domain->last_status;
1911 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
1912 "for domain %s\n", domain->name ));
1914 status = domain->backend->lookup_useraliases(domain, mem_ctx,
1916 num_aliases, alias_rids);
1919 refresh_sequence_number(domain, false);
1920 centry = centry_start(domain, status);
1923 centry_put_uint32(centry, *num_aliases);
1924 for (i=0; i<(*num_aliases); i++)
1925 centry_put_uint32(centry, (*alias_rids)[i]);
1926 centry_end(centry, "UA%s", sidlist);
1927 centry_free(centry);
1934 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1935 TALLOC_CTX *mem_ctx,
1936 const DOM_SID *group_sid, uint32 *num_names,
1937 DOM_SID **sid_mem, char ***names,
1938 uint32 **name_types)
1940 struct winbind_cache *cache = get_cache(domain);
1941 struct cache_entry *centry = NULL;
1949 centry = wcache_fetch(cache, domain, "GM/%s",
1950 sid_to_fstring(sid_string, group_sid));
1954 *num_names = centry_uint32(centry);
1956 if (*num_names == 0)
1959 (*sid_mem) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_names);
1960 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_names);
1961 (*name_types) = TALLOC_ARRAY(mem_ctx, uint32, *num_names);
1963 if (! (*sid_mem) || ! (*names) || ! (*name_types)) {
1964 smb_panic_fn("lookup_groupmem out of memory");
1967 for (i=0; i<(*num_names); i++) {
1968 centry_sid(centry, mem_ctx, &(*sid_mem)[i]);
1969 (*names)[i] = centry_string(centry, mem_ctx);
1970 (*name_types)[i] = centry_uint32(centry);
1974 status = centry->status;
1976 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status: %s\n",
1977 domain->name, nt_errstr(status)));
1979 centry_free(centry);
1986 (*name_types) = NULL;
1988 /* Return status value returned by seq number check */
1990 if (!NT_STATUS_IS_OK(domain->last_status))
1991 return domain->last_status;
1993 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
1996 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid, num_names,
1997 sid_mem, names, name_types);
2000 refresh_sequence_number(domain, false);
2001 centry = centry_start(domain, status);
2004 centry_put_uint32(centry, *num_names);
2005 for (i=0; i<(*num_names); i++) {
2006 centry_put_sid(centry, &(*sid_mem)[i]);
2007 centry_put_string(centry, (*names)[i]);
2008 centry_put_uint32(centry, (*name_types)[i]);
2010 centry_end(centry, "GM/%s", sid_to_fstring(sid_string, group_sid));
2011 centry_free(centry);
2017 /* find the sequence number for a domain */
2018 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
2020 refresh_sequence_number(domain, false);
2022 *seq = domain->sequence_number;
2024 return NT_STATUS_OK;
2027 /* enumerate trusted domains
2028 * (we need to have the list of trustdoms in the cache when we go offline) -
2030 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
2031 TALLOC_CTX *mem_ctx,
2032 uint32 *num_domains,
2037 struct winbind_cache *cache = get_cache(domain);
2038 struct cache_entry *centry = NULL;
2045 centry = wcache_fetch(cache, domain, "TRUSTDOMS/%s", domain->name);
2051 *num_domains = centry_uint32(centry);
2054 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
2055 (*alt_names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
2056 (*dom_sids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
2058 if (! (*dom_sids) || ! (*names) || ! (*alt_names)) {
2059 smb_panic_fn("trusted_domains out of memory");
2063 (*alt_names) = NULL;
2067 for (i=0; i<(*num_domains); i++) {
2068 (*names)[i] = centry_string(centry, mem_ctx);
2069 (*alt_names)[i] = centry_string(centry, mem_ctx);
2070 centry_sid(centry, mem_ctx, &(*dom_sids)[i]);
2073 status = centry->status;
2075 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
2076 domain->name, *num_domains, nt_errstr(status) ));
2078 centry_free(centry);
2085 (*alt_names) = NULL;
2087 /* Return status value returned by seq number check */
2089 if (!NT_STATUS_IS_OK(domain->last_status))
2090 return domain->last_status;
2092 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2095 status = domain->backend->trusted_domains(domain, mem_ctx, num_domains,
2096 names, alt_names, dom_sids);
2098 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2099 * so that the generic centry handling still applies correctly -
2102 if (!NT_STATUS_IS_ERR(status)) {
2103 status = NT_STATUS_OK;
2107 #if 0 /* Disabled as we want the trust dom list to be managed by
2108 the main parent and always to make the query. --jerry */
2111 refresh_sequence_number(domain, false);
2113 centry = centry_start(domain, status);
2117 centry_put_uint32(centry, *num_domains);
2119 for (i=0; i<(*num_domains); i++) {
2120 centry_put_string(centry, (*names)[i]);
2121 centry_put_string(centry, (*alt_names)[i]);
2122 centry_put_sid(centry, &(*dom_sids)[i]);
2125 centry_end(centry, "TRUSTDOMS/%s", domain->name);
2127 centry_free(centry);
2135 /* get lockout policy */
2136 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
2137 TALLOC_CTX *mem_ctx,
2138 struct samr_DomInfo12 *policy)
2140 struct winbind_cache *cache = get_cache(domain);
2141 struct cache_entry *centry = NULL;
2147 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2152 policy->lockout_duration = centry_nttime(centry);
2153 policy->lockout_window = centry_nttime(centry);
2154 policy->lockout_threshold = centry_uint16(centry);
2156 status = centry->status;
2158 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2159 domain->name, nt_errstr(status) ));
2161 centry_free(centry);
2165 ZERO_STRUCTP(policy);
2167 /* Return status value returned by seq number check */
2169 if (!NT_STATUS_IS_OK(domain->last_status))
2170 return domain->last_status;
2172 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2175 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2178 refresh_sequence_number(domain, false);
2179 wcache_save_lockout_policy(domain, status, policy);
2184 /* get password policy */
2185 static NTSTATUS password_policy(struct winbindd_domain *domain,
2186 TALLOC_CTX *mem_ctx,
2187 struct samr_DomInfo1 *policy)
2189 struct winbind_cache *cache = get_cache(domain);
2190 struct cache_entry *centry = NULL;
2196 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2201 policy->min_password_length = centry_uint16(centry);
2202 policy->password_history_length = centry_uint16(centry);
2203 policy->password_properties = centry_uint32(centry);
2204 policy->max_password_age = centry_nttime(centry);
2205 policy->min_password_age = centry_nttime(centry);
2207 status = centry->status;
2209 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2210 domain->name, nt_errstr(status) ));
2212 centry_free(centry);
2216 ZERO_STRUCTP(policy);
2218 /* Return status value returned by seq number check */
2220 if (!NT_STATUS_IS_OK(domain->last_status))
2221 return domain->last_status;
2223 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2226 status = domain->backend->password_policy(domain, mem_ctx, policy);
2229 refresh_sequence_number(domain, false);
2230 wcache_save_password_policy(domain, status, policy);
2236 /* Invalidate cached user and group lists coherently */
2238 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2241 if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
2242 strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
2243 tdb_delete(the_tdb, kbuf);
2248 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2250 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
2251 struct netr_SamInfo3 *info3)
2253 struct winbind_cache *cache;
2255 /* dont clear cached U/SID and UG/SID entries when we want to logon
2258 if (lp_winbind_offline_logon()) {
2265 cache = get_cache(domain);
2266 netsamlogon_clear_cached_user(cache->tdb, info3);
2269 bool wcache_invalidate_cache(void)
2271 struct winbindd_domain *domain;
2273 for (domain = domain_list(); domain; domain = domain->next) {
2274 struct winbind_cache *cache = get_cache(domain);
2276 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2277 "entries for %s\n", domain->name));
2280 tdb_traverse(cache->tdb, traverse_fn, NULL);
2289 bool init_wcache(void)
2291 if (wcache == NULL) {
2292 wcache = SMB_XMALLOC_P(struct winbind_cache);
2293 ZERO_STRUCTP(wcache);
2296 if (wcache->tdb != NULL)
2299 /* when working offline we must not clear the cache on restart */
2300 wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
2301 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2302 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
2303 O_RDWR|O_CREAT, 0600);
2305 if (wcache->tdb == NULL) {
2306 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2313 /************************************************************************
2314 This is called by the parent to initialize the cache file.
2315 We don't need sophisticated locking here as we know we're the
2317 ************************************************************************/
2319 bool initialize_winbindd_cache(void)
2321 bool cache_bad = true;
2324 if (!init_wcache()) {
2325 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
2329 /* Check version number. */
2330 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
2331 vers == WINBINDD_CACHE_VERSION) {
2336 DEBUG(0,("initialize_winbindd_cache: clearing cache "
2337 "and re-creating with version number %d\n",
2338 WINBINDD_CACHE_VERSION ));
2340 tdb_close(wcache->tdb);
2343 if (unlink(lock_path("winbindd_cache.tdb")) == -1) {
2344 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
2345 lock_path("winbindd_cache.tdb"),
2349 if (!init_wcache()) {
2350 DEBUG(0,("initialize_winbindd_cache: re-initialization "
2351 "init_wcache failed.\n"));
2355 /* Write the version. */
2356 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
2357 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
2358 tdb_errorstr(wcache->tdb) ));
2363 tdb_close(wcache->tdb);
2368 void close_winbindd_cache(void)
2374 tdb_close(wcache->tdb);
2379 void cache_store_response(pid_t pid, struct winbindd_response *response)
2386 DEBUG(10, ("Storing response for pid %d, len %d\n",
2387 pid, response->length));
2389 fstr_sprintf(key_str, "DR/%d", pid);
2390 if (tdb_store(wcache->tdb, string_tdb_data(key_str),
2391 make_tdb_data((uint8 *)response, sizeof(*response)),
2395 if (response->length == sizeof(*response))
2398 /* There's extra data */
2400 DEBUG(10, ("Storing extra data: len=%d\n",
2401 (int)(response->length - sizeof(*response))));
2403 fstr_sprintf(key_str, "DE/%d", pid);
2404 if (tdb_store(wcache->tdb, string_tdb_data(key_str),
2405 make_tdb_data((uint8 *)response->extra_data.data,
2406 response->length - sizeof(*response)),
2410 /* We could not store the extra data, make sure the tdb does not
2411 * contain a main record with wrong dangling extra data */
2413 fstr_sprintf(key_str, "DR/%d", pid);
2414 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2419 bool cache_retrieve_response(pid_t pid, struct winbindd_response * response)
2427 DEBUG(10, ("Retrieving response for pid %d\n", pid));
2429 fstr_sprintf(key_str, "DR/%d", pid);
2430 data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
2432 if (data.dptr == NULL)
2435 if (data.dsize != sizeof(*response))
2438 memcpy(response, data.dptr, data.dsize);
2439 SAFE_FREE(data.dptr);
2441 if (response->length == sizeof(*response)) {
2442 response->extra_data.data = NULL;
2446 /* There's extra data */
2448 DEBUG(10, ("Retrieving extra data length=%d\n",
2449 (int)(response->length - sizeof(*response))));
2451 fstr_sprintf(key_str, "DE/%d", pid);
2452 data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
2454 if (data.dptr == NULL) {
2455 DEBUG(0, ("Did not find extra data\n"));
2459 if (data.dsize != (response->length - sizeof(*response))) {
2460 DEBUG(0, ("Invalid extra data length: %d\n", (int)data.dsize));
2461 SAFE_FREE(data.dptr);
2465 dump_data(11, (uint8 *)data.dptr, data.dsize);
2467 response->extra_data.data = data.dptr;
2471 void cache_cleanup_response(pid_t pid)
2478 fstr_sprintf(key_str, "DR/%d", pid);
2479 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2481 fstr_sprintf(key_str, "DE/%d", pid);
2482 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2488 bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
2489 char **domain_name, char **name,
2490 enum lsa_SidType *type)
2492 struct winbindd_domain *domain;
2493 struct winbind_cache *cache;
2494 struct cache_entry *centry = NULL;
2498 domain = find_lookup_domain_from_sid(sid);
2499 if (domain == NULL) {
2503 cache = get_cache(domain);
2505 if (cache->tdb == NULL) {
2509 centry = wcache_fetch(cache, domain, "SN/%s",
2510 sid_to_fstring(tmp, sid));
2511 if (centry == NULL) {
2515 if (NT_STATUS_IS_OK(centry->status)) {
2516 *type = (enum lsa_SidType)centry_uint32(centry);
2517 *domain_name = centry_string(centry, mem_ctx);
2518 *name = centry_string(centry, mem_ctx);
2521 status = centry->status;
2522 centry_free(centry);
2523 return NT_STATUS_IS_OK(status);
2526 bool lookup_cached_name(TALLOC_CTX *mem_ctx,
2527 const char *domain_name,
2530 enum lsa_SidType *type)
2532 struct winbindd_domain *domain;
2533 struct winbind_cache *cache;
2534 struct cache_entry *centry = NULL;
2537 bool original_online_state;
2539 domain = find_lookup_domain_from_name(domain_name);
2540 if (domain == NULL) {
2544 cache = get_cache(domain);
2546 if (cache->tdb == NULL) {
2550 fstrcpy(uname, name);
2553 /* If we are doing a cached logon, temporarily set the domain
2554 offline so the cache won't expire the entry */
2556 original_online_state = domain->online;
2557 domain->online = false;
2558 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
2559 domain->online = original_online_state;
2561 if (centry == NULL) {
2565 if (NT_STATUS_IS_OK(centry->status)) {
2566 *type = (enum lsa_SidType)centry_uint32(centry);
2567 centry_sid(centry, mem_ctx, sid);
2570 status = centry->status;
2571 centry_free(centry);
2573 return NT_STATUS_IS_OK(status);
2576 void cache_name2sid(struct winbindd_domain *domain,
2577 const char *domain_name, const char *name,
2578 enum lsa_SidType type, const DOM_SID *sid)
2580 refresh_sequence_number(domain, false);
2581 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
2586 * The original idea that this cache only contains centries has
2587 * been blurred - now other stuff gets put in here. Ensure we
2588 * ignore these things on cleanup.
2591 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
2592 TDB_DATA dbuf, void *state)
2594 struct cache_entry *centry;
2596 if (is_non_centry_key(kbuf)) {
2600 centry = wcache_fetch_raw((char *)kbuf.dptr);
2605 if (!NT_STATUS_IS_OK(centry->status)) {
2606 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
2607 tdb_delete(the_tdb, kbuf);
2610 centry_free(centry);
2614 /* flush the cache */
2615 void wcache_flush_cache(void)
2620 tdb_close(wcache->tdb);
2626 /* when working offline we must not clear the cache on restart */
2627 wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
2628 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2629 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
2630 O_RDWR|O_CREAT, 0600);
2633 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2637 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
2639 DEBUG(10,("wcache_flush_cache success\n"));
2642 /* Count cached creds */
2644 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2647 int *cred_count = (int*)state;
2649 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
2655 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
2657 struct winbind_cache *cache = get_cache(domain);
2662 return NT_STATUS_INTERNAL_DB_ERROR;
2665 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
2667 return NT_STATUS_OK;
2671 struct cred_list *prev, *next;
2676 static struct cred_list *wcache_cred_list;
2678 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2681 struct cred_list *cred;
2683 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
2685 cred = SMB_MALLOC_P(struct cred_list);
2687 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2693 /* save a copy of the key */
2695 fstrcpy(cred->name, (const char *)kbuf.dptr);
2696 DLIST_ADD(wcache_cred_list, cred);
2702 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const DOM_SID *sid)
2704 struct winbind_cache *cache = get_cache(domain);
2707 struct cred_list *cred, *oldest = NULL;
2710 return NT_STATUS_INTERNAL_DB_ERROR;
2713 /* we possibly already have an entry */
2714 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
2716 fstring key_str, tmp;
2718 DEBUG(11,("we already have an entry, deleting that\n"));
2720 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
2722 tdb_delete(cache->tdb, string_tdb_data(key_str));
2724 return NT_STATUS_OK;
2727 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
2729 return NT_STATUS_OK;
2730 } else if ((ret == -1) || (wcache_cred_list == NULL)) {
2731 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2734 ZERO_STRUCTP(oldest);
2736 for (cred = wcache_cred_list; cred; cred = cred->next) {
2741 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
2743 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
2745 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
2749 t = IVAL(data.dptr, 0);
2750 SAFE_FREE(data.dptr);
2753 oldest = SMB_MALLOC_P(struct cred_list);
2754 if (oldest == NULL) {
2755 status = NT_STATUS_NO_MEMORY;
2759 fstrcpy(oldest->name, cred->name);
2760 oldest->created = t;
2764 if (t < oldest->created) {
2765 fstrcpy(oldest->name, cred->name);
2766 oldest->created = t;
2770 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
2771 status = NT_STATUS_OK;
2773 status = NT_STATUS_UNSUCCESSFUL;
2776 SAFE_FREE(wcache_cred_list);
2782 /* Change the global online/offline state. */
2783 bool set_global_winbindd_state_offline(void)
2787 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
2789 /* Only go offline if someone has created
2790 the key "WINBINDD_OFFLINE" in the cache tdb. */
2792 if (wcache == NULL || wcache->tdb == NULL) {
2793 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
2797 if (!lp_winbind_offline_logon()) {
2798 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
2802 if (global_winbindd_offline_state) {
2803 /* Already offline. */
2807 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
2809 if (!data.dptr || data.dsize != 4) {
2810 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
2811 SAFE_FREE(data.dptr);
2814 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
2815 global_winbindd_offline_state = true;
2816 SAFE_FREE(data.dptr);
2821 void set_global_winbindd_state_online(void)
2823 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
2825 if (!lp_winbind_offline_logon()) {
2826 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
2830 if (!global_winbindd_offline_state) {
2831 /* Already online. */
2834 global_winbindd_offline_state = false;
2840 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
2841 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
2844 bool get_global_winbindd_state_offline(void)
2846 return global_winbindd_offline_state;
2849 /***********************************************************************
2850 Validate functions for all possible cache tdb keys.
2851 ***********************************************************************/
2853 static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
2854 struct tdb_validation_status *state)
2856 struct cache_entry *centry;
2858 centry = SMB_XMALLOC_P(struct cache_entry);
2859 centry->data = (unsigned char *)memdup(data.dptr, data.dsize);
2860 if (!centry->data) {
2864 centry->len = data.dsize;
2867 if (centry->len < 8) {
2868 /* huh? corrupt cache? */
2869 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr));
2870 centry_free(centry);
2871 state->bad_entry = true;
2872 state->success = false;
2876 centry->status = NT_STATUS(centry_uint32(centry));
2877 centry->sequence_number = centry_uint32(centry);
2881 static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2882 struct tdb_validation_status *state)
2884 if (dbuf.dsize != 8) {
2885 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
2886 keystr, (unsigned int)dbuf.dsize ));
2887 state->bad_entry = true;
2893 static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2894 struct tdb_validation_status *state)
2896 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2901 (void)centry_uint32(centry);
2902 if (NT_STATUS_IS_OK(centry->status)) {
2904 (void)centry_sid(centry, mem_ctx, &sid);
2907 centry_free(centry);
2909 if (!(state->success)) {
2912 DEBUG(10,("validate_ns: %s ok\n", keystr));
2916 static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2917 struct tdb_validation_status *state)
2919 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2924 if (NT_STATUS_IS_OK(centry->status)) {
2925 (void)centry_uint32(centry);
2926 (void)centry_string(centry, mem_ctx);
2927 (void)centry_string(centry, mem_ctx);
2930 centry_free(centry);
2932 if (!(state->success)) {
2935 DEBUG(10,("validate_sn: %s ok\n", keystr));
2939 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2940 struct tdb_validation_status *state)
2942 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2949 (void)centry_string(centry, mem_ctx);
2950 (void)centry_string(centry, mem_ctx);
2951 (void)centry_string(centry, mem_ctx);
2952 (void)centry_string(centry, mem_ctx);
2953 (void)centry_uint32(centry);
2954 (void)centry_sid(centry, mem_ctx, &sid);
2955 (void)centry_sid(centry, mem_ctx, &sid);
2957 centry_free(centry);
2959 if (!(state->success)) {
2962 DEBUG(10,("validate_u: %s ok\n", keystr));
2966 static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2967 struct tdb_validation_status *state)
2969 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2975 (void)centry_nttime(centry);
2976 (void)centry_nttime(centry);
2977 (void)centry_uint16(centry);
2979 centry_free(centry);
2981 if (!(state->success)) {
2984 DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
2988 static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2989 struct tdb_validation_status *state)
2991 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2997 (void)centry_uint16(centry);
2998 (void)centry_uint16(centry);
2999 (void)centry_uint32(centry);
3000 (void)centry_nttime(centry);
3001 (void)centry_nttime(centry);
3003 centry_free(centry);
3005 if (!(state->success)) {
3008 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
3012 static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3013 struct tdb_validation_status *state)
3015 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3021 (void)centry_time(centry);
3022 (void)centry_hash16(centry, mem_ctx);
3024 /* We only have 17 bytes more data in the salted cred case. */
3025 if (centry->len - centry->ofs == 17) {
3026 (void)centry_hash16(centry, mem_ctx);
3029 centry_free(centry);
3031 if (!(state->success)) {
3034 DEBUG(10,("validate_cred: %s ok\n", keystr));
3038 static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3039 struct tdb_validation_status *state)
3041 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3042 int32 num_entries, i;
3048 num_entries = (int32)centry_uint32(centry);
3050 for (i=0; i< num_entries; i++) {
3052 (void)centry_string(centry, mem_ctx);
3053 (void)centry_string(centry, mem_ctx);
3054 (void)centry_string(centry, mem_ctx);
3055 (void)centry_string(centry, mem_ctx);
3056 (void)centry_sid(centry, mem_ctx, &sid);
3057 (void)centry_sid(centry, mem_ctx, &sid);
3060 centry_free(centry);
3062 if (!(state->success)) {
3065 DEBUG(10,("validate_ul: %s ok\n", keystr));
3069 static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3070 struct tdb_validation_status *state)
3072 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3073 int32 num_entries, i;
3079 num_entries = centry_uint32(centry);
3081 for (i=0; i< num_entries; i++) {
3082 (void)centry_string(centry, mem_ctx);
3083 (void)centry_string(centry, mem_ctx);
3084 (void)centry_uint32(centry);
3087 centry_free(centry);
3089 if (!(state->success)) {
3092 DEBUG(10,("validate_gl: %s ok\n", keystr));
3096 static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3097 struct tdb_validation_status *state)
3099 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3100 int32 num_groups, i;
3106 num_groups = centry_uint32(centry);
3108 for (i=0; i< num_groups; i++) {
3110 centry_sid(centry, mem_ctx, &sid);
3113 centry_free(centry);
3115 if (!(state->success)) {
3118 DEBUG(10,("validate_ug: %s ok\n", keystr));
3122 static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3123 struct tdb_validation_status *state)
3125 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3126 int32 num_aliases, i;
3132 num_aliases = centry_uint32(centry);
3134 for (i=0; i < num_aliases; i++) {
3135 (void)centry_uint32(centry);
3138 centry_free(centry);
3140 if (!(state->success)) {
3143 DEBUG(10,("validate_ua: %s ok\n", keystr));
3147 static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3148 struct tdb_validation_status *state)
3150 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3157 num_names = centry_uint32(centry);
3159 for (i=0; i< num_names; i++) {
3161 centry_sid(centry, mem_ctx, &sid);
3162 (void)centry_string(centry, mem_ctx);
3163 (void)centry_uint32(centry);
3166 centry_free(centry);
3168 if (!(state->success)) {
3171 DEBUG(10,("validate_gm: %s ok\n", keystr));
3175 static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3176 struct tdb_validation_status *state)
3178 /* Can't say anything about this other than must be nonzero. */
3179 if (dbuf.dsize == 0) {
3180 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3182 state->bad_entry = true;
3183 state->success = false;
3187 DEBUG(10,("validate_dr: %s ok\n", keystr));
3191 static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3192 struct tdb_validation_status *state)
3194 /* Can't say anything about this other than must be nonzero. */
3195 if (dbuf.dsize == 0) {
3196 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3198 state->bad_entry = true;
3199 state->success = false;
3203 DEBUG(10,("validate_de: %s ok\n", keystr));
3207 static int validate_trustdoms(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3208 struct tdb_validation_status *state)
3210 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3211 int32 num_domains, i;
3217 num_domains = centry_uint32(centry);
3219 for (i=0; i< num_domains; i++) {
3221 (void)centry_string(centry, mem_ctx);
3222 (void)centry_string(centry, mem_ctx);
3223 (void)centry_sid(centry, mem_ctx, &sid);
3226 centry_free(centry);
3228 if (!(state->success)) {
3231 DEBUG(10,("validate_trustdoms: %s ok\n", keystr));
3235 static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
3237 struct tdb_validation_status *state)
3239 if (dbuf.dsize == 0) {
3240 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3241 "key %s (len ==0) ?\n", keystr));
3242 state->bad_entry = true;
3243 state->success = false;
3247 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
3248 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3252 static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3253 struct tdb_validation_status *state)
3255 if (dbuf.dsize != 4) {
3256 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3257 keystr, (unsigned int)dbuf.dsize ));
3258 state->bad_entry = true;
3259 state->success = false;
3262 DEBUG(10,("validate_offline: %s ok\n", keystr));
3266 static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3267 struct tdb_validation_status *state)
3269 if (dbuf.dsize != 4) {
3270 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3271 "key %s (len %u != 4) ?\n",
3272 keystr, (unsigned int)dbuf.dsize));
3273 state->bad_entry = true;
3274 state->success = false;
3278 DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
3282 /***********************************************************************
3283 A list of all possible cache tdb keys with associated validation
3285 ***********************************************************************/
3287 struct key_val_struct {
3288 const char *keyname;
3289 int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
3291 {"SEQNUM/", validate_seqnum},
3292 {"NS/", validate_ns},
3293 {"SN/", validate_sn},
3295 {"LOC_POL/", validate_loc_pol},
3296 {"PWD_POL/", validate_pwd_pol},
3297 {"CRED/", validate_cred},
3298 {"UL/", validate_ul},
3299 {"GL/", validate_gl},
3300 {"UG/", validate_ug},
3301 {"UA", validate_ua},
3302 {"GM/", validate_gm},
3303 {"DR/", validate_dr},
3304 {"DE/", validate_de},
3305 {"TRUSTDOMS/", validate_trustdoms},
3306 {"TRUSTDOMCACHE/", validate_trustdomcache},
3307 {"WINBINDD_OFFLINE", validate_offline},
3308 {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
3312 /***********************************************************************
3313 Function to look at every entry in the tdb and validate it as far as
3315 ***********************************************************************/
3317 static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
3320 struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
3322 /* Paranoia check. */
3323 if (kbuf.dsize > 1024) {
3324 DEBUG(0,("cache_traverse_validate_fn: key length too large (%u) > 1024\n\n",
3325 (unsigned int)kbuf.dsize ));
3329 for (i = 0; key_val[i].keyname; i++) {
3330 size_t namelen = strlen(key_val[i].keyname);
3331 if (kbuf.dsize >= namelen && (
3332 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
3333 TALLOC_CTX *mem_ctx;
3337 keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
3341 memcpy(keystr, kbuf.dptr, kbuf.dsize);
3342 keystr[kbuf.dsize] = '\0';
3344 mem_ctx = talloc_init("validate_ctx");
3350 ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
3354 talloc_destroy(mem_ctx);
3359 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
3360 dump_data(0, (uint8 *)kbuf.dptr, kbuf.dsize);
3361 DEBUG(0,("data :\n"));
3362 dump_data(0, (uint8 *)dbuf.dptr, dbuf.dsize);
3363 v_state->unknown_key = true;
3364 v_state->success = false;
3365 return 1; /* terminate. */
3368 static void validate_panic(const char *const why)
3370 DEBUG(0,("validating cache: would panic %s\n", why ));
3371 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
3375 /***********************************************************************
3376 Try and validate every entry in the winbindd cache. If we fail here,
3377 delete the cache tdb and return non-zero.
3378 ***********************************************************************/
3380 int winbindd_validate_cache(void)
3383 const char *tdb_path = lock_path("winbindd_cache.tdb");
3384 TDB_CONTEXT *tdb = NULL;
3386 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3387 smb_panic_fn = validate_panic;
3390 tdb = tdb_open_log(tdb_path,
3391 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3392 ( lp_winbind_offline_logon()
3394 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
3398 DEBUG(0, ("winbindd_validate_cache: "
3399 "error opening/initializing tdb\n"));
3404 ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
3407 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
3408 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
3413 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
3414 smb_panic_fn = smb_panic;
3418 /***********************************************************************
3419 Try and validate every entry in the winbindd cache.
3420 ***********************************************************************/
3422 int winbindd_validate_cache_nobackup(void)
3425 const char *tdb_path = lock_path("winbindd_cache.tdb");
3427 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3428 smb_panic_fn = validate_panic;
3431 if (wcache == NULL || wcache->tdb == NULL) {
3432 ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
3434 ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
3438 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
3442 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
3444 smb_panic_fn = smb_panic;
3448 /*********************************************************************
3449 ********************************************************************/
3451 static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
3452 struct winbindd_tdc_domain **domains,
3453 size_t *num_domains )
3455 struct winbindd_tdc_domain *list = NULL;
3458 bool set_only = false;
3460 /* don't allow duplicates */
3465 for ( i=0; i< (*num_domains); i++ ) {
3466 if ( strequal( new_dom->name, list[i].domain_name ) ) {
3467 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
3478 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, 1 );
3481 list = TALLOC_REALLOC_ARRAY( *domains, *domains,
3482 struct winbindd_tdc_domain,
3487 ZERO_STRUCT( list[idx] );
3493 list[idx].domain_name = talloc_strdup( list, new_dom->name );
3494 list[idx].dns_name = talloc_strdup( list, new_dom->alt_name );
3496 if ( !is_null_sid( &new_dom->sid ) )
3497 sid_copy( &list[idx].sid, &new_dom->sid );
3499 if ( new_dom->domain_flags != 0x0 )
3500 list[idx].trust_flags = new_dom->domain_flags;
3502 if ( new_dom->domain_type != 0x0 )
3503 list[idx].trust_type = new_dom->domain_type;
3505 if ( new_dom->domain_trust_attribs != 0x0 )
3506 list[idx].trust_attribs = new_dom->domain_trust_attribs;
3510 *num_domains = idx + 1;
3516 /*********************************************************************
3517 ********************************************************************/
3519 static TDB_DATA make_tdc_key( const char *domain_name )
3521 char *keystr = NULL;
3522 TDB_DATA key = { NULL, 0 };
3524 if ( !domain_name ) {
3525 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
3530 asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name );
3531 key = string_term_tdb_data(keystr);
3536 /*********************************************************************
3537 ********************************************************************/
3539 static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
3541 unsigned char **buf )
3543 unsigned char *buffer = NULL;
3548 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
3556 /* Store the number of array items first */
3557 len += tdb_pack( buffer+len, buflen-len, "d",
3560 /* now pack each domain trust record */
3561 for ( i=0; i<num_domains; i++ ) {
3566 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
3567 domains[i].domain_name,
3568 domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
3571 len += tdb_pack( buffer+len, buflen-len, "fffddd",
3572 domains[i].domain_name,
3573 domains[i].dns_name,
3574 sid_to_fstring(tmp, &domains[i].sid),
3575 domains[i].trust_flags,
3576 domains[i].trust_attribs,
3577 domains[i].trust_type );
3580 if ( buflen < len ) {
3582 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
3583 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
3597 /*********************************************************************
3598 ********************************************************************/
3600 static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
3601 struct winbindd_tdc_domain **domains )
3603 fstring domain_name, dns_name, sid_string;
3604 uint32 type, attribs, flags;
3608 struct winbindd_tdc_domain *list = NULL;
3610 /* get the number of domains */
3611 len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
3613 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3617 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, num_domains );
3619 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
3623 for ( i=0; i<num_domains; i++ ) {
3624 len += tdb_unpack( buf+len, buflen-len, "fffddd",
3633 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3634 TALLOC_FREE( list );
3638 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
3639 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
3640 domain_name, dns_name, sid_string,
3641 flags, attribs, type));
3643 list[i].domain_name = talloc_strdup( list, domain_name );
3644 list[i].dns_name = talloc_strdup( list, dns_name );
3645 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
3646 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
3649 list[i].trust_flags = flags;
3650 list[i].trust_attribs = attribs;
3651 list[i].trust_type = type;
3659 /*********************************************************************
3660 ********************************************************************/
3662 static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
3664 TDB_DATA key = make_tdc_key( lp_workgroup() );
3665 TDB_DATA data = { NULL, 0 };
3671 /* See if we were asked to delete the cache entry */
3674 ret = tdb_delete( wcache->tdb, key );
3678 data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
3685 ret = tdb_store( wcache->tdb, key, data, 0 );
3688 SAFE_FREE( data.dptr );
3689 SAFE_FREE( key.dptr );
3691 return ( ret != -1 );
3694 /*********************************************************************
3695 ********************************************************************/
3697 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
3699 TDB_DATA key = make_tdc_key( lp_workgroup() );
3700 TDB_DATA data = { NULL, 0 };
3708 data = tdb_fetch( wcache->tdb, key );
3710 SAFE_FREE( key.dptr );
3715 *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
3717 SAFE_FREE( data.dptr );
3725 /*********************************************************************
3726 ********************************************************************/
3728 bool wcache_tdc_add_domain( struct winbindd_domain *domain )
3730 struct winbindd_tdc_domain *dom_list = NULL;
3731 size_t num_domains = 0;
3734 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
3735 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
3736 domain->name, domain->alt_name,
3737 sid_string_dbg(&domain->sid),
3738 domain->domain_flags,
3739 domain->domain_trust_attribs,
3740 domain->domain_type));
3742 if ( !init_wcache() ) {
3746 /* fetch the list */
3748 wcache_tdc_fetch_list( &dom_list, &num_domains );
3750 /* add the new domain */
3752 if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
3756 /* pack the domain */
3758 if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
3766 TALLOC_FREE( dom_list );
3771 /*********************************************************************
3772 ********************************************************************/
3774 struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
3776 struct winbindd_tdc_domain *dom_list = NULL;
3777 size_t num_domains = 0;
3779 struct winbindd_tdc_domain *d = NULL;
3781 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
3783 if ( !init_wcache() ) {
3787 /* fetch the list */
3789 wcache_tdc_fetch_list( &dom_list, &num_domains );
3791 for ( i=0; i<num_domains; i++ ) {
3792 if ( strequal(name, dom_list[i].domain_name) ||
3793 strequal(name, dom_list[i].dns_name) )
3795 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
3798 d = TALLOC_P( ctx, struct winbindd_tdc_domain );
3802 d->domain_name = talloc_strdup( d, dom_list[i].domain_name );
3803 d->dns_name = talloc_strdup( d, dom_list[i].dns_name );
3804 sid_copy( &d->sid, &dom_list[i].sid );
3805 d->trust_flags = dom_list[i].trust_flags;
3806 d->trust_type = dom_list[i].trust_type;
3807 d->trust_attribs = dom_list[i].trust_attribs;
3813 TALLOC_FREE( dom_list );
3819 /*********************************************************************
3820 ********************************************************************/
3822 void wcache_tdc_clear( void )
3824 if ( !init_wcache() )
3827 wcache_tdc_store_list( NULL, 0 );
3833 /*********************************************************************
3834 ********************************************************************/
3836 static void wcache_save_user_pwinfo(struct winbindd_domain *domain,
3838 const DOM_SID *user_sid,
3839 const char *homedir,
3844 struct cache_entry *centry;
3847 if ( (centry = centry_start(domain, status)) == NULL )
3850 centry_put_string( centry, homedir );
3851 centry_put_string( centry, shell );
3852 centry_put_string( centry, gecos );
3853 centry_put_uint32( centry, gid );
3855 centry_end(centry, "NSS/PWINFO/%s", sid_to_fstring(tmp, user_sid) );
3857 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid) ));
3859 centry_free(centry);
3862 NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
3863 const DOM_SID *user_sid,
3865 ADS_STRUCT *ads, LDAPMessage *msg,
3866 char **homedir, char **shell, char **gecos,
3869 struct winbind_cache *cache = get_cache(domain);
3870 struct cache_entry *centry = NULL;
3877 centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s",
3878 sid_to_fstring(tmp, user_sid));
3883 *homedir = centry_string( centry, ctx );
3884 *shell = centry_string( centry, ctx );
3885 *gecos = centry_string( centry, ctx );
3886 *p_gid = centry_uint32( centry );
3888 centry_free(centry);
3890 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
3891 sid_string_dbg(user_sid)));
3893 return NT_STATUS_OK;
3897 nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg,
3898 homedir, shell, gecos, p_gid );
3900 if ( NT_STATUS_IS_OK(nt_status) ) {
3901 wcache_save_user_pwinfo( domain, nt_status, user_sid,
3902 *homedir, *shell, *gecos, *p_gid );
3905 if ( NT_STATUS_EQUAL( nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
3906 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
3908 set_domain_offline( domain );
3915 /* the cache backend methods are exposed via this structure */
3916 struct winbindd_methods cache_methods = {