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_string(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_string(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_string(sid_string, &info->user_sid));
906 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
910 static void wcache_save_lockout_policy(struct winbindd_domain *domain, NTSTATUS status, SAM_UNK_INFO_12 *lockout_policy)
912 struct cache_entry *centry;
914 centry = centry_start(domain, status);
918 centry_put_nttime(centry, lockout_policy->duration);
919 centry_put_nttime(centry, lockout_policy->reset_count);
920 centry_put_uint16(centry, lockout_policy->bad_attempt_lockout);
922 centry_end(centry, "LOC_POL/%s", domain->name);
924 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
929 static void wcache_save_password_policy(struct winbindd_domain *domain, NTSTATUS status, SAM_UNK_INFO_1 *policy)
931 struct cache_entry *centry;
933 centry = centry_start(domain, status);
937 centry_put_uint16(centry, policy->min_length_password);
938 centry_put_uint16(centry, policy->password_history);
939 centry_put_uint32(centry, policy->password_properties);
940 centry_put_nttime(centry, policy->expire);
941 centry_put_nttime(centry, policy->min_passwordage);
943 centry_end(centry, "PWD_POL/%s", domain->name);
945 DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
950 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const DOM_SID *sid)
952 struct winbind_cache *cache = get_cache(domain);
958 return NT_STATUS_INTERNAL_DB_ERROR;
961 if (is_null_sid(sid)) {
962 return NT_STATUS_INVALID_SID;
965 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
966 return NT_STATUS_INVALID_SID;
969 fstr_sprintf(key_str, "CRED/%s", sid_string_static(sid));
971 data = tdb_fetch(cache->tdb, string_tdb_data(key_str));
973 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
976 SAFE_FREE(data.dptr);
980 /* Lookup creds for a SID - copes with old (unsalted) creds as well
981 as new salted ones. */
983 NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
986 const uint8 **cached_nt_pass,
987 const uint8 **cached_salt)
989 struct winbind_cache *cache = get_cache(domain);
990 struct cache_entry *centry = NULL;
996 return NT_STATUS_INTERNAL_DB_ERROR;
999 if (is_null_sid(sid)) {
1000 return NT_STATUS_INVALID_SID;
1003 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1004 return NT_STATUS_INVALID_SID;
1007 /* Try and get a salted cred first. If we can't
1008 fall back to an unsalted cred. */
1010 centry = wcache_fetch(cache, domain, "CRED/%s", sid_string_static(sid));
1012 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1013 sid_string_dbg(sid)));
1014 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1017 t = centry_time(centry);
1019 /* In the salted case this isn't actually the nt_hash itself,
1020 but the MD5 of the salt + nt_hash. Let the caller
1021 sort this out. It can tell as we only return the cached_salt
1022 if we are returning a salted cred. */
1024 *cached_nt_pass = (const uint8 *)centry_hash16(centry, mem_ctx);
1025 if (*cached_nt_pass == NULL) {
1028 sid_to_string(sidstr, sid);
1030 /* Bad (old) cred cache. Delete and pretend we
1032 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1034 wcache_delete("CRED/%s", sidstr);
1035 centry_free(centry);
1036 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1039 /* We only have 17 bytes more data in the salted cred case. */
1040 if (centry->len - centry->ofs == 17) {
1041 *cached_salt = (const uint8 *)centry_hash16(centry, mem_ctx);
1043 *cached_salt = NULL;
1046 dump_data_pw("cached_nt_pass", *cached_nt_pass, NT_HASH_LEN);
1048 dump_data_pw("cached_salt", *cached_salt, NT_HASH_LEN);
1051 status = centry->status;
1053 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1054 sid_string_dbg(sid), nt_errstr(status) ));
1056 centry_free(centry);
1060 /* Store creds for a SID - only writes out new salted ones. */
1062 NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
1063 TALLOC_CTX *mem_ctx,
1065 const uint8 nt_pass[NT_HASH_LEN])
1067 struct cache_entry *centry;
1070 uint8 cred_salt[NT_HASH_LEN];
1071 uint8 salted_hash[NT_HASH_LEN];
1073 if (is_null_sid(sid)) {
1074 return NT_STATUS_INVALID_SID;
1077 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1078 return NT_STATUS_INVALID_SID;
1081 centry = centry_start(domain, NT_STATUS_OK);
1083 return NT_STATUS_INTERNAL_DB_ERROR;
1086 dump_data_pw("nt_pass", nt_pass, NT_HASH_LEN);
1088 centry_put_time(centry, time(NULL));
1090 /* Create a salt and then salt the hash. */
1091 generate_random_buffer(cred_salt, NT_HASH_LEN);
1092 E_md5hash(cred_salt, nt_pass, salted_hash);
1094 centry_put_hash16(centry, salted_hash);
1095 centry_put_hash16(centry, cred_salt);
1096 centry_end(centry, "CRED/%s", sid_to_string(sid_string, sid));
1098 DEBUG(10,("wcache_save_creds: %s\n", sid_string));
1100 centry_free(centry);
1102 return NT_STATUS_OK;
1106 /* Query display info. This is the basic user list fn */
1107 static NTSTATUS query_user_list(struct winbindd_domain *domain,
1108 TALLOC_CTX *mem_ctx,
1109 uint32 *num_entries,
1110 WINBIND_USERINFO **info)
1112 struct winbind_cache *cache = get_cache(domain);
1113 struct cache_entry *centry = NULL;
1115 unsigned int i, retry;
1120 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1124 *num_entries = centry_uint32(centry);
1126 if (*num_entries == 0)
1129 (*info) = TALLOC_ARRAY(mem_ctx, WINBIND_USERINFO, *num_entries);
1131 smb_panic_fn("query_user_list out of memory");
1133 for (i=0; i<(*num_entries); i++) {
1134 (*info)[i].acct_name = centry_string(centry, mem_ctx);
1135 (*info)[i].full_name = centry_string(centry, mem_ctx);
1136 (*info)[i].homedir = centry_string(centry, mem_ctx);
1137 (*info)[i].shell = centry_string(centry, mem_ctx);
1138 centry_sid(centry, mem_ctx, &(*info)[i].user_sid);
1139 centry_sid(centry, mem_ctx, &(*info)[i].group_sid);
1143 status = centry->status;
1145 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1146 domain->name, nt_errstr(status) ));
1148 centry_free(centry);
1155 /* Return status value returned by seq number check */
1157 if (!NT_STATUS_IS_OK(domain->last_status))
1158 return domain->last_status;
1160 /* Put the query_user_list() in a retry loop. There appears to be
1161 * some bug either with Windows 2000 or Samba's handling of large
1162 * rpc replies. This manifests itself as sudden disconnection
1163 * at a random point in the enumeration of a large (60k) user list.
1164 * The retry loop simply tries the operation again. )-: It's not
1165 * pretty but an acceptable workaround until we work out what the
1166 * real problem is. */
1171 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1174 status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
1175 if (!NT_STATUS_IS_OK(status)) {
1176 DEBUG(3, ("query_user_list: returned 0x%08x, "
1177 "retrying\n", NT_STATUS_V(status)));
1179 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1180 DEBUG(3, ("query_user_list: flushing "
1181 "connection cache\n"));
1182 invalidate_cm_connection(&domain->conn);
1185 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
1189 refresh_sequence_number(domain, False);
1190 centry = centry_start(domain, status);
1193 centry_put_uint32(centry, *num_entries);
1194 for (i=0; i<(*num_entries); i++) {
1195 centry_put_string(centry, (*info)[i].acct_name);
1196 centry_put_string(centry, (*info)[i].full_name);
1197 centry_put_string(centry, (*info)[i].homedir);
1198 centry_put_string(centry, (*info)[i].shell);
1199 centry_put_sid(centry, &(*info)[i].user_sid);
1200 centry_put_sid(centry, &(*info)[i].group_sid);
1201 if (domain->backend && domain->backend->consistent) {
1202 /* when the backend is consistent we can pre-prime some mappings */
1203 wcache_save_name_to_sid(domain, NT_STATUS_OK,
1205 (*info)[i].acct_name,
1206 &(*info)[i].user_sid,
1208 wcache_save_sid_to_name(domain, NT_STATUS_OK,
1209 &(*info)[i].user_sid,
1211 (*info)[i].acct_name,
1213 wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
1216 centry_end(centry, "UL/%s", domain->name);
1217 centry_free(centry);
1223 /* list all domain groups */
1224 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
1225 TALLOC_CTX *mem_ctx,
1226 uint32 *num_entries,
1227 struct acct_info **info)
1229 struct winbind_cache *cache = get_cache(domain);
1230 struct cache_entry *centry = NULL;
1237 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1241 *num_entries = centry_uint32(centry);
1243 if (*num_entries == 0)
1246 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1248 smb_panic_fn("enum_dom_groups out of memory");
1250 for (i=0; i<(*num_entries); i++) {
1251 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1252 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1253 (*info)[i].rid = centry_uint32(centry);
1257 status = centry->status;
1259 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1260 domain->name, nt_errstr(status) ));
1262 centry_free(centry);
1269 /* Return status value returned by seq number check */
1271 if (!NT_STATUS_IS_OK(domain->last_status))
1272 return domain->last_status;
1274 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1277 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1280 refresh_sequence_number(domain, False);
1281 centry = centry_start(domain, status);
1284 centry_put_uint32(centry, *num_entries);
1285 for (i=0; i<(*num_entries); i++) {
1286 centry_put_string(centry, (*info)[i].acct_name);
1287 centry_put_string(centry, (*info)[i].acct_desc);
1288 centry_put_uint32(centry, (*info)[i].rid);
1290 centry_end(centry, "GL/%s/domain", domain->name);
1291 centry_free(centry);
1297 /* list all domain groups */
1298 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
1299 TALLOC_CTX *mem_ctx,
1300 uint32 *num_entries,
1301 struct acct_info **info)
1303 struct winbind_cache *cache = get_cache(domain);
1304 struct cache_entry *centry = NULL;
1311 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1315 *num_entries = centry_uint32(centry);
1317 if (*num_entries == 0)
1320 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1322 smb_panic_fn("enum_dom_groups out of memory");
1324 for (i=0; i<(*num_entries); i++) {
1325 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1326 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1327 (*info)[i].rid = centry_uint32(centry);
1332 /* If we are returning cached data and the domain controller
1333 is down then we don't know whether the data is up to date
1334 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1337 if (wcache_server_down(domain)) {
1338 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1339 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1341 status = centry->status;
1343 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1344 domain->name, nt_errstr(status) ));
1346 centry_free(centry);
1353 /* Return status value returned by seq number check */
1355 if (!NT_STATUS_IS_OK(domain->last_status))
1356 return domain->last_status;
1358 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1361 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1364 refresh_sequence_number(domain, False);
1365 centry = centry_start(domain, status);
1368 centry_put_uint32(centry, *num_entries);
1369 for (i=0; i<(*num_entries); i++) {
1370 centry_put_string(centry, (*info)[i].acct_name);
1371 centry_put_string(centry, (*info)[i].acct_desc);
1372 centry_put_uint32(centry, (*info)[i].rid);
1374 centry_end(centry, "GL/%s/local", domain->name);
1375 centry_free(centry);
1381 /* convert a single name to a sid in a domain */
1382 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
1383 TALLOC_CTX *mem_ctx,
1384 enum winbindd_cmd orig_cmd,
1385 const char *domain_name,
1388 enum lsa_SidType *type)
1390 struct winbind_cache *cache = get_cache(domain);
1391 struct cache_entry *centry = NULL;
1398 fstrcpy(uname, name);
1400 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1404 status = centry->status;
1405 if (NT_STATUS_IS_OK(status)) {
1406 *type = (enum lsa_SidType)centry_uint32(centry);
1407 centry_sid(centry, mem_ctx, sid);
1410 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: %s\n",
1411 domain->name, nt_errstr(status) ));
1413 centry_free(centry);
1419 /* If the seq number check indicated that there is a problem
1420 * with this DC, then return that status... except for
1421 * access_denied. This is special because the dc may be in
1422 * "restrict anonymous = 1" mode, in which case it will deny
1423 * most unauthenticated operations, but *will* allow the LSA
1424 * name-to-sid that we try as a fallback. */
1426 if (!(NT_STATUS_IS_OK(domain->last_status)
1427 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1428 return domain->last_status;
1430 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1433 status = domain->backend->name_to_sid(domain, mem_ctx, orig_cmd,
1434 domain_name, name, sid, type);
1437 refresh_sequence_number(domain, False);
1439 if (domain->online &&
1440 (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
1441 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1443 /* Only save the reverse mapping if this was not a UPN */
1444 if (!strchr(name, '@')) {
1445 strupper_m(CONST_DISCARD(char *,domain_name));
1446 strlower_m(CONST_DISCARD(char *,name));
1447 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1454 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1456 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
1457 TALLOC_CTX *mem_ctx,
1461 enum lsa_SidType *type)
1463 struct winbind_cache *cache = get_cache(domain);
1464 struct cache_entry *centry = NULL;
1471 centry = wcache_fetch(cache, domain, "SN/%s", sid_to_string(sid_string, sid));
1475 status = centry->status;
1476 if (NT_STATUS_IS_OK(status)) {
1477 *type = (enum lsa_SidType)centry_uint32(centry);
1478 *domain_name = centry_string(centry, mem_ctx);
1479 *name = centry_string(centry, mem_ctx);
1482 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: %s\n",
1483 domain->name, nt_errstr(status) ));
1485 centry_free(centry);
1490 *domain_name = NULL;
1492 /* If the seq number check indicated that there is a problem
1493 * with this DC, then return that status... except for
1494 * access_denied. This is special because the dc may be in
1495 * "restrict anonymous = 1" mode, in which case it will deny
1496 * most unauthenticated operations, but *will* allow the LSA
1497 * sid-to-name that we try as a fallback. */
1499 if (!(NT_STATUS_IS_OK(domain->last_status)
1500 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1501 return domain->last_status;
1503 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1506 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1509 refresh_sequence_number(domain, False);
1510 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1512 /* We can't save the name to sid mapping here, as with sid history a
1513 * later name2sid would give the wrong sid. */
1518 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
1519 TALLOC_CTX *mem_ctx,
1520 const DOM_SID *domain_sid,
1525 enum lsa_SidType **types)
1527 struct winbind_cache *cache = get_cache(domain);
1529 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1533 *domain_name = NULL;
1541 if (num_rids == 0) {
1542 return NT_STATUS_OK;
1545 *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
1546 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
1548 if ((*names == NULL) || (*types == NULL)) {
1549 result = NT_STATUS_NO_MEMORY;
1553 have_mapped = have_unmapped = False;
1555 for (i=0; i<num_rids; i++) {
1557 struct cache_entry *centry;
1559 if (!sid_compose(&sid, domain_sid, rids[i])) {
1560 result = NT_STATUS_INTERNAL_ERROR;
1564 centry = wcache_fetch(cache, domain, "SN/%s",
1565 sid_string_static(&sid));
1570 (*types)[i] = SID_NAME_UNKNOWN;
1571 (*names)[i] = talloc_strdup(*names, "");
1573 if (NT_STATUS_IS_OK(centry->status)) {
1576 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
1578 dom = centry_string(centry, mem_ctx);
1579 if (*domain_name == NULL) {
1585 (*names)[i] = centry_string(centry, *names);
1587 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
1588 have_unmapped = True;
1591 /* something's definitely wrong */
1592 result = centry->status;
1596 centry_free(centry);
1600 return NT_STATUS_NONE_MAPPED;
1602 if (!have_unmapped) {
1603 return NT_STATUS_OK;
1605 return STATUS_SOME_UNMAPPED;
1609 TALLOC_FREE(*names);
1610 TALLOC_FREE(*types);
1612 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
1613 rids, num_rids, domain_name,
1617 None of the queried rids has been found so save all negative entries
1619 if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
1620 for (i = 0; i < num_rids; i++) {
1622 const char *name = "";
1623 const enum lsa_SidType type = SID_NAME_UNKNOWN;
1624 NTSTATUS status = NT_STATUS_NONE_MAPPED;
1626 if (!sid_compose(&sid, domain_sid, rids[i])) {
1627 return NT_STATUS_INTERNAL_ERROR;
1630 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
1638 Some or all of the queried rids have been found.
1640 if (!NT_STATUS_IS_OK(result) &&
1641 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
1645 refresh_sequence_number(domain, False);
1647 for (i=0; i<num_rids; i++) {
1651 if (!sid_compose(&sid, domain_sid, rids[i])) {
1652 result = NT_STATUS_INTERNAL_ERROR;
1656 status = (*types)[i] == SID_NAME_UNKNOWN ?
1657 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
1659 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
1660 (*names)[i], (*types)[i]);
1667 TALLOC_FREE(*names);
1668 TALLOC_FREE(*types);
1672 /* Lookup user information from a rid */
1673 static NTSTATUS query_user(struct winbindd_domain *domain,
1674 TALLOC_CTX *mem_ctx,
1675 const DOM_SID *user_sid,
1676 WINBIND_USERINFO *info)
1678 struct winbind_cache *cache = get_cache(domain);
1679 struct cache_entry *centry = NULL;
1685 centry = wcache_fetch(cache, domain, "U/%s", sid_string_static(user_sid));
1687 /* If we have an access denied cache entry and a cached info3 in the
1688 samlogon cache then do a query. This will force the rpc back end
1689 to return the info3 data. */
1691 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1692 netsamlogon_cache_have(user_sid)) {
1693 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1694 domain->last_status = NT_STATUS_OK;
1695 centry_free(centry);
1702 /* if status is not ok then this is a negative hit
1703 and the rest of the data doesn't matter */
1704 status = centry->status;
1705 if (NT_STATUS_IS_OK(status)) {
1706 info->acct_name = centry_string(centry, mem_ctx);
1707 info->full_name = centry_string(centry, mem_ctx);
1708 info->homedir = centry_string(centry, mem_ctx);
1709 info->shell = centry_string(centry, mem_ctx);
1710 info->primary_gid = centry_uint32(centry);
1711 centry_sid(centry, mem_ctx, &info->user_sid);
1712 centry_sid(centry, mem_ctx, &info->group_sid);
1715 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: %s\n",
1716 domain->name, nt_errstr(status) ));
1718 centry_free(centry);
1724 /* Return status value returned by seq number check */
1726 if (!NT_STATUS_IS_OK(domain->last_status))
1727 return domain->last_status;
1729 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
1732 status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
1735 refresh_sequence_number(domain, False);
1736 wcache_save_user(domain, status, info);
1742 /* Lookup groups a user is a member of. */
1743 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
1744 TALLOC_CTX *mem_ctx,
1745 const DOM_SID *user_sid,
1746 uint32 *num_groups, DOM_SID **user_gids)
1748 struct winbind_cache *cache = get_cache(domain);
1749 struct cache_entry *centry = NULL;
1757 centry = wcache_fetch(cache, domain, "UG/%s", sid_to_string(sid_string, user_sid));
1759 /* If we have an access denied cache entry and a cached info3 in the
1760 samlogon cache then do a query. This will force the rpc back end
1761 to return the info3 data. */
1763 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1764 netsamlogon_cache_have(user_sid)) {
1765 DEBUG(10, ("lookup_usergroups: cached access denied and have cached info3\n"));
1766 domain->last_status = NT_STATUS_OK;
1767 centry_free(centry);
1774 *num_groups = centry_uint32(centry);
1776 if (*num_groups == 0)
1779 (*user_gids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
1780 if (! (*user_gids)) {
1781 smb_panic_fn("lookup_usergroups out of memory");
1783 for (i=0; i<(*num_groups); i++) {
1784 centry_sid(centry, mem_ctx, &(*user_gids)[i]);
1788 status = centry->status;
1790 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status: %s\n",
1791 domain->name, nt_errstr(status) ));
1793 centry_free(centry);
1798 (*user_gids) = NULL;
1800 /* Return status value returned by seq number check */
1802 if (!NT_STATUS_IS_OK(domain->last_status))
1803 return domain->last_status;
1805 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
1808 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
1810 if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
1814 refresh_sequence_number(domain, False);
1815 centry = centry_start(domain, status);
1819 centry_put_uint32(centry, *num_groups);
1820 for (i=0; i<(*num_groups); i++) {
1821 centry_put_sid(centry, &(*user_gids)[i]);
1824 centry_end(centry, "UG/%s", sid_to_string(sid_string, user_sid));
1825 centry_free(centry);
1831 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
1832 TALLOC_CTX *mem_ctx,
1833 uint32 num_sids, const DOM_SID *sids,
1834 uint32 *num_aliases, uint32 **alias_rids)
1836 struct winbind_cache *cache = get_cache(domain);
1837 struct cache_entry *centry = NULL;
1839 char *sidlist = talloc_strdup(mem_ctx, "");
1845 if (num_sids == 0) {
1848 return NT_STATUS_OK;
1851 /* We need to cache indexed by the whole list of SIDs, the aliases
1852 * resulting might come from any of the SIDs. */
1854 for (i=0; i<num_sids; i++) {
1855 sidlist = talloc_asprintf(mem_ctx, "%s/%s", sidlist,
1856 sid_string_static(&sids[i]));
1857 if (sidlist == NULL)
1858 return NT_STATUS_NO_MEMORY;
1861 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
1866 *num_aliases = centry_uint32(centry);
1870 (*alias_rids) = TALLOC_ARRAY(mem_ctx, uint32, *num_aliases);
1872 if ((*alias_rids) == NULL) {
1873 centry_free(centry);
1874 return NT_STATUS_NO_MEMORY;
1877 (*alias_rids) = NULL;
1880 for (i=0; i<(*num_aliases); i++)
1881 (*alias_rids)[i] = centry_uint32(centry);
1883 status = centry->status;
1885 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
1886 "status %s\n", domain->name, nt_errstr(status)));
1888 centry_free(centry);
1893 (*alias_rids) = NULL;
1895 if (!NT_STATUS_IS_OK(domain->last_status))
1896 return domain->last_status;
1898 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
1899 "for domain %s\n", domain->name ));
1901 status = domain->backend->lookup_useraliases(domain, mem_ctx,
1903 num_aliases, alias_rids);
1906 refresh_sequence_number(domain, False);
1907 centry = centry_start(domain, status);
1910 centry_put_uint32(centry, *num_aliases);
1911 for (i=0; i<(*num_aliases); i++)
1912 centry_put_uint32(centry, (*alias_rids)[i]);
1913 centry_end(centry, "UA%s", sidlist);
1914 centry_free(centry);
1921 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1922 TALLOC_CTX *mem_ctx,
1923 const DOM_SID *group_sid, uint32 *num_names,
1924 DOM_SID **sid_mem, char ***names,
1925 uint32 **name_types)
1927 struct winbind_cache *cache = get_cache(domain);
1928 struct cache_entry *centry = NULL;
1936 centry = wcache_fetch(cache, domain, "GM/%s", sid_to_string(sid_string, group_sid));
1940 *num_names = centry_uint32(centry);
1942 if (*num_names == 0)
1945 (*sid_mem) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_names);
1946 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_names);
1947 (*name_types) = TALLOC_ARRAY(mem_ctx, uint32, *num_names);
1949 if (! (*sid_mem) || ! (*names) || ! (*name_types)) {
1950 smb_panic_fn("lookup_groupmem out of memory");
1953 for (i=0; i<(*num_names); i++) {
1954 centry_sid(centry, mem_ctx, &(*sid_mem)[i]);
1955 (*names)[i] = centry_string(centry, mem_ctx);
1956 (*name_types)[i] = centry_uint32(centry);
1960 status = centry->status;
1962 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status: %s\n",
1963 domain->name, nt_errstr(status)));
1965 centry_free(centry);
1972 (*name_types) = NULL;
1974 /* Return status value returned by seq number check */
1976 if (!NT_STATUS_IS_OK(domain->last_status))
1977 return domain->last_status;
1979 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
1982 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid, num_names,
1983 sid_mem, names, name_types);
1986 refresh_sequence_number(domain, False);
1987 centry = centry_start(domain, status);
1990 centry_put_uint32(centry, *num_names);
1991 for (i=0; i<(*num_names); i++) {
1992 centry_put_sid(centry, &(*sid_mem)[i]);
1993 centry_put_string(centry, (*names)[i]);
1994 centry_put_uint32(centry, (*name_types)[i]);
1996 centry_end(centry, "GM/%s", sid_to_string(sid_string, group_sid));
1997 centry_free(centry);
2003 /* find the sequence number for a domain */
2004 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
2006 refresh_sequence_number(domain, False);
2008 *seq = domain->sequence_number;
2010 return NT_STATUS_OK;
2013 /* enumerate trusted domains
2014 * (we need to have the list of trustdoms in the cache when we go offline) -
2016 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
2017 TALLOC_CTX *mem_ctx,
2018 uint32 *num_domains,
2023 struct winbind_cache *cache = get_cache(domain);
2024 struct cache_entry *centry = NULL;
2031 centry = wcache_fetch(cache, domain, "TRUSTDOMS/%s", domain->name);
2037 *num_domains = centry_uint32(centry);
2040 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
2041 (*alt_names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
2042 (*dom_sids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
2044 if (! (*dom_sids) || ! (*names) || ! (*alt_names)) {
2045 smb_panic_fn("trusted_domains out of memory");
2049 (*alt_names) = NULL;
2053 for (i=0; i<(*num_domains); i++) {
2054 (*names)[i] = centry_string(centry, mem_ctx);
2055 (*alt_names)[i] = centry_string(centry, mem_ctx);
2056 centry_sid(centry, mem_ctx, &(*dom_sids)[i]);
2059 status = centry->status;
2061 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
2062 domain->name, *num_domains, nt_errstr(status) ));
2064 centry_free(centry);
2071 (*alt_names) = NULL;
2073 /* Return status value returned by seq number check */
2075 if (!NT_STATUS_IS_OK(domain->last_status))
2076 return domain->last_status;
2078 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2081 status = domain->backend->trusted_domains(domain, mem_ctx, num_domains,
2082 names, alt_names, dom_sids);
2084 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2085 * so that the generic centry handling still applies correctly -
2088 if (!NT_STATUS_IS_ERR(status)) {
2089 status = NT_STATUS_OK;
2093 #if 0 /* Disabled as we want the trust dom list to be managed by
2094 the main parent and always to make the query. --jerry */
2097 refresh_sequence_number(domain, False);
2099 centry = centry_start(domain, status);
2103 centry_put_uint32(centry, *num_domains);
2105 for (i=0; i<(*num_domains); i++) {
2106 centry_put_string(centry, (*names)[i]);
2107 centry_put_string(centry, (*alt_names)[i]);
2108 centry_put_sid(centry, &(*dom_sids)[i]);
2111 centry_end(centry, "TRUSTDOMS/%s", domain->name);
2113 centry_free(centry);
2121 /* get lockout policy */
2122 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
2123 TALLOC_CTX *mem_ctx,
2124 SAM_UNK_INFO_12 *policy){
2125 struct winbind_cache *cache = get_cache(domain);
2126 struct cache_entry *centry = NULL;
2132 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2137 policy->duration = centry_nttime(centry);
2138 policy->reset_count = centry_nttime(centry);
2139 policy->bad_attempt_lockout = centry_uint16(centry);
2141 status = centry->status;
2143 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2144 domain->name, nt_errstr(status) ));
2146 centry_free(centry);
2150 ZERO_STRUCTP(policy);
2152 /* Return status value returned by seq number check */
2154 if (!NT_STATUS_IS_OK(domain->last_status))
2155 return domain->last_status;
2157 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2160 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2163 refresh_sequence_number(domain, False);
2164 wcache_save_lockout_policy(domain, status, policy);
2169 /* get password policy */
2170 static NTSTATUS password_policy(struct winbindd_domain *domain,
2171 TALLOC_CTX *mem_ctx,
2172 SAM_UNK_INFO_1 *policy)
2174 struct winbind_cache *cache = get_cache(domain);
2175 struct cache_entry *centry = NULL;
2181 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2186 policy->min_length_password = centry_uint16(centry);
2187 policy->password_history = centry_uint16(centry);
2188 policy->password_properties = centry_uint32(centry);
2189 policy->expire = centry_nttime(centry);
2190 policy->min_passwordage = centry_nttime(centry);
2192 status = centry->status;
2194 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2195 domain->name, nt_errstr(status) ));
2197 centry_free(centry);
2201 ZERO_STRUCTP(policy);
2203 /* Return status value returned by seq number check */
2205 if (!NT_STATUS_IS_OK(domain->last_status))
2206 return domain->last_status;
2208 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2211 status = domain->backend->password_policy(domain, mem_ctx, policy);
2214 refresh_sequence_number(domain, False);
2215 wcache_save_password_policy(domain, status, policy);
2221 /* Invalidate cached user and group lists coherently */
2223 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2226 if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
2227 strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
2228 tdb_delete(the_tdb, kbuf);
2233 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2235 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
2236 NET_USER_INFO_3 *info3)
2238 struct winbind_cache *cache;
2240 /* dont clear cached U/SID and UG/SID entries when we want to logon
2243 if (lp_winbind_offline_logon()) {
2250 cache = get_cache(domain);
2251 netsamlogon_clear_cached_user(cache->tdb, info3);
2254 void wcache_invalidate_cache(void)
2256 struct winbindd_domain *domain;
2258 for (domain = domain_list(); domain; domain = domain->next) {
2259 struct winbind_cache *cache = get_cache(domain);
2261 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2262 "entries for %s\n", domain->name));
2264 tdb_traverse(cache->tdb, traverse_fn, NULL);
2268 bool init_wcache(void)
2270 if (wcache == NULL) {
2271 wcache = SMB_XMALLOC_P(struct winbind_cache);
2272 ZERO_STRUCTP(wcache);
2275 if (wcache->tdb != NULL)
2278 /* when working offline we must not clear the cache on restart */
2279 wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
2280 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2281 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
2282 O_RDWR|O_CREAT, 0600);
2284 if (wcache->tdb == NULL) {
2285 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2292 /************************************************************************
2293 This is called by the parent to initialize the cache file.
2294 We don't need sophisticated locking here as we know we're the
2296 ************************************************************************/
2298 bool initialize_winbindd_cache(void)
2300 bool cache_bad = True;
2303 if (!init_wcache()) {
2304 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
2308 /* Check version number. */
2309 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
2310 vers == WINBINDD_CACHE_VERSION) {
2315 DEBUG(0,("initialize_winbindd_cache: clearing cache "
2316 "and re-creating with version number %d\n",
2317 WINBINDD_CACHE_VERSION ));
2319 tdb_close(wcache->tdb);
2322 if (unlink(lock_path("winbindd_cache.tdb")) == -1) {
2323 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
2324 lock_path("winbindd_cache.tdb"),
2328 if (!init_wcache()) {
2329 DEBUG(0,("initialize_winbindd_cache: re-initialization "
2330 "init_wcache failed.\n"));
2334 /* Write the version. */
2335 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
2336 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
2337 tdb_errorstr(wcache->tdb) ));
2342 tdb_close(wcache->tdb);
2347 void cache_store_response(pid_t pid, struct winbindd_response *response)
2354 DEBUG(10, ("Storing response for pid %d, len %d\n",
2355 pid, response->length));
2357 fstr_sprintf(key_str, "DR/%d", pid);
2358 if (tdb_store(wcache->tdb, string_tdb_data(key_str),
2359 make_tdb_data((uint8 *)response, sizeof(*response)),
2363 if (response->length == sizeof(*response))
2366 /* There's extra data */
2368 DEBUG(10, ("Storing extra data: len=%d\n",
2369 (int)(response->length - sizeof(*response))));
2371 fstr_sprintf(key_str, "DE/%d", pid);
2372 if (tdb_store(wcache->tdb, string_tdb_data(key_str),
2373 make_tdb_data((uint8 *)response->extra_data.data,
2374 response->length - sizeof(*response)),
2378 /* We could not store the extra data, make sure the tdb does not
2379 * contain a main record with wrong dangling extra data */
2381 fstr_sprintf(key_str, "DR/%d", pid);
2382 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2387 bool cache_retrieve_response(pid_t pid, struct winbindd_response * response)
2395 DEBUG(10, ("Retrieving response for pid %d\n", pid));
2397 fstr_sprintf(key_str, "DR/%d", pid);
2398 data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
2400 if (data.dptr == NULL)
2403 if (data.dsize != sizeof(*response))
2406 memcpy(response, data.dptr, data.dsize);
2407 SAFE_FREE(data.dptr);
2409 if (response->length == sizeof(*response)) {
2410 response->extra_data.data = NULL;
2414 /* There's extra data */
2416 DEBUG(10, ("Retrieving extra data length=%d\n",
2417 (int)(response->length - sizeof(*response))));
2419 fstr_sprintf(key_str, "DE/%d", pid);
2420 data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
2422 if (data.dptr == NULL) {
2423 DEBUG(0, ("Did not find extra data\n"));
2427 if (data.dsize != (response->length - sizeof(*response))) {
2428 DEBUG(0, ("Invalid extra data length: %d\n", (int)data.dsize));
2429 SAFE_FREE(data.dptr);
2433 dump_data(11, (uint8 *)data.dptr, data.dsize);
2435 response->extra_data.data = data.dptr;
2439 void cache_cleanup_response(pid_t pid)
2446 fstr_sprintf(key_str, "DR/%d", pid);
2447 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2449 fstr_sprintf(key_str, "DE/%d", pid);
2450 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2456 bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
2457 char **domain_name, char **name,
2458 enum lsa_SidType *type)
2460 struct winbindd_domain *domain;
2461 struct winbind_cache *cache;
2462 struct cache_entry *centry = NULL;
2465 domain = find_lookup_domain_from_sid(sid);
2466 if (domain == NULL) {
2470 cache = get_cache(domain);
2472 if (cache->tdb == NULL) {
2476 centry = wcache_fetch(cache, domain, "SN/%s", sid_string_static(sid));
2477 if (centry == NULL) {
2481 if (NT_STATUS_IS_OK(centry->status)) {
2482 *type = (enum lsa_SidType)centry_uint32(centry);
2483 *domain_name = centry_string(centry, mem_ctx);
2484 *name = centry_string(centry, mem_ctx);
2487 status = centry->status;
2488 centry_free(centry);
2489 return NT_STATUS_IS_OK(status);
2492 bool lookup_cached_name(TALLOC_CTX *mem_ctx,
2493 const char *domain_name,
2496 enum lsa_SidType *type)
2498 struct winbindd_domain *domain;
2499 struct winbind_cache *cache;
2500 struct cache_entry *centry = NULL;
2503 bool original_online_state;
2505 domain = find_lookup_domain_from_name(domain_name);
2506 if (domain == NULL) {
2510 cache = get_cache(domain);
2512 if (cache->tdb == NULL) {
2516 fstrcpy(uname, name);
2519 /* If we are doing a cached logon, temporarily set the domain
2520 offline so the cache won't expire the entry */
2522 original_online_state = domain->online;
2523 domain->online = False;
2524 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
2525 domain->online = original_online_state;
2527 if (centry == NULL) {
2531 if (NT_STATUS_IS_OK(centry->status)) {
2532 *type = (enum lsa_SidType)centry_uint32(centry);
2533 centry_sid(centry, mem_ctx, sid);
2536 status = centry->status;
2537 centry_free(centry);
2539 return NT_STATUS_IS_OK(status);
2542 void cache_name2sid(struct winbindd_domain *domain,
2543 const char *domain_name, const char *name,
2544 enum lsa_SidType type, const DOM_SID *sid)
2546 refresh_sequence_number(domain, False);
2547 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
2552 * The original idea that this cache only contains centries has
2553 * been blurred - now other stuff gets put in here. Ensure we
2554 * ignore these things on cleanup.
2557 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
2558 TDB_DATA dbuf, void *state)
2560 struct cache_entry *centry;
2562 if (is_non_centry_key(kbuf)) {
2566 centry = wcache_fetch_raw((char *)kbuf.dptr);
2571 if (!NT_STATUS_IS_OK(centry->status)) {
2572 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
2573 tdb_delete(the_tdb, kbuf);
2576 centry_free(centry);
2580 /* flush the cache */
2581 void wcache_flush_cache(void)
2586 tdb_close(wcache->tdb);
2592 /* when working offline we must not clear the cache on restart */
2593 wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
2594 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2595 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
2596 O_RDWR|O_CREAT, 0600);
2599 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2603 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
2605 DEBUG(10,("wcache_flush_cache success\n"));
2608 /* Count cached creds */
2610 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2613 int *cred_count = (int*)state;
2615 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
2621 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
2623 struct winbind_cache *cache = get_cache(domain);
2628 return NT_STATUS_INTERNAL_DB_ERROR;
2631 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
2633 return NT_STATUS_OK;
2637 struct cred_list *prev, *next;
2642 static struct cred_list *wcache_cred_list;
2644 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2647 struct cred_list *cred;
2649 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
2651 cred = SMB_MALLOC_P(struct cred_list);
2653 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2659 /* save a copy of the key */
2661 fstrcpy(cred->name, (const char *)kbuf.dptr);
2662 DLIST_ADD(wcache_cred_list, cred);
2668 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const DOM_SID *sid)
2670 struct winbind_cache *cache = get_cache(domain);
2673 struct cred_list *cred, *oldest = NULL;
2676 return NT_STATUS_INTERNAL_DB_ERROR;
2679 /* we possibly already have an entry */
2680 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
2684 DEBUG(11,("we already have an entry, deleting that\n"));
2686 fstr_sprintf(key_str, "CRED/%s", sid_string_static(sid));
2688 tdb_delete(cache->tdb, string_tdb_data(key_str));
2690 return NT_STATUS_OK;
2693 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
2695 return NT_STATUS_OK;
2696 } else if ((ret == -1) || (wcache_cred_list == NULL)) {
2697 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2700 ZERO_STRUCTP(oldest);
2702 for (cred = wcache_cred_list; cred; cred = cred->next) {
2707 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
2709 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
2711 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
2715 t = IVAL(data.dptr, 0);
2716 SAFE_FREE(data.dptr);
2719 oldest = SMB_MALLOC_P(struct cred_list);
2720 if (oldest == NULL) {
2721 status = NT_STATUS_NO_MEMORY;
2725 fstrcpy(oldest->name, cred->name);
2726 oldest->created = t;
2730 if (t < oldest->created) {
2731 fstrcpy(oldest->name, cred->name);
2732 oldest->created = t;
2736 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
2737 status = NT_STATUS_OK;
2739 status = NT_STATUS_UNSUCCESSFUL;
2742 SAFE_FREE(wcache_cred_list);
2748 /* Change the global online/offline state. */
2749 bool set_global_winbindd_state_offline(void)
2753 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
2755 /* Only go offline if someone has created
2756 the key "WINBINDD_OFFLINE" in the cache tdb. */
2758 if (wcache == NULL || wcache->tdb == NULL) {
2759 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
2763 if (!lp_winbind_offline_logon()) {
2764 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
2768 if (global_winbindd_offline_state) {
2769 /* Already offline. */
2773 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
2775 if (!data.dptr || data.dsize != 4) {
2776 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
2777 SAFE_FREE(data.dptr);
2780 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
2781 global_winbindd_offline_state = True;
2782 SAFE_FREE(data.dptr);
2787 void set_global_winbindd_state_online(void)
2789 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
2791 if (!lp_winbind_offline_logon()) {
2792 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
2796 if (!global_winbindd_offline_state) {
2797 /* Already online. */
2800 global_winbindd_offline_state = False;
2806 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
2807 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
2810 bool get_global_winbindd_state_offline(void)
2812 return global_winbindd_offline_state;
2815 /***********************************************************************
2816 Validate functions for all possible cache tdb keys.
2817 ***********************************************************************/
2819 static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
2820 struct tdb_validation_status *state)
2822 struct cache_entry *centry;
2824 centry = SMB_XMALLOC_P(struct cache_entry);
2825 centry->data = (unsigned char *)memdup(data.dptr, data.dsize);
2826 if (!centry->data) {
2830 centry->len = data.dsize;
2833 if (centry->len < 8) {
2834 /* huh? corrupt cache? */
2835 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr));
2836 centry_free(centry);
2837 state->bad_entry = True;
2838 state->success = False;
2842 centry->status = NT_STATUS(centry_uint32(centry));
2843 centry->sequence_number = centry_uint32(centry);
2847 static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2848 struct tdb_validation_status *state)
2850 if (dbuf.dsize != 8) {
2851 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
2852 keystr, (unsigned int)dbuf.dsize ));
2853 state->bad_entry = True;
2859 static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2860 struct tdb_validation_status *state)
2862 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2867 (void)centry_uint32(centry);
2868 if (NT_STATUS_IS_OK(centry->status)) {
2870 (void)centry_sid(centry, mem_ctx, &sid);
2873 centry_free(centry);
2875 if (!(state->success)) {
2878 DEBUG(10,("validate_ns: %s ok\n", keystr));
2882 static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2883 struct tdb_validation_status *state)
2885 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2890 if (NT_STATUS_IS_OK(centry->status)) {
2891 (void)centry_uint32(centry);
2892 (void)centry_string(centry, mem_ctx);
2893 (void)centry_string(centry, mem_ctx);
2896 centry_free(centry);
2898 if (!(state->success)) {
2901 DEBUG(10,("validate_sn: %s ok\n", keystr));
2905 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2906 struct tdb_validation_status *state)
2908 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2915 (void)centry_string(centry, mem_ctx);
2916 (void)centry_string(centry, mem_ctx);
2917 (void)centry_string(centry, mem_ctx);
2918 (void)centry_string(centry, mem_ctx);
2919 (void)centry_uint32(centry);
2920 (void)centry_sid(centry, mem_ctx, &sid);
2921 (void)centry_sid(centry, mem_ctx, &sid);
2923 centry_free(centry);
2925 if (!(state->success)) {
2928 DEBUG(10,("validate_u: %s ok\n", keystr));
2932 static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2933 struct tdb_validation_status *state)
2935 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2941 (void)centry_nttime(centry);
2942 (void)centry_nttime(centry);
2943 (void)centry_uint16(centry);
2945 centry_free(centry);
2947 if (!(state->success)) {
2950 DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
2954 static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2955 struct tdb_validation_status *state)
2957 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2963 (void)centry_uint16(centry);
2964 (void)centry_uint16(centry);
2965 (void)centry_uint32(centry);
2966 (void)centry_nttime(centry);
2967 (void)centry_nttime(centry);
2969 centry_free(centry);
2971 if (!(state->success)) {
2974 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
2978 static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2979 struct tdb_validation_status *state)
2981 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2987 (void)centry_time(centry);
2988 (void)centry_hash16(centry, mem_ctx);
2990 /* We only have 17 bytes more data in the salted cred case. */
2991 if (centry->len - centry->ofs == 17) {
2992 (void)centry_hash16(centry, mem_ctx);
2995 centry_free(centry);
2997 if (!(state->success)) {
3000 DEBUG(10,("validate_cred: %s ok\n", keystr));
3004 static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3005 struct tdb_validation_status *state)
3007 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3008 int32 num_entries, i;
3014 num_entries = (int32)centry_uint32(centry);
3016 for (i=0; i< num_entries; i++) {
3018 (void)centry_string(centry, mem_ctx);
3019 (void)centry_string(centry, mem_ctx);
3020 (void)centry_string(centry, mem_ctx);
3021 (void)centry_string(centry, mem_ctx);
3022 (void)centry_sid(centry, mem_ctx, &sid);
3023 (void)centry_sid(centry, mem_ctx, &sid);
3026 centry_free(centry);
3028 if (!(state->success)) {
3031 DEBUG(10,("validate_ul: %s ok\n", keystr));
3035 static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3036 struct tdb_validation_status *state)
3038 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3039 int32 num_entries, i;
3045 num_entries = centry_uint32(centry);
3047 for (i=0; i< num_entries; i++) {
3048 (void)centry_string(centry, mem_ctx);
3049 (void)centry_string(centry, mem_ctx);
3050 (void)centry_uint32(centry);
3053 centry_free(centry);
3055 if (!(state->success)) {
3058 DEBUG(10,("validate_gl: %s ok\n", keystr));
3062 static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3063 struct tdb_validation_status *state)
3065 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3066 int32 num_groups, i;
3072 num_groups = centry_uint32(centry);
3074 for (i=0; i< num_groups; i++) {
3076 centry_sid(centry, mem_ctx, &sid);
3079 centry_free(centry);
3081 if (!(state->success)) {
3084 DEBUG(10,("validate_ug: %s ok\n", keystr));
3088 static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3089 struct tdb_validation_status *state)
3091 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3092 int32 num_aliases, i;
3098 num_aliases = centry_uint32(centry);
3100 for (i=0; i < num_aliases; i++) {
3101 (void)centry_uint32(centry);
3104 centry_free(centry);
3106 if (!(state->success)) {
3109 DEBUG(10,("validate_ua: %s ok\n", keystr));
3113 static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3114 struct tdb_validation_status *state)
3116 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3123 num_names = centry_uint32(centry);
3125 for (i=0; i< num_names; i++) {
3127 centry_sid(centry, mem_ctx, &sid);
3128 (void)centry_string(centry, mem_ctx);
3129 (void)centry_uint32(centry);
3132 centry_free(centry);
3134 if (!(state->success)) {
3137 DEBUG(10,("validate_gm: %s ok\n", keystr));
3141 static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3142 struct tdb_validation_status *state)
3144 /* Can't say anything about this other than must be nonzero. */
3145 if (dbuf.dsize == 0) {
3146 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3148 state->bad_entry = True;
3149 state->success = False;
3153 DEBUG(10,("validate_dr: %s ok\n", keystr));
3157 static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3158 struct tdb_validation_status *state)
3160 /* Can't say anything about this other than must be nonzero. */
3161 if (dbuf.dsize == 0) {
3162 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3164 state->bad_entry = True;
3165 state->success = False;
3169 DEBUG(10,("validate_de: %s ok\n", keystr));
3173 static int validate_trustdoms(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3174 struct tdb_validation_status *state)
3176 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3177 int32 num_domains, i;
3183 num_domains = centry_uint32(centry);
3185 for (i=0; i< num_domains; i++) {
3187 (void)centry_string(centry, mem_ctx);
3188 (void)centry_string(centry, mem_ctx);
3189 (void)centry_sid(centry, mem_ctx, &sid);
3192 centry_free(centry);
3194 if (!(state->success)) {
3197 DEBUG(10,("validate_trustdoms: %s ok\n", keystr));
3201 static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
3203 struct tdb_validation_status *state)
3205 if (dbuf.dsize == 0) {
3206 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3207 "key %s (len ==0) ?\n", keystr));
3208 state->bad_entry = True;
3209 state->success = False;
3213 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
3214 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3218 static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3219 struct tdb_validation_status *state)
3221 if (dbuf.dsize != 4) {
3222 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3223 keystr, (unsigned int)dbuf.dsize ));
3224 state->bad_entry = True;
3225 state->success = False;
3228 DEBUG(10,("validate_offline: %s ok\n", keystr));
3232 static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3233 struct tdb_validation_status *state)
3235 if (dbuf.dsize != 4) {
3236 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3237 "key %s (len %u != 4) ?\n",
3238 keystr, (unsigned int)dbuf.dsize));
3239 state->bad_entry = True;
3240 state->success = False;
3244 DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
3248 /***********************************************************************
3249 A list of all possible cache tdb keys with associated validation
3251 ***********************************************************************/
3253 struct key_val_struct {
3254 const char *keyname;
3255 int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
3257 {"SEQNUM/", validate_seqnum},
3258 {"NS/", validate_ns},
3259 {"SN/", validate_sn},
3261 {"LOC_POL/", validate_loc_pol},
3262 {"PWD_POL/", validate_pwd_pol},
3263 {"CRED/", validate_cred},
3264 {"UL/", validate_ul},
3265 {"GL/", validate_gl},
3266 {"UG/", validate_ug},
3267 {"UA", validate_ua},
3268 {"GM/", validate_gm},
3269 {"DR/", validate_dr},
3270 {"DE/", validate_de},
3271 {"TRUSTDOMS/", validate_trustdoms},
3272 {"TRUSTDOMCACHE/", validate_trustdomcache},
3273 {"WINBINDD_OFFLINE", validate_offline},
3274 {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
3278 /***********************************************************************
3279 Function to look at every entry in the tdb and validate it as far as
3281 ***********************************************************************/
3283 static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
3286 struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
3288 /* Paranoia check. */
3289 if (kbuf.dsize > 1024) {
3290 DEBUG(0,("cache_traverse_validate_fn: key length too large (%u) > 1024\n\n",
3291 (unsigned int)kbuf.dsize ));
3295 for (i = 0; key_val[i].keyname; i++) {
3296 size_t namelen = strlen(key_val[i].keyname);
3297 if (kbuf.dsize >= namelen && (
3298 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
3299 TALLOC_CTX *mem_ctx;
3303 keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
3307 memcpy(keystr, kbuf.dptr, kbuf.dsize);
3308 keystr[kbuf.dsize] = '\0';
3310 mem_ctx = talloc_init("validate_ctx");
3316 ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
3320 talloc_destroy(mem_ctx);
3325 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
3326 dump_data(0, (uint8 *)kbuf.dptr, kbuf.dsize);
3327 DEBUG(0,("data :\n"));
3328 dump_data(0, (uint8 *)dbuf.dptr, dbuf.dsize);
3329 v_state->unknown_key = True;
3330 v_state->success = False;
3331 return 1; /* terminate. */
3334 static void validate_panic(const char *const why)
3336 DEBUG(0,("validating cache: would panic %s\n", why ));
3337 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
3341 /***********************************************************************
3342 Try and validate every entry in the winbindd cache. If we fail here,
3343 delete the cache tdb and return non-zero.
3344 ***********************************************************************/
3346 int winbindd_validate_cache(void)
3349 const char *tdb_path = lock_path("winbindd_cache.tdb");
3350 TDB_CONTEXT *tdb = NULL;
3352 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3353 smb_panic_fn = validate_panic;
3356 tdb = tdb_open_log(tdb_path,
3357 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3358 ( lp_winbind_offline_logon()
3360 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
3364 DEBUG(0, ("winbindd_validate_cache: "
3365 "error opening/initializing tdb\n"));
3370 ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
3373 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
3374 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
3379 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
3380 smb_panic_fn = smb_panic;
3384 /***********************************************************************
3385 Try and validate every entry in the winbindd cache.
3386 ***********************************************************************/
3388 int winbindd_validate_cache_nobackup(void)
3391 const char *tdb_path = lock_path("winbindd_cache.tdb");
3393 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3394 smb_panic_fn = validate_panic;
3397 if (wcache == NULL || wcache->tdb == NULL) {
3398 ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
3400 ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
3404 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
3408 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
3410 smb_panic_fn = smb_panic;
3414 /*********************************************************************
3415 ********************************************************************/
3417 static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
3418 struct winbindd_tdc_domain **domains,
3419 size_t *num_domains )
3421 struct winbindd_tdc_domain *list = NULL;
3424 bool set_only = False;
3426 /* don't allow duplicates */
3431 for ( i=0; i< (*num_domains); i++ ) {
3432 if ( strequal( new_dom->name, list[i].domain_name ) ) {
3433 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
3444 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, 1 );
3447 list = TALLOC_REALLOC_ARRAY( *domains, *domains,
3448 struct winbindd_tdc_domain,
3453 ZERO_STRUCT( list[idx] );
3459 list[idx].domain_name = talloc_strdup( list, new_dom->name );
3460 list[idx].dns_name = talloc_strdup( list, new_dom->alt_name );
3462 if ( !is_null_sid( &new_dom->sid ) )
3463 sid_copy( &list[idx].sid, &new_dom->sid );
3465 if ( new_dom->domain_flags != 0x0 )
3466 list[idx].trust_flags = new_dom->domain_flags;
3468 if ( new_dom->domain_type != 0x0 )
3469 list[idx].trust_type = new_dom->domain_type;
3471 if ( new_dom->domain_trust_attribs != 0x0 )
3472 list[idx].trust_attribs = new_dom->domain_trust_attribs;
3476 *num_domains = idx + 1;
3482 /*********************************************************************
3483 ********************************************************************/
3485 static TDB_DATA make_tdc_key( const char *domain_name )
3487 char *keystr = NULL;
3488 TDB_DATA key = { NULL, 0 };
3490 if ( !domain_name ) {
3491 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
3496 asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name );
3497 key = string_term_tdb_data(keystr);
3502 /*********************************************************************
3503 ********************************************************************/
3505 static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
3507 unsigned char **buf )
3509 unsigned char *buffer = NULL;
3514 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
3522 /* Store the number of array items first */
3523 len += tdb_pack( buffer+len, buflen-len, "d",
3526 /* now pack each domain trust record */
3527 for ( i=0; i<num_domains; i++ ) {
3530 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
3531 domains[i].domain_name,
3532 domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
3535 len += tdb_pack( buffer+len, buflen-len, "fffddd",
3536 domains[i].domain_name,
3537 domains[i].dns_name,
3538 sid_string_static(&domains[i].sid),
3539 domains[i].trust_flags,
3540 domains[i].trust_attribs,
3541 domains[i].trust_type );
3544 if ( buflen < len ) {
3546 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
3547 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
3561 /*********************************************************************
3562 ********************************************************************/
3564 static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
3565 struct winbindd_tdc_domain **domains )
3567 fstring domain_name, dns_name, sid_string;
3568 uint32 type, attribs, flags;
3572 struct winbindd_tdc_domain *list = NULL;
3574 /* get the number of domains */
3575 len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
3577 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3581 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, num_domains );
3583 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
3587 for ( i=0; i<num_domains; i++ ) {
3588 len += tdb_unpack( buf+len, buflen-len, "fffddd",
3597 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3598 TALLOC_FREE( list );
3602 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
3603 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
3604 domain_name, dns_name, sid_string,
3605 flags, attribs, type));
3607 list[i].domain_name = talloc_strdup( list, domain_name );
3608 list[i].dns_name = talloc_strdup( list, dns_name );
3609 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
3610 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
3613 list[i].trust_flags = flags;
3614 list[i].trust_attribs = attribs;
3615 list[i].trust_type = type;
3623 /*********************************************************************
3624 ********************************************************************/
3626 static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
3628 TDB_DATA key = make_tdc_key( lp_workgroup() );
3629 TDB_DATA data = { NULL, 0 };
3635 /* See if we were asked to delete the cache entry */
3638 ret = tdb_delete( wcache->tdb, key );
3642 data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
3649 ret = tdb_store( wcache->tdb, key, data, 0 );
3652 SAFE_FREE( data.dptr );
3653 SAFE_FREE( key.dptr );
3655 return ( ret != -1 );
3658 /*********************************************************************
3659 ********************************************************************/
3661 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
3663 TDB_DATA key = make_tdc_key( lp_workgroup() );
3664 TDB_DATA data = { NULL, 0 };
3672 data = tdb_fetch( wcache->tdb, key );
3674 SAFE_FREE( key.dptr );
3679 *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
3681 SAFE_FREE( data.dptr );
3689 /*********************************************************************
3690 ********************************************************************/
3692 bool wcache_tdc_add_domain( struct winbindd_domain *domain )
3694 struct winbindd_tdc_domain *dom_list = NULL;
3695 size_t num_domains = 0;
3698 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
3699 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
3700 domain->name, domain->alt_name,
3701 sid_string_dbg(&domain->sid),
3702 domain->domain_flags,
3703 domain->domain_trust_attribs,
3704 domain->domain_type));
3706 if ( !init_wcache() ) {
3710 /* fetch the list */
3712 wcache_tdc_fetch_list( &dom_list, &num_domains );
3714 /* add the new domain */
3716 if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
3720 /* pack the domain */
3722 if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
3730 TALLOC_FREE( dom_list );
3735 /*********************************************************************
3736 ********************************************************************/
3738 struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
3740 struct winbindd_tdc_domain *dom_list = NULL;
3741 size_t num_domains = 0;
3743 struct winbindd_tdc_domain *d = NULL;
3745 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
3747 if ( !init_wcache() ) {
3751 /* fetch the list */
3753 wcache_tdc_fetch_list( &dom_list, &num_domains );
3755 for ( i=0; i<num_domains; i++ ) {
3756 if ( strequal(name, dom_list[i].domain_name) ||
3757 strequal(name, dom_list[i].dns_name) )
3759 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
3762 d = TALLOC_P( ctx, struct winbindd_tdc_domain );
3766 d->domain_name = talloc_strdup( d, dom_list[i].domain_name );
3767 d->dns_name = talloc_strdup( d, dom_list[i].dns_name );
3768 sid_copy( &d->sid, &dom_list[i].sid );
3769 d->trust_flags = dom_list[i].trust_flags;
3770 d->trust_type = dom_list[i].trust_type;
3771 d->trust_attribs = dom_list[i].trust_attribs;
3777 TALLOC_FREE( dom_list );
3783 /*********************************************************************
3784 ********************************************************************/
3786 void wcache_tdc_clear( void )
3788 if ( !init_wcache() )
3791 wcache_tdc_store_list( NULL, 0 );
3797 /*********************************************************************
3798 ********************************************************************/
3800 static void wcache_save_user_pwinfo(struct winbindd_domain *domain,
3802 const DOM_SID *user_sid,
3803 const char *homedir,
3808 struct cache_entry *centry;
3810 if ( (centry = centry_start(domain, status)) == NULL )
3813 centry_put_string( centry, homedir );
3814 centry_put_string( centry, shell );
3815 centry_put_string( centry, gecos );
3816 centry_put_uint32( centry, gid );
3818 centry_end(centry, "NSS/PWINFO/%s", sid_string_static(user_sid) );
3820 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid) ));
3822 centry_free(centry);
3825 NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
3826 const DOM_SID *user_sid,
3828 ADS_STRUCT *ads, LDAPMessage *msg,
3829 char **homedir, char **shell, char **gecos,
3832 struct winbind_cache *cache = get_cache(domain);
3833 struct cache_entry *centry = NULL;
3839 centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s", sid_string_static(user_sid));
3844 *homedir = centry_string( centry, ctx );
3845 *shell = centry_string( centry, ctx );
3846 *gecos = centry_string( centry, ctx );
3847 *p_gid = centry_uint32( centry );
3849 centry_free(centry);
3851 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
3852 sid_string_dbg(user_sid)));
3854 return NT_STATUS_OK;
3858 nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg,
3859 homedir, shell, gecos, p_gid );
3861 if ( NT_STATUS_IS_OK(nt_status) ) {
3862 wcache_save_user_pwinfo( domain, nt_status, user_sid,
3863 *homedir, *shell, *gecos, *p_gid );
3866 if ( NT_STATUS_EQUAL( nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
3867 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
3869 set_domain_offline( domain );
3876 /* the cache backend methods are exposed via this structure */
3877 struct winbindd_methods cache_methods = {