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, NTSTATUS status, SAM_UNK_INFO_12 *lockout_policy)
913 struct cache_entry *centry;
915 centry = centry_start(domain, status);
919 centry_put_nttime(centry, lockout_policy->duration);
920 centry_put_nttime(centry, lockout_policy->reset_count);
921 centry_put_uint16(centry, lockout_policy->bad_attempt_lockout);
923 centry_end(centry, "LOC_POL/%s", domain->name);
925 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
930 static void wcache_save_password_policy(struct winbindd_domain *domain, NTSTATUS status, SAM_UNK_INFO_1 *policy)
932 struct cache_entry *centry;
934 centry = centry_start(domain, status);
938 centry_put_uint16(centry, policy->min_length_password);
939 centry_put_uint16(centry, policy->password_history);
940 centry_put_uint32(centry, policy->password_properties);
941 centry_put_nttime(centry, policy->expire);
942 centry_put_nttime(centry, policy->min_passwordage);
944 centry_end(centry, "PWD_POL/%s", domain->name);
946 DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
951 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const DOM_SID *sid)
953 struct winbind_cache *cache = get_cache(domain);
955 fstring key_str, tmp;
959 return NT_STATUS_INTERNAL_DB_ERROR;
962 if (is_null_sid(sid)) {
963 return NT_STATUS_INVALID_SID;
966 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
967 return NT_STATUS_INVALID_SID;
970 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
972 data = tdb_fetch(cache->tdb, string_tdb_data(key_str));
974 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
977 SAFE_FREE(data.dptr);
981 /* Lookup creds for a SID - copes with old (unsalted) creds as well
982 as new salted ones. */
984 NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
987 const uint8 **cached_nt_pass,
988 const uint8 **cached_salt)
990 struct winbind_cache *cache = get_cache(domain);
991 struct cache_entry *centry = NULL;
998 return NT_STATUS_INTERNAL_DB_ERROR;
1001 if (is_null_sid(sid)) {
1002 return NT_STATUS_INVALID_SID;
1005 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1006 return NT_STATUS_INVALID_SID;
1009 /* Try and get a salted cred first. If we can't
1010 fall back to an unsalted cred. */
1012 centry = wcache_fetch(cache, domain, "CRED/%s",
1013 sid_to_fstring(tmp, sid));
1015 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1016 sid_string_dbg(sid)));
1017 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1020 t = centry_time(centry);
1022 /* In the salted case this isn't actually the nt_hash itself,
1023 but the MD5 of the salt + nt_hash. Let the caller
1024 sort this out. It can tell as we only return the cached_salt
1025 if we are returning a salted cred. */
1027 *cached_nt_pass = (const uint8 *)centry_hash16(centry, mem_ctx);
1028 if (*cached_nt_pass == NULL) {
1031 sid_to_fstring(sidstr, sid);
1033 /* Bad (old) cred cache. Delete and pretend we
1035 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1037 wcache_delete("CRED/%s", sidstr);
1038 centry_free(centry);
1039 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1042 /* We only have 17 bytes more data in the salted cred case. */
1043 if (centry->len - centry->ofs == 17) {
1044 *cached_salt = (const uint8 *)centry_hash16(centry, mem_ctx);
1046 *cached_salt = NULL;
1049 dump_data_pw("cached_nt_pass", *cached_nt_pass, NT_HASH_LEN);
1051 dump_data_pw("cached_salt", *cached_salt, NT_HASH_LEN);
1054 status = centry->status;
1056 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1057 sid_string_dbg(sid), nt_errstr(status) ));
1059 centry_free(centry);
1063 /* Store creds for a SID - only writes out new salted ones. */
1065 NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
1066 TALLOC_CTX *mem_ctx,
1068 const uint8 nt_pass[NT_HASH_LEN])
1070 struct cache_entry *centry;
1073 uint8 cred_salt[NT_HASH_LEN];
1074 uint8 salted_hash[NT_HASH_LEN];
1076 if (is_null_sid(sid)) {
1077 return NT_STATUS_INVALID_SID;
1080 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1081 return NT_STATUS_INVALID_SID;
1084 centry = centry_start(domain, NT_STATUS_OK);
1086 return NT_STATUS_INTERNAL_DB_ERROR;
1089 dump_data_pw("nt_pass", nt_pass, NT_HASH_LEN);
1091 centry_put_time(centry, time(NULL));
1093 /* Create a salt and then salt the hash. */
1094 generate_random_buffer(cred_salt, NT_HASH_LEN);
1095 E_md5hash(cred_salt, nt_pass, salted_hash);
1097 centry_put_hash16(centry, salted_hash);
1098 centry_put_hash16(centry, cred_salt);
1099 centry_end(centry, "CRED/%s", sid_to_fstring(sid_string, sid));
1101 DEBUG(10,("wcache_save_creds: %s\n", sid_string));
1103 centry_free(centry);
1105 return NT_STATUS_OK;
1109 /* Query display info. This is the basic user list fn */
1110 static NTSTATUS query_user_list(struct winbindd_domain *domain,
1111 TALLOC_CTX *mem_ctx,
1112 uint32 *num_entries,
1113 WINBIND_USERINFO **info)
1115 struct winbind_cache *cache = get_cache(domain);
1116 struct cache_entry *centry = NULL;
1118 unsigned int i, retry;
1123 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1127 *num_entries = centry_uint32(centry);
1129 if (*num_entries == 0)
1132 (*info) = TALLOC_ARRAY(mem_ctx, WINBIND_USERINFO, *num_entries);
1134 smb_panic_fn("query_user_list out of memory");
1136 for (i=0; i<(*num_entries); i++) {
1137 (*info)[i].acct_name = centry_string(centry, mem_ctx);
1138 (*info)[i].full_name = centry_string(centry, mem_ctx);
1139 (*info)[i].homedir = centry_string(centry, mem_ctx);
1140 (*info)[i].shell = centry_string(centry, mem_ctx);
1141 centry_sid(centry, mem_ctx, &(*info)[i].user_sid);
1142 centry_sid(centry, mem_ctx, &(*info)[i].group_sid);
1146 status = centry->status;
1148 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1149 domain->name, nt_errstr(status) ));
1151 centry_free(centry);
1158 /* Return status value returned by seq number check */
1160 if (!NT_STATUS_IS_OK(domain->last_status))
1161 return domain->last_status;
1163 /* Put the query_user_list() in a retry loop. There appears to be
1164 * some bug either with Windows 2000 or Samba's handling of large
1165 * rpc replies. This manifests itself as sudden disconnection
1166 * at a random point in the enumeration of a large (60k) user list.
1167 * The retry loop simply tries the operation again. )-: It's not
1168 * pretty but an acceptable workaround until we work out what the
1169 * real problem is. */
1174 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1177 status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
1178 if (!NT_STATUS_IS_OK(status)) {
1179 DEBUG(3, ("query_user_list: returned 0x%08x, "
1180 "retrying\n", NT_STATUS_V(status)));
1182 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1183 DEBUG(3, ("query_user_list: flushing "
1184 "connection cache\n"));
1185 invalidate_cm_connection(&domain->conn);
1188 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
1192 refresh_sequence_number(domain, False);
1193 centry = centry_start(domain, status);
1196 centry_put_uint32(centry, *num_entries);
1197 for (i=0; i<(*num_entries); i++) {
1198 centry_put_string(centry, (*info)[i].acct_name);
1199 centry_put_string(centry, (*info)[i].full_name);
1200 centry_put_string(centry, (*info)[i].homedir);
1201 centry_put_string(centry, (*info)[i].shell);
1202 centry_put_sid(centry, &(*info)[i].user_sid);
1203 centry_put_sid(centry, &(*info)[i].group_sid);
1204 if (domain->backend && domain->backend->consistent) {
1205 /* when the backend is consistent we can pre-prime some mappings */
1206 wcache_save_name_to_sid(domain, NT_STATUS_OK,
1208 (*info)[i].acct_name,
1209 &(*info)[i].user_sid,
1211 wcache_save_sid_to_name(domain, NT_STATUS_OK,
1212 &(*info)[i].user_sid,
1214 (*info)[i].acct_name,
1216 wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
1219 centry_end(centry, "UL/%s", domain->name);
1220 centry_free(centry);
1226 /* list all domain groups */
1227 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
1228 TALLOC_CTX *mem_ctx,
1229 uint32 *num_entries,
1230 struct acct_info **info)
1232 struct winbind_cache *cache = get_cache(domain);
1233 struct cache_entry *centry = NULL;
1240 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1244 *num_entries = centry_uint32(centry);
1246 if (*num_entries == 0)
1249 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1251 smb_panic_fn("enum_dom_groups out of memory");
1253 for (i=0; i<(*num_entries); i++) {
1254 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1255 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1256 (*info)[i].rid = centry_uint32(centry);
1260 status = centry->status;
1262 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1263 domain->name, nt_errstr(status) ));
1265 centry_free(centry);
1272 /* Return status value returned by seq number check */
1274 if (!NT_STATUS_IS_OK(domain->last_status))
1275 return domain->last_status;
1277 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1280 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1283 refresh_sequence_number(domain, False);
1284 centry = centry_start(domain, status);
1287 centry_put_uint32(centry, *num_entries);
1288 for (i=0; i<(*num_entries); i++) {
1289 centry_put_string(centry, (*info)[i].acct_name);
1290 centry_put_string(centry, (*info)[i].acct_desc);
1291 centry_put_uint32(centry, (*info)[i].rid);
1293 centry_end(centry, "GL/%s/domain", domain->name);
1294 centry_free(centry);
1300 /* list all domain groups */
1301 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
1302 TALLOC_CTX *mem_ctx,
1303 uint32 *num_entries,
1304 struct acct_info **info)
1306 struct winbind_cache *cache = get_cache(domain);
1307 struct cache_entry *centry = NULL;
1314 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1318 *num_entries = centry_uint32(centry);
1320 if (*num_entries == 0)
1323 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1325 smb_panic_fn("enum_dom_groups out of memory");
1327 for (i=0; i<(*num_entries); i++) {
1328 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1329 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1330 (*info)[i].rid = centry_uint32(centry);
1335 /* If we are returning cached data and the domain controller
1336 is down then we don't know whether the data is up to date
1337 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1340 if (wcache_server_down(domain)) {
1341 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1342 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1344 status = centry->status;
1346 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1347 domain->name, nt_errstr(status) ));
1349 centry_free(centry);
1356 /* Return status value returned by seq number check */
1358 if (!NT_STATUS_IS_OK(domain->last_status))
1359 return domain->last_status;
1361 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1364 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1367 refresh_sequence_number(domain, False);
1368 centry = centry_start(domain, status);
1371 centry_put_uint32(centry, *num_entries);
1372 for (i=0; i<(*num_entries); i++) {
1373 centry_put_string(centry, (*info)[i].acct_name);
1374 centry_put_string(centry, (*info)[i].acct_desc);
1375 centry_put_uint32(centry, (*info)[i].rid);
1377 centry_end(centry, "GL/%s/local", domain->name);
1378 centry_free(centry);
1384 /* convert a single name to a sid in a domain */
1385 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
1386 TALLOC_CTX *mem_ctx,
1387 enum winbindd_cmd orig_cmd,
1388 const char *domain_name,
1391 enum lsa_SidType *type)
1393 struct winbind_cache *cache = get_cache(domain);
1394 struct cache_entry *centry = NULL;
1401 fstrcpy(uname, name);
1403 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1407 status = centry->status;
1408 if (NT_STATUS_IS_OK(status)) {
1409 *type = (enum lsa_SidType)centry_uint32(centry);
1410 centry_sid(centry, mem_ctx, sid);
1413 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: %s\n",
1414 domain->name, nt_errstr(status) ));
1416 centry_free(centry);
1422 /* If the seq number check indicated that there is a problem
1423 * with this DC, then return that status... except for
1424 * access_denied. This is special because the dc may be in
1425 * "restrict anonymous = 1" mode, in which case it will deny
1426 * most unauthenticated operations, but *will* allow the LSA
1427 * name-to-sid that we try as a fallback. */
1429 if (!(NT_STATUS_IS_OK(domain->last_status)
1430 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1431 return domain->last_status;
1433 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1436 status = domain->backend->name_to_sid(domain, mem_ctx, orig_cmd,
1437 domain_name, name, sid, type);
1440 refresh_sequence_number(domain, False);
1442 if (domain->online &&
1443 (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
1444 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1446 /* Only save the reverse mapping if this was not a UPN */
1447 if (!strchr(name, '@')) {
1448 strupper_m(CONST_DISCARD(char *,domain_name));
1449 strlower_m(CONST_DISCARD(char *,name));
1450 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1457 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1459 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
1460 TALLOC_CTX *mem_ctx,
1464 enum lsa_SidType *type)
1466 struct winbind_cache *cache = get_cache(domain);
1467 struct cache_entry *centry = NULL;
1474 centry = wcache_fetch(cache, domain, "SN/%s",
1475 sid_to_fstring(sid_string, sid));
1479 status = centry->status;
1480 if (NT_STATUS_IS_OK(status)) {
1481 *type = (enum lsa_SidType)centry_uint32(centry);
1482 *domain_name = centry_string(centry, mem_ctx);
1483 *name = centry_string(centry, mem_ctx);
1486 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: %s\n",
1487 domain->name, nt_errstr(status) ));
1489 centry_free(centry);
1494 *domain_name = NULL;
1496 /* If the seq number check indicated that there is a problem
1497 * with this DC, then return that status... except for
1498 * access_denied. This is special because the dc may be in
1499 * "restrict anonymous = 1" mode, in which case it will deny
1500 * most unauthenticated operations, but *will* allow the LSA
1501 * sid-to-name that we try as a fallback. */
1503 if (!(NT_STATUS_IS_OK(domain->last_status)
1504 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1505 return domain->last_status;
1507 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1510 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1513 refresh_sequence_number(domain, False);
1514 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1516 /* We can't save the name to sid mapping here, as with sid history a
1517 * later name2sid would give the wrong sid. */
1522 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
1523 TALLOC_CTX *mem_ctx,
1524 const DOM_SID *domain_sid,
1529 enum lsa_SidType **types)
1531 struct winbind_cache *cache = get_cache(domain);
1533 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1537 *domain_name = NULL;
1545 if (num_rids == 0) {
1546 return NT_STATUS_OK;
1549 *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
1550 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
1552 if ((*names == NULL) || (*types == NULL)) {
1553 result = NT_STATUS_NO_MEMORY;
1557 have_mapped = have_unmapped = False;
1559 for (i=0; i<num_rids; i++) {
1561 struct cache_entry *centry;
1564 if (!sid_compose(&sid, domain_sid, rids[i])) {
1565 result = NT_STATUS_INTERNAL_ERROR;
1569 centry = wcache_fetch(cache, domain, "SN/%s",
1570 sid_to_fstring(tmp, &sid));
1575 (*types)[i] = SID_NAME_UNKNOWN;
1576 (*names)[i] = talloc_strdup(*names, "");
1578 if (NT_STATUS_IS_OK(centry->status)) {
1581 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
1583 dom = centry_string(centry, mem_ctx);
1584 if (*domain_name == NULL) {
1590 (*names)[i] = centry_string(centry, *names);
1592 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
1593 have_unmapped = True;
1596 /* something's definitely wrong */
1597 result = centry->status;
1601 centry_free(centry);
1605 return NT_STATUS_NONE_MAPPED;
1607 if (!have_unmapped) {
1608 return NT_STATUS_OK;
1610 return STATUS_SOME_UNMAPPED;
1614 TALLOC_FREE(*names);
1615 TALLOC_FREE(*types);
1617 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
1618 rids, num_rids, domain_name,
1622 None of the queried rids has been found so save all negative entries
1624 if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
1625 for (i = 0; i < num_rids; i++) {
1627 const char *name = "";
1628 const enum lsa_SidType type = SID_NAME_UNKNOWN;
1629 NTSTATUS status = NT_STATUS_NONE_MAPPED;
1631 if (!sid_compose(&sid, domain_sid, rids[i])) {
1632 return NT_STATUS_INTERNAL_ERROR;
1635 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
1643 Some or all of the queried rids have been found.
1645 if (!NT_STATUS_IS_OK(result) &&
1646 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
1650 refresh_sequence_number(domain, False);
1652 for (i=0; i<num_rids; i++) {
1656 if (!sid_compose(&sid, domain_sid, rids[i])) {
1657 result = NT_STATUS_INTERNAL_ERROR;
1661 status = (*types)[i] == SID_NAME_UNKNOWN ?
1662 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
1664 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
1665 (*names)[i], (*types)[i]);
1672 TALLOC_FREE(*names);
1673 TALLOC_FREE(*types);
1677 /* Lookup user information from a rid */
1678 static NTSTATUS query_user(struct winbindd_domain *domain,
1679 TALLOC_CTX *mem_ctx,
1680 const DOM_SID *user_sid,
1681 WINBIND_USERINFO *info)
1683 struct winbind_cache *cache = get_cache(domain);
1684 struct cache_entry *centry = NULL;
1691 centry = wcache_fetch(cache, domain, "U/%s",
1692 sid_to_fstring(tmp, user_sid));
1694 /* If we have an access denied cache entry and a cached info3 in the
1695 samlogon cache then do a query. This will force the rpc back end
1696 to return the info3 data. */
1698 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1699 netsamlogon_cache_have(user_sid)) {
1700 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1701 domain->last_status = NT_STATUS_OK;
1702 centry_free(centry);
1709 /* if status is not ok then this is a negative hit
1710 and the rest of the data doesn't matter */
1711 status = centry->status;
1712 if (NT_STATUS_IS_OK(status)) {
1713 info->acct_name = centry_string(centry, mem_ctx);
1714 info->full_name = centry_string(centry, mem_ctx);
1715 info->homedir = centry_string(centry, mem_ctx);
1716 info->shell = centry_string(centry, mem_ctx);
1717 info->primary_gid = centry_uint32(centry);
1718 centry_sid(centry, mem_ctx, &info->user_sid);
1719 centry_sid(centry, mem_ctx, &info->group_sid);
1722 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: %s\n",
1723 domain->name, nt_errstr(status) ));
1725 centry_free(centry);
1731 /* Return status value returned by seq number check */
1733 if (!NT_STATUS_IS_OK(domain->last_status))
1734 return domain->last_status;
1736 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
1739 status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
1742 refresh_sequence_number(domain, False);
1743 wcache_save_user(domain, status, info);
1749 /* Lookup groups a user is a member of. */
1750 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
1751 TALLOC_CTX *mem_ctx,
1752 const DOM_SID *user_sid,
1753 uint32 *num_groups, DOM_SID **user_gids)
1755 struct winbind_cache *cache = get_cache(domain);
1756 struct cache_entry *centry = NULL;
1764 centry = wcache_fetch(cache, domain, "UG/%s",
1765 sid_to_fstring(sid_string, user_sid));
1767 /* If we have an access denied cache entry and a cached info3 in the
1768 samlogon cache then do a query. This will force the rpc back end
1769 to return the info3 data. */
1771 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1772 netsamlogon_cache_have(user_sid)) {
1773 DEBUG(10, ("lookup_usergroups: cached access denied and have cached info3\n"));
1774 domain->last_status = NT_STATUS_OK;
1775 centry_free(centry);
1782 *num_groups = centry_uint32(centry);
1784 if (*num_groups == 0)
1787 (*user_gids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
1788 if (! (*user_gids)) {
1789 smb_panic_fn("lookup_usergroups out of memory");
1791 for (i=0; i<(*num_groups); i++) {
1792 centry_sid(centry, mem_ctx, &(*user_gids)[i]);
1796 status = centry->status;
1798 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status: %s\n",
1799 domain->name, nt_errstr(status) ));
1801 centry_free(centry);
1806 (*user_gids) = NULL;
1808 /* Return status value returned by seq number check */
1810 if (!NT_STATUS_IS_OK(domain->last_status))
1811 return domain->last_status;
1813 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
1816 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
1818 if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
1822 refresh_sequence_number(domain, False);
1823 centry = centry_start(domain, status);
1827 centry_put_uint32(centry, *num_groups);
1828 for (i=0; i<(*num_groups); i++) {
1829 centry_put_sid(centry, &(*user_gids)[i]);
1832 centry_end(centry, "UG/%s", sid_to_fstring(sid_string, user_sid));
1833 centry_free(centry);
1839 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
1840 TALLOC_CTX *mem_ctx,
1841 uint32 num_sids, const DOM_SID *sids,
1842 uint32 *num_aliases, uint32 **alias_rids)
1844 struct winbind_cache *cache = get_cache(domain);
1845 struct cache_entry *centry = NULL;
1847 char *sidlist = talloc_strdup(mem_ctx, "");
1853 if (num_sids == 0) {
1856 return NT_STATUS_OK;
1859 /* We need to cache indexed by the whole list of SIDs, the aliases
1860 * resulting might come from any of the SIDs. */
1862 for (i=0; i<num_sids; i++) {
1864 sidlist = talloc_asprintf(mem_ctx, "%s/%s", sidlist,
1865 sid_to_fstring(tmp, &sids[i]));
1866 if (sidlist == NULL)
1867 return NT_STATUS_NO_MEMORY;
1870 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
1875 *num_aliases = centry_uint32(centry);
1879 (*alias_rids) = TALLOC_ARRAY(mem_ctx, uint32, *num_aliases);
1881 if ((*alias_rids) == NULL) {
1882 centry_free(centry);
1883 return NT_STATUS_NO_MEMORY;
1886 (*alias_rids) = NULL;
1889 for (i=0; i<(*num_aliases); i++)
1890 (*alias_rids)[i] = centry_uint32(centry);
1892 status = centry->status;
1894 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
1895 "status %s\n", domain->name, nt_errstr(status)));
1897 centry_free(centry);
1902 (*alias_rids) = NULL;
1904 if (!NT_STATUS_IS_OK(domain->last_status))
1905 return domain->last_status;
1907 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
1908 "for domain %s\n", domain->name ));
1910 status = domain->backend->lookup_useraliases(domain, mem_ctx,
1912 num_aliases, alias_rids);
1915 refresh_sequence_number(domain, False);
1916 centry = centry_start(domain, status);
1919 centry_put_uint32(centry, *num_aliases);
1920 for (i=0; i<(*num_aliases); i++)
1921 centry_put_uint32(centry, (*alias_rids)[i]);
1922 centry_end(centry, "UA%s", sidlist);
1923 centry_free(centry);
1930 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1931 TALLOC_CTX *mem_ctx,
1932 const DOM_SID *group_sid, uint32 *num_names,
1933 DOM_SID **sid_mem, char ***names,
1934 uint32 **name_types)
1936 struct winbind_cache *cache = get_cache(domain);
1937 struct cache_entry *centry = NULL;
1945 centry = wcache_fetch(cache, domain, "GM/%s",
1946 sid_to_fstring(sid_string, group_sid));
1950 *num_names = centry_uint32(centry);
1952 if (*num_names == 0)
1955 (*sid_mem) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_names);
1956 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_names);
1957 (*name_types) = TALLOC_ARRAY(mem_ctx, uint32, *num_names);
1959 if (! (*sid_mem) || ! (*names) || ! (*name_types)) {
1960 smb_panic_fn("lookup_groupmem out of memory");
1963 for (i=0; i<(*num_names); i++) {
1964 centry_sid(centry, mem_ctx, &(*sid_mem)[i]);
1965 (*names)[i] = centry_string(centry, mem_ctx);
1966 (*name_types)[i] = centry_uint32(centry);
1970 status = centry->status;
1972 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status: %s\n",
1973 domain->name, nt_errstr(status)));
1975 centry_free(centry);
1982 (*name_types) = NULL;
1984 /* Return status value returned by seq number check */
1986 if (!NT_STATUS_IS_OK(domain->last_status))
1987 return domain->last_status;
1989 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
1992 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid, num_names,
1993 sid_mem, names, name_types);
1996 refresh_sequence_number(domain, False);
1997 centry = centry_start(domain, status);
2000 centry_put_uint32(centry, *num_names);
2001 for (i=0; i<(*num_names); i++) {
2002 centry_put_sid(centry, &(*sid_mem)[i]);
2003 centry_put_string(centry, (*names)[i]);
2004 centry_put_uint32(centry, (*name_types)[i]);
2006 centry_end(centry, "GM/%s", sid_to_fstring(sid_string, group_sid));
2007 centry_free(centry);
2013 /* find the sequence number for a domain */
2014 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
2016 refresh_sequence_number(domain, False);
2018 *seq = domain->sequence_number;
2020 return NT_STATUS_OK;
2023 /* enumerate trusted domains
2024 * (we need to have the list of trustdoms in the cache when we go offline) -
2026 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
2027 TALLOC_CTX *mem_ctx,
2028 uint32 *num_domains,
2033 struct winbind_cache *cache = get_cache(domain);
2034 struct cache_entry *centry = NULL;
2041 centry = wcache_fetch(cache, domain, "TRUSTDOMS/%s", domain->name);
2047 *num_domains = centry_uint32(centry);
2050 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
2051 (*alt_names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
2052 (*dom_sids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
2054 if (! (*dom_sids) || ! (*names) || ! (*alt_names)) {
2055 smb_panic_fn("trusted_domains out of memory");
2059 (*alt_names) = NULL;
2063 for (i=0; i<(*num_domains); i++) {
2064 (*names)[i] = centry_string(centry, mem_ctx);
2065 (*alt_names)[i] = centry_string(centry, mem_ctx);
2066 centry_sid(centry, mem_ctx, &(*dom_sids)[i]);
2069 status = centry->status;
2071 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
2072 domain->name, *num_domains, nt_errstr(status) ));
2074 centry_free(centry);
2081 (*alt_names) = NULL;
2083 /* Return status value returned by seq number check */
2085 if (!NT_STATUS_IS_OK(domain->last_status))
2086 return domain->last_status;
2088 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2091 status = domain->backend->trusted_domains(domain, mem_ctx, num_domains,
2092 names, alt_names, dom_sids);
2094 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2095 * so that the generic centry handling still applies correctly -
2098 if (!NT_STATUS_IS_ERR(status)) {
2099 status = NT_STATUS_OK;
2103 #if 0 /* Disabled as we want the trust dom list to be managed by
2104 the main parent and always to make the query. --jerry */
2107 refresh_sequence_number(domain, False);
2109 centry = centry_start(domain, status);
2113 centry_put_uint32(centry, *num_domains);
2115 for (i=0; i<(*num_domains); i++) {
2116 centry_put_string(centry, (*names)[i]);
2117 centry_put_string(centry, (*alt_names)[i]);
2118 centry_put_sid(centry, &(*dom_sids)[i]);
2121 centry_end(centry, "TRUSTDOMS/%s", domain->name);
2123 centry_free(centry);
2131 /* get lockout policy */
2132 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
2133 TALLOC_CTX *mem_ctx,
2134 SAM_UNK_INFO_12 *policy){
2135 struct winbind_cache *cache = get_cache(domain);
2136 struct cache_entry *centry = NULL;
2142 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2147 policy->duration = centry_nttime(centry);
2148 policy->reset_count = centry_nttime(centry);
2149 policy->bad_attempt_lockout = centry_uint16(centry);
2151 status = centry->status;
2153 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2154 domain->name, nt_errstr(status) ));
2156 centry_free(centry);
2160 ZERO_STRUCTP(policy);
2162 /* Return status value returned by seq number check */
2164 if (!NT_STATUS_IS_OK(domain->last_status))
2165 return domain->last_status;
2167 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2170 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2173 refresh_sequence_number(domain, False);
2174 wcache_save_lockout_policy(domain, status, policy);
2179 /* get password policy */
2180 static NTSTATUS password_policy(struct winbindd_domain *domain,
2181 TALLOC_CTX *mem_ctx,
2182 SAM_UNK_INFO_1 *policy)
2184 struct winbind_cache *cache = get_cache(domain);
2185 struct cache_entry *centry = NULL;
2191 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2196 policy->min_length_password = centry_uint16(centry);
2197 policy->password_history = centry_uint16(centry);
2198 policy->password_properties = centry_uint32(centry);
2199 policy->expire = centry_nttime(centry);
2200 policy->min_passwordage = centry_nttime(centry);
2202 status = centry->status;
2204 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2205 domain->name, nt_errstr(status) ));
2207 centry_free(centry);
2211 ZERO_STRUCTP(policy);
2213 /* Return status value returned by seq number check */
2215 if (!NT_STATUS_IS_OK(domain->last_status))
2216 return domain->last_status;
2218 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2221 status = domain->backend->password_policy(domain, mem_ctx, policy);
2224 refresh_sequence_number(domain, False);
2225 wcache_save_password_policy(domain, status, policy);
2231 /* Invalidate cached user and group lists coherently */
2233 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2236 if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
2237 strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
2238 tdb_delete(the_tdb, kbuf);
2243 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2245 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
2246 NET_USER_INFO_3 *info3)
2248 struct winbind_cache *cache;
2250 /* dont clear cached U/SID and UG/SID entries when we want to logon
2253 if (lp_winbind_offline_logon()) {
2260 cache = get_cache(domain);
2261 netsamlogon_clear_cached_user(cache->tdb, info3);
2264 void wcache_invalidate_cache(void)
2266 struct winbindd_domain *domain;
2268 for (domain = domain_list(); domain; domain = domain->next) {
2269 struct winbind_cache *cache = get_cache(domain);
2271 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2272 "entries for %s\n", domain->name));
2274 tdb_traverse(cache->tdb, traverse_fn, NULL);
2278 bool init_wcache(void)
2280 if (wcache == NULL) {
2281 wcache = SMB_XMALLOC_P(struct winbind_cache);
2282 ZERO_STRUCTP(wcache);
2285 if (wcache->tdb != NULL)
2288 /* when working offline we must not clear the cache on restart */
2289 wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
2290 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2291 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
2292 O_RDWR|O_CREAT, 0600);
2294 if (wcache->tdb == NULL) {
2295 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2302 /************************************************************************
2303 This is called by the parent to initialize the cache file.
2304 We don't need sophisticated locking here as we know we're the
2306 ************************************************************************/
2308 bool initialize_winbindd_cache(void)
2310 bool cache_bad = True;
2313 if (!init_wcache()) {
2314 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
2318 /* Check version number. */
2319 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
2320 vers == WINBINDD_CACHE_VERSION) {
2325 DEBUG(0,("initialize_winbindd_cache: clearing cache "
2326 "and re-creating with version number %d\n",
2327 WINBINDD_CACHE_VERSION ));
2329 tdb_close(wcache->tdb);
2332 if (unlink(lock_path("winbindd_cache.tdb")) == -1) {
2333 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
2334 lock_path("winbindd_cache.tdb"),
2338 if (!init_wcache()) {
2339 DEBUG(0,("initialize_winbindd_cache: re-initialization "
2340 "init_wcache failed.\n"));
2344 /* Write the version. */
2345 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
2346 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
2347 tdb_errorstr(wcache->tdb) ));
2352 tdb_close(wcache->tdb);
2357 void cache_store_response(pid_t pid, struct winbindd_response *response)
2364 DEBUG(10, ("Storing response for pid %d, len %d\n",
2365 pid, response->length));
2367 fstr_sprintf(key_str, "DR/%d", pid);
2368 if (tdb_store(wcache->tdb, string_tdb_data(key_str),
2369 make_tdb_data((uint8 *)response, sizeof(*response)),
2373 if (response->length == sizeof(*response))
2376 /* There's extra data */
2378 DEBUG(10, ("Storing extra data: len=%d\n",
2379 (int)(response->length - sizeof(*response))));
2381 fstr_sprintf(key_str, "DE/%d", pid);
2382 if (tdb_store(wcache->tdb, string_tdb_data(key_str),
2383 make_tdb_data((uint8 *)response->extra_data.data,
2384 response->length - sizeof(*response)),
2388 /* We could not store the extra data, make sure the tdb does not
2389 * contain a main record with wrong dangling extra data */
2391 fstr_sprintf(key_str, "DR/%d", pid);
2392 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2397 bool cache_retrieve_response(pid_t pid, struct winbindd_response * response)
2405 DEBUG(10, ("Retrieving response for pid %d\n", pid));
2407 fstr_sprintf(key_str, "DR/%d", pid);
2408 data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
2410 if (data.dptr == NULL)
2413 if (data.dsize != sizeof(*response))
2416 memcpy(response, data.dptr, data.dsize);
2417 SAFE_FREE(data.dptr);
2419 if (response->length == sizeof(*response)) {
2420 response->extra_data.data = NULL;
2424 /* There's extra data */
2426 DEBUG(10, ("Retrieving extra data length=%d\n",
2427 (int)(response->length - sizeof(*response))));
2429 fstr_sprintf(key_str, "DE/%d", pid);
2430 data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
2432 if (data.dptr == NULL) {
2433 DEBUG(0, ("Did not find extra data\n"));
2437 if (data.dsize != (response->length - sizeof(*response))) {
2438 DEBUG(0, ("Invalid extra data length: %d\n", (int)data.dsize));
2439 SAFE_FREE(data.dptr);
2443 dump_data(11, (uint8 *)data.dptr, data.dsize);
2445 response->extra_data.data = data.dptr;
2449 void cache_cleanup_response(pid_t pid)
2456 fstr_sprintf(key_str, "DR/%d", pid);
2457 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2459 fstr_sprintf(key_str, "DE/%d", pid);
2460 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2466 bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
2467 char **domain_name, char **name,
2468 enum lsa_SidType *type)
2470 struct winbindd_domain *domain;
2471 struct winbind_cache *cache;
2472 struct cache_entry *centry = NULL;
2476 domain = find_lookup_domain_from_sid(sid);
2477 if (domain == NULL) {
2481 cache = get_cache(domain);
2483 if (cache->tdb == NULL) {
2487 centry = wcache_fetch(cache, domain, "SN/%s",
2488 sid_to_fstring(tmp, sid));
2489 if (centry == NULL) {
2493 if (NT_STATUS_IS_OK(centry->status)) {
2494 *type = (enum lsa_SidType)centry_uint32(centry);
2495 *domain_name = centry_string(centry, mem_ctx);
2496 *name = centry_string(centry, mem_ctx);
2499 status = centry->status;
2500 centry_free(centry);
2501 return NT_STATUS_IS_OK(status);
2504 bool lookup_cached_name(TALLOC_CTX *mem_ctx,
2505 const char *domain_name,
2508 enum lsa_SidType *type)
2510 struct winbindd_domain *domain;
2511 struct winbind_cache *cache;
2512 struct cache_entry *centry = NULL;
2515 bool original_online_state;
2517 domain = find_lookup_domain_from_name(domain_name);
2518 if (domain == NULL) {
2522 cache = get_cache(domain);
2524 if (cache->tdb == NULL) {
2528 fstrcpy(uname, name);
2531 /* If we are doing a cached logon, temporarily set the domain
2532 offline so the cache won't expire the entry */
2534 original_online_state = domain->online;
2535 domain->online = False;
2536 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
2537 domain->online = original_online_state;
2539 if (centry == NULL) {
2543 if (NT_STATUS_IS_OK(centry->status)) {
2544 *type = (enum lsa_SidType)centry_uint32(centry);
2545 centry_sid(centry, mem_ctx, sid);
2548 status = centry->status;
2549 centry_free(centry);
2551 return NT_STATUS_IS_OK(status);
2554 void cache_name2sid(struct winbindd_domain *domain,
2555 const char *domain_name, const char *name,
2556 enum lsa_SidType type, const DOM_SID *sid)
2558 refresh_sequence_number(domain, False);
2559 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
2564 * The original idea that this cache only contains centries has
2565 * been blurred - now other stuff gets put in here. Ensure we
2566 * ignore these things on cleanup.
2569 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
2570 TDB_DATA dbuf, void *state)
2572 struct cache_entry *centry;
2574 if (is_non_centry_key(kbuf)) {
2578 centry = wcache_fetch_raw((char *)kbuf.dptr);
2583 if (!NT_STATUS_IS_OK(centry->status)) {
2584 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
2585 tdb_delete(the_tdb, kbuf);
2588 centry_free(centry);
2592 /* flush the cache */
2593 void wcache_flush_cache(void)
2598 tdb_close(wcache->tdb);
2604 /* when working offline we must not clear the cache on restart */
2605 wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
2606 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2607 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
2608 O_RDWR|O_CREAT, 0600);
2611 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2615 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
2617 DEBUG(10,("wcache_flush_cache success\n"));
2620 /* Count cached creds */
2622 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2625 int *cred_count = (int*)state;
2627 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
2633 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
2635 struct winbind_cache *cache = get_cache(domain);
2640 return NT_STATUS_INTERNAL_DB_ERROR;
2643 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
2645 return NT_STATUS_OK;
2649 struct cred_list *prev, *next;
2654 static struct cred_list *wcache_cred_list;
2656 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2659 struct cred_list *cred;
2661 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
2663 cred = SMB_MALLOC_P(struct cred_list);
2665 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2671 /* save a copy of the key */
2673 fstrcpy(cred->name, (const char *)kbuf.dptr);
2674 DLIST_ADD(wcache_cred_list, cred);
2680 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const DOM_SID *sid)
2682 struct winbind_cache *cache = get_cache(domain);
2685 struct cred_list *cred, *oldest = NULL;
2688 return NT_STATUS_INTERNAL_DB_ERROR;
2691 /* we possibly already have an entry */
2692 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
2694 fstring key_str, tmp;
2696 DEBUG(11,("we already have an entry, deleting that\n"));
2698 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
2700 tdb_delete(cache->tdb, string_tdb_data(key_str));
2702 return NT_STATUS_OK;
2705 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
2707 return NT_STATUS_OK;
2708 } else if ((ret == -1) || (wcache_cred_list == NULL)) {
2709 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2712 ZERO_STRUCTP(oldest);
2714 for (cred = wcache_cred_list; cred; cred = cred->next) {
2719 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
2721 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
2723 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
2727 t = IVAL(data.dptr, 0);
2728 SAFE_FREE(data.dptr);
2731 oldest = SMB_MALLOC_P(struct cred_list);
2732 if (oldest == NULL) {
2733 status = NT_STATUS_NO_MEMORY;
2737 fstrcpy(oldest->name, cred->name);
2738 oldest->created = t;
2742 if (t < oldest->created) {
2743 fstrcpy(oldest->name, cred->name);
2744 oldest->created = t;
2748 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
2749 status = NT_STATUS_OK;
2751 status = NT_STATUS_UNSUCCESSFUL;
2754 SAFE_FREE(wcache_cred_list);
2760 /* Change the global online/offline state. */
2761 bool set_global_winbindd_state_offline(void)
2765 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
2767 /* Only go offline if someone has created
2768 the key "WINBINDD_OFFLINE" in the cache tdb. */
2770 if (wcache == NULL || wcache->tdb == NULL) {
2771 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
2775 if (!lp_winbind_offline_logon()) {
2776 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
2780 if (global_winbindd_offline_state) {
2781 /* Already offline. */
2785 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
2787 if (!data.dptr || data.dsize != 4) {
2788 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
2789 SAFE_FREE(data.dptr);
2792 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
2793 global_winbindd_offline_state = True;
2794 SAFE_FREE(data.dptr);
2799 void set_global_winbindd_state_online(void)
2801 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
2803 if (!lp_winbind_offline_logon()) {
2804 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
2808 if (!global_winbindd_offline_state) {
2809 /* Already online. */
2812 global_winbindd_offline_state = False;
2818 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
2819 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
2822 bool get_global_winbindd_state_offline(void)
2824 return global_winbindd_offline_state;
2827 /***********************************************************************
2828 Validate functions for all possible cache tdb keys.
2829 ***********************************************************************/
2831 static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
2832 struct tdb_validation_status *state)
2834 struct cache_entry *centry;
2836 centry = SMB_XMALLOC_P(struct cache_entry);
2837 centry->data = (unsigned char *)memdup(data.dptr, data.dsize);
2838 if (!centry->data) {
2842 centry->len = data.dsize;
2845 if (centry->len < 8) {
2846 /* huh? corrupt cache? */
2847 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr));
2848 centry_free(centry);
2849 state->bad_entry = True;
2850 state->success = False;
2854 centry->status = NT_STATUS(centry_uint32(centry));
2855 centry->sequence_number = centry_uint32(centry);
2859 static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2860 struct tdb_validation_status *state)
2862 if (dbuf.dsize != 8) {
2863 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
2864 keystr, (unsigned int)dbuf.dsize ));
2865 state->bad_entry = True;
2871 static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2872 struct tdb_validation_status *state)
2874 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2879 (void)centry_uint32(centry);
2880 if (NT_STATUS_IS_OK(centry->status)) {
2882 (void)centry_sid(centry, mem_ctx, &sid);
2885 centry_free(centry);
2887 if (!(state->success)) {
2890 DEBUG(10,("validate_ns: %s ok\n", keystr));
2894 static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2895 struct tdb_validation_status *state)
2897 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2902 if (NT_STATUS_IS_OK(centry->status)) {
2903 (void)centry_uint32(centry);
2904 (void)centry_string(centry, mem_ctx);
2905 (void)centry_string(centry, mem_ctx);
2908 centry_free(centry);
2910 if (!(state->success)) {
2913 DEBUG(10,("validate_sn: %s ok\n", keystr));
2917 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2918 struct tdb_validation_status *state)
2920 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2927 (void)centry_string(centry, mem_ctx);
2928 (void)centry_string(centry, mem_ctx);
2929 (void)centry_string(centry, mem_ctx);
2930 (void)centry_string(centry, mem_ctx);
2931 (void)centry_uint32(centry);
2932 (void)centry_sid(centry, mem_ctx, &sid);
2933 (void)centry_sid(centry, mem_ctx, &sid);
2935 centry_free(centry);
2937 if (!(state->success)) {
2940 DEBUG(10,("validate_u: %s ok\n", keystr));
2944 static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2945 struct tdb_validation_status *state)
2947 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2953 (void)centry_nttime(centry);
2954 (void)centry_nttime(centry);
2955 (void)centry_uint16(centry);
2957 centry_free(centry);
2959 if (!(state->success)) {
2962 DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
2966 static int validate_pwd_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_uint16(centry);
2976 (void)centry_uint16(centry);
2977 (void)centry_uint32(centry);
2978 (void)centry_nttime(centry);
2979 (void)centry_nttime(centry);
2981 centry_free(centry);
2983 if (!(state->success)) {
2986 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
2990 static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2991 struct tdb_validation_status *state)
2993 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2999 (void)centry_time(centry);
3000 (void)centry_hash16(centry, mem_ctx);
3002 /* We only have 17 bytes more data in the salted cred case. */
3003 if (centry->len - centry->ofs == 17) {
3004 (void)centry_hash16(centry, mem_ctx);
3007 centry_free(centry);
3009 if (!(state->success)) {
3012 DEBUG(10,("validate_cred: %s ok\n", keystr));
3016 static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3017 struct tdb_validation_status *state)
3019 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3020 int32 num_entries, i;
3026 num_entries = (int32)centry_uint32(centry);
3028 for (i=0; i< num_entries; i++) {
3030 (void)centry_string(centry, mem_ctx);
3031 (void)centry_string(centry, mem_ctx);
3032 (void)centry_string(centry, mem_ctx);
3033 (void)centry_string(centry, mem_ctx);
3034 (void)centry_sid(centry, mem_ctx, &sid);
3035 (void)centry_sid(centry, mem_ctx, &sid);
3038 centry_free(centry);
3040 if (!(state->success)) {
3043 DEBUG(10,("validate_ul: %s ok\n", keystr));
3047 static int validate_gl(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 = centry_uint32(centry);
3059 for (i=0; i< num_entries; i++) {
3060 (void)centry_string(centry, mem_ctx);
3061 (void)centry_string(centry, mem_ctx);
3062 (void)centry_uint32(centry);
3065 centry_free(centry);
3067 if (!(state->success)) {
3070 DEBUG(10,("validate_gl: %s ok\n", keystr));
3074 static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3075 struct tdb_validation_status *state)
3077 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3078 int32 num_groups, i;
3084 num_groups = centry_uint32(centry);
3086 for (i=0; i< num_groups; i++) {
3088 centry_sid(centry, mem_ctx, &sid);
3091 centry_free(centry);
3093 if (!(state->success)) {
3096 DEBUG(10,("validate_ug: %s ok\n", keystr));
3100 static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3101 struct tdb_validation_status *state)
3103 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3104 int32 num_aliases, i;
3110 num_aliases = centry_uint32(centry);
3112 for (i=0; i < num_aliases; i++) {
3113 (void)centry_uint32(centry);
3116 centry_free(centry);
3118 if (!(state->success)) {
3121 DEBUG(10,("validate_ua: %s ok\n", keystr));
3125 static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3126 struct tdb_validation_status *state)
3128 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3135 num_names = centry_uint32(centry);
3137 for (i=0; i< num_names; i++) {
3139 centry_sid(centry, mem_ctx, &sid);
3140 (void)centry_string(centry, mem_ctx);
3141 (void)centry_uint32(centry);
3144 centry_free(centry);
3146 if (!(state->success)) {
3149 DEBUG(10,("validate_gm: %s ok\n", keystr));
3153 static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3154 struct tdb_validation_status *state)
3156 /* Can't say anything about this other than must be nonzero. */
3157 if (dbuf.dsize == 0) {
3158 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3160 state->bad_entry = True;
3161 state->success = False;
3165 DEBUG(10,("validate_dr: %s ok\n", keystr));
3169 static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3170 struct tdb_validation_status *state)
3172 /* Can't say anything about this other than must be nonzero. */
3173 if (dbuf.dsize == 0) {
3174 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3176 state->bad_entry = True;
3177 state->success = False;
3181 DEBUG(10,("validate_de: %s ok\n", keystr));
3185 static int validate_trustdoms(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3186 struct tdb_validation_status *state)
3188 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3189 int32 num_domains, i;
3195 num_domains = centry_uint32(centry);
3197 for (i=0; i< num_domains; i++) {
3199 (void)centry_string(centry, mem_ctx);
3200 (void)centry_string(centry, mem_ctx);
3201 (void)centry_sid(centry, mem_ctx, &sid);
3204 centry_free(centry);
3206 if (!(state->success)) {
3209 DEBUG(10,("validate_trustdoms: %s ok\n", keystr));
3213 static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
3215 struct tdb_validation_status *state)
3217 if (dbuf.dsize == 0) {
3218 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3219 "key %s (len ==0) ?\n", keystr));
3220 state->bad_entry = True;
3221 state->success = False;
3225 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
3226 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3230 static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3231 struct tdb_validation_status *state)
3233 if (dbuf.dsize != 4) {
3234 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3235 keystr, (unsigned int)dbuf.dsize ));
3236 state->bad_entry = True;
3237 state->success = False;
3240 DEBUG(10,("validate_offline: %s ok\n", keystr));
3244 static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3245 struct tdb_validation_status *state)
3247 if (dbuf.dsize != 4) {
3248 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3249 "key %s (len %u != 4) ?\n",
3250 keystr, (unsigned int)dbuf.dsize));
3251 state->bad_entry = True;
3252 state->success = False;
3256 DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
3260 /***********************************************************************
3261 A list of all possible cache tdb keys with associated validation
3263 ***********************************************************************/
3265 struct key_val_struct {
3266 const char *keyname;
3267 int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
3269 {"SEQNUM/", validate_seqnum},
3270 {"NS/", validate_ns},
3271 {"SN/", validate_sn},
3273 {"LOC_POL/", validate_loc_pol},
3274 {"PWD_POL/", validate_pwd_pol},
3275 {"CRED/", validate_cred},
3276 {"UL/", validate_ul},
3277 {"GL/", validate_gl},
3278 {"UG/", validate_ug},
3279 {"UA", validate_ua},
3280 {"GM/", validate_gm},
3281 {"DR/", validate_dr},
3282 {"DE/", validate_de},
3283 {"TRUSTDOMS/", validate_trustdoms},
3284 {"TRUSTDOMCACHE/", validate_trustdomcache},
3285 {"WINBINDD_OFFLINE", validate_offline},
3286 {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
3290 /***********************************************************************
3291 Function to look at every entry in the tdb and validate it as far as
3293 ***********************************************************************/
3295 static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
3298 struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
3300 /* Paranoia check. */
3301 if (kbuf.dsize > 1024) {
3302 DEBUG(0,("cache_traverse_validate_fn: key length too large (%u) > 1024\n\n",
3303 (unsigned int)kbuf.dsize ));
3307 for (i = 0; key_val[i].keyname; i++) {
3308 size_t namelen = strlen(key_val[i].keyname);
3309 if (kbuf.dsize >= namelen && (
3310 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
3311 TALLOC_CTX *mem_ctx;
3315 keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
3319 memcpy(keystr, kbuf.dptr, kbuf.dsize);
3320 keystr[kbuf.dsize] = '\0';
3322 mem_ctx = talloc_init("validate_ctx");
3328 ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
3332 talloc_destroy(mem_ctx);
3337 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
3338 dump_data(0, (uint8 *)kbuf.dptr, kbuf.dsize);
3339 DEBUG(0,("data :\n"));
3340 dump_data(0, (uint8 *)dbuf.dptr, dbuf.dsize);
3341 v_state->unknown_key = True;
3342 v_state->success = False;
3343 return 1; /* terminate. */
3346 static void validate_panic(const char *const why)
3348 DEBUG(0,("validating cache: would panic %s\n", why ));
3349 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
3353 /***********************************************************************
3354 Try and validate every entry in the winbindd cache. If we fail here,
3355 delete the cache tdb and return non-zero.
3356 ***********************************************************************/
3358 int winbindd_validate_cache(void)
3361 const char *tdb_path = lock_path("winbindd_cache.tdb");
3362 TDB_CONTEXT *tdb = NULL;
3364 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3365 smb_panic_fn = validate_panic;
3368 tdb = tdb_open_log(tdb_path,
3369 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3370 ( lp_winbind_offline_logon()
3372 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
3376 DEBUG(0, ("winbindd_validate_cache: "
3377 "error opening/initializing tdb\n"));
3382 ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
3385 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
3386 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
3391 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
3392 smb_panic_fn = smb_panic;
3396 /***********************************************************************
3397 Try and validate every entry in the winbindd cache.
3398 ***********************************************************************/
3400 int winbindd_validate_cache_nobackup(void)
3403 const char *tdb_path = lock_path("winbindd_cache.tdb");
3405 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3406 smb_panic_fn = validate_panic;
3409 if (wcache == NULL || wcache->tdb == NULL) {
3410 ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
3412 ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
3416 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
3420 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
3422 smb_panic_fn = smb_panic;
3426 /*********************************************************************
3427 ********************************************************************/
3429 static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
3430 struct winbindd_tdc_domain **domains,
3431 size_t *num_domains )
3433 struct winbindd_tdc_domain *list = NULL;
3436 bool set_only = False;
3438 /* don't allow duplicates */
3443 for ( i=0; i< (*num_domains); i++ ) {
3444 if ( strequal( new_dom->name, list[i].domain_name ) ) {
3445 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
3456 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, 1 );
3459 list = TALLOC_REALLOC_ARRAY( *domains, *domains,
3460 struct winbindd_tdc_domain,
3465 ZERO_STRUCT( list[idx] );
3471 list[idx].domain_name = talloc_strdup( list, new_dom->name );
3472 list[idx].dns_name = talloc_strdup( list, new_dom->alt_name );
3474 if ( !is_null_sid( &new_dom->sid ) )
3475 sid_copy( &list[idx].sid, &new_dom->sid );
3477 if ( new_dom->domain_flags != 0x0 )
3478 list[idx].trust_flags = new_dom->domain_flags;
3480 if ( new_dom->domain_type != 0x0 )
3481 list[idx].trust_type = new_dom->domain_type;
3483 if ( new_dom->domain_trust_attribs != 0x0 )
3484 list[idx].trust_attribs = new_dom->domain_trust_attribs;
3488 *num_domains = idx + 1;
3494 /*********************************************************************
3495 ********************************************************************/
3497 static TDB_DATA make_tdc_key( const char *domain_name )
3499 char *keystr = NULL;
3500 TDB_DATA key = { NULL, 0 };
3502 if ( !domain_name ) {
3503 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
3508 asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name );
3509 key = string_term_tdb_data(keystr);
3514 /*********************************************************************
3515 ********************************************************************/
3517 static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
3519 unsigned char **buf )
3521 unsigned char *buffer = NULL;
3526 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
3534 /* Store the number of array items first */
3535 len += tdb_pack( buffer+len, buflen-len, "d",
3538 /* now pack each domain trust record */
3539 for ( i=0; i<num_domains; i++ ) {
3544 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
3545 domains[i].domain_name,
3546 domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
3549 len += tdb_pack( buffer+len, buflen-len, "fffddd",
3550 domains[i].domain_name,
3551 domains[i].dns_name,
3552 sid_to_fstring(tmp, &domains[i].sid),
3553 domains[i].trust_flags,
3554 domains[i].trust_attribs,
3555 domains[i].trust_type );
3558 if ( buflen < len ) {
3560 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
3561 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
3575 /*********************************************************************
3576 ********************************************************************/
3578 static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
3579 struct winbindd_tdc_domain **domains )
3581 fstring domain_name, dns_name, sid_string;
3582 uint32 type, attribs, flags;
3586 struct winbindd_tdc_domain *list = NULL;
3588 /* get the number of domains */
3589 len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
3591 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3595 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, num_domains );
3597 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
3601 for ( i=0; i<num_domains; i++ ) {
3602 len += tdb_unpack( buf+len, buflen-len, "fffddd",
3611 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3612 TALLOC_FREE( list );
3616 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
3617 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
3618 domain_name, dns_name, sid_string,
3619 flags, attribs, type));
3621 list[i].domain_name = talloc_strdup( list, domain_name );
3622 list[i].dns_name = talloc_strdup( list, dns_name );
3623 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
3624 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
3627 list[i].trust_flags = flags;
3628 list[i].trust_attribs = attribs;
3629 list[i].trust_type = type;
3637 /*********************************************************************
3638 ********************************************************************/
3640 static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
3642 TDB_DATA key = make_tdc_key( lp_workgroup() );
3643 TDB_DATA data = { NULL, 0 };
3649 /* See if we were asked to delete the cache entry */
3652 ret = tdb_delete( wcache->tdb, key );
3656 data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
3663 ret = tdb_store( wcache->tdb, key, data, 0 );
3666 SAFE_FREE( data.dptr );
3667 SAFE_FREE( key.dptr );
3669 return ( ret != -1 );
3672 /*********************************************************************
3673 ********************************************************************/
3675 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
3677 TDB_DATA key = make_tdc_key( lp_workgroup() );
3678 TDB_DATA data = { NULL, 0 };
3686 data = tdb_fetch( wcache->tdb, key );
3688 SAFE_FREE( key.dptr );
3693 *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
3695 SAFE_FREE( data.dptr );
3703 /*********************************************************************
3704 ********************************************************************/
3706 bool wcache_tdc_add_domain( struct winbindd_domain *domain )
3708 struct winbindd_tdc_domain *dom_list = NULL;
3709 size_t num_domains = 0;
3712 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
3713 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
3714 domain->name, domain->alt_name,
3715 sid_string_dbg(&domain->sid),
3716 domain->domain_flags,
3717 domain->domain_trust_attribs,
3718 domain->domain_type));
3720 if ( !init_wcache() ) {
3724 /* fetch the list */
3726 wcache_tdc_fetch_list( &dom_list, &num_domains );
3728 /* add the new domain */
3730 if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
3734 /* pack the domain */
3736 if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
3744 TALLOC_FREE( dom_list );
3749 /*********************************************************************
3750 ********************************************************************/
3752 struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
3754 struct winbindd_tdc_domain *dom_list = NULL;
3755 size_t num_domains = 0;
3757 struct winbindd_tdc_domain *d = NULL;
3759 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
3761 if ( !init_wcache() ) {
3765 /* fetch the list */
3767 wcache_tdc_fetch_list( &dom_list, &num_domains );
3769 for ( i=0; i<num_domains; i++ ) {
3770 if ( strequal(name, dom_list[i].domain_name) ||
3771 strequal(name, dom_list[i].dns_name) )
3773 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
3776 d = TALLOC_P( ctx, struct winbindd_tdc_domain );
3780 d->domain_name = talloc_strdup( d, dom_list[i].domain_name );
3781 d->dns_name = talloc_strdup( d, dom_list[i].dns_name );
3782 sid_copy( &d->sid, &dom_list[i].sid );
3783 d->trust_flags = dom_list[i].trust_flags;
3784 d->trust_type = dom_list[i].trust_type;
3785 d->trust_attribs = dom_list[i].trust_attribs;
3791 TALLOC_FREE( dom_list );
3797 /*********************************************************************
3798 ********************************************************************/
3800 void wcache_tdc_clear( void )
3802 if ( !init_wcache() )
3805 wcache_tdc_store_list( NULL, 0 );
3811 /*********************************************************************
3812 ********************************************************************/
3814 static void wcache_save_user_pwinfo(struct winbindd_domain *domain,
3816 const DOM_SID *user_sid,
3817 const char *homedir,
3822 struct cache_entry *centry;
3825 if ( (centry = centry_start(domain, status)) == NULL )
3828 centry_put_string( centry, homedir );
3829 centry_put_string( centry, shell );
3830 centry_put_string( centry, gecos );
3831 centry_put_uint32( centry, gid );
3833 centry_end(centry, "NSS/PWINFO/%s", sid_to_fstring(tmp, user_sid) );
3835 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid) ));
3837 centry_free(centry);
3840 NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
3841 const DOM_SID *user_sid,
3843 ADS_STRUCT *ads, LDAPMessage *msg,
3844 char **homedir, char **shell, char **gecos,
3847 struct winbind_cache *cache = get_cache(domain);
3848 struct cache_entry *centry = NULL;
3855 centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s",
3856 sid_to_fstring(tmp, user_sid));
3861 *homedir = centry_string( centry, ctx );
3862 *shell = centry_string( centry, ctx );
3863 *gecos = centry_string( centry, ctx );
3864 *p_gid = centry_uint32( centry );
3866 centry_free(centry);
3868 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
3869 sid_string_dbg(user_sid)));
3871 return NT_STATUS_OK;
3875 nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg,
3876 homedir, shell, gecos, p_gid );
3878 if ( NT_STATUS_IS_OK(nt_status) ) {
3879 wcache_save_user_pwinfo( domain, nt_status, user_sid,
3880 *homedir, *shell, *gecos, *p_gid );
3883 if ( NT_STATUS_EQUAL( nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
3884 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
3886 set_domain_offline( domain );
3893 /* the cache backend methods are exposed via this structure */
3894 struct winbindd_methods cache_methods = {