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, uname,
859 sid_string_static(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_static(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) {
1026 const char *sidstr = sid_string_static(sid);
1028 /* Bad (old) cred cache. Delete and pretend we
1030 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1032 wcache_delete("CRED/%s", sidstr);
1033 centry_free(centry);
1034 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1037 /* We only have 17 bytes more data in the salted cred case. */
1038 if (centry->len - centry->ofs == 17) {
1039 *cached_salt = (const uint8 *)centry_hash16(centry, mem_ctx);
1041 *cached_salt = NULL;
1044 dump_data_pw("cached_nt_pass", *cached_nt_pass, NT_HASH_LEN);
1046 dump_data_pw("cached_salt", *cached_salt, NT_HASH_LEN);
1049 status = centry->status;
1051 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1052 sid_string_static(sid), nt_errstr(status) ));
1054 centry_free(centry);
1058 /* Store creds for a SID - only writes out new salted ones. */
1060 NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
1061 TALLOC_CTX *mem_ctx,
1063 const uint8 nt_pass[NT_HASH_LEN])
1065 struct cache_entry *centry;
1068 uint8 cred_salt[NT_HASH_LEN];
1069 uint8 salted_hash[NT_HASH_LEN];
1071 if (is_null_sid(sid)) {
1072 return NT_STATUS_INVALID_SID;
1075 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1076 return NT_STATUS_INVALID_SID;
1079 centry = centry_start(domain, NT_STATUS_OK);
1081 return NT_STATUS_INTERNAL_DB_ERROR;
1084 dump_data_pw("nt_pass", nt_pass, NT_HASH_LEN);
1086 centry_put_time(centry, time(NULL));
1088 /* Create a salt and then salt the hash. */
1089 generate_random_buffer(cred_salt, NT_HASH_LEN);
1090 E_md5hash(cred_salt, nt_pass, salted_hash);
1092 centry_put_hash16(centry, salted_hash);
1093 centry_put_hash16(centry, cred_salt);
1094 centry_end(centry, "CRED/%s", sid_to_string(sid_string, sid));
1096 DEBUG(10,("wcache_save_creds: %s\n", sid_string));
1098 centry_free(centry);
1100 return NT_STATUS_OK;
1104 /* Query display info. This is the basic user list fn */
1105 static NTSTATUS query_user_list(struct winbindd_domain *domain,
1106 TALLOC_CTX *mem_ctx,
1107 uint32 *num_entries,
1108 WINBIND_USERINFO **info)
1110 struct winbind_cache *cache = get_cache(domain);
1111 struct cache_entry *centry = NULL;
1113 unsigned int i, retry;
1118 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1122 *num_entries = centry_uint32(centry);
1124 if (*num_entries == 0)
1127 (*info) = TALLOC_ARRAY(mem_ctx, WINBIND_USERINFO, *num_entries);
1129 smb_panic_fn("query_user_list out of memory");
1131 for (i=0; i<(*num_entries); i++) {
1132 (*info)[i].acct_name = centry_string(centry, mem_ctx);
1133 (*info)[i].full_name = centry_string(centry, mem_ctx);
1134 (*info)[i].homedir = centry_string(centry, mem_ctx);
1135 (*info)[i].shell = centry_string(centry, mem_ctx);
1136 centry_sid(centry, mem_ctx, &(*info)[i].user_sid);
1137 centry_sid(centry, mem_ctx, &(*info)[i].group_sid);
1141 status = centry->status;
1143 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1144 domain->name, nt_errstr(status) ));
1146 centry_free(centry);
1153 /* Return status value returned by seq number check */
1155 if (!NT_STATUS_IS_OK(domain->last_status))
1156 return domain->last_status;
1158 /* Put the query_user_list() in a retry loop. There appears to be
1159 * some bug either with Windows 2000 or Samba's handling of large
1160 * rpc replies. This manifests itself as sudden disconnection
1161 * at a random point in the enumeration of a large (60k) user list.
1162 * The retry loop simply tries the operation again. )-: It's not
1163 * pretty but an acceptable workaround until we work out what the
1164 * real problem is. */
1169 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1172 status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
1173 if (!NT_STATUS_IS_OK(status)) {
1174 DEBUG(3, ("query_user_list: returned 0x%08x, "
1175 "retrying\n", NT_STATUS_V(status)));
1177 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1178 DEBUG(3, ("query_user_list: flushing "
1179 "connection cache\n"));
1180 invalidate_cm_connection(&domain->conn);
1183 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
1187 refresh_sequence_number(domain, False);
1188 centry = centry_start(domain, status);
1191 centry_put_uint32(centry, *num_entries);
1192 for (i=0; i<(*num_entries); i++) {
1193 centry_put_string(centry, (*info)[i].acct_name);
1194 centry_put_string(centry, (*info)[i].full_name);
1195 centry_put_string(centry, (*info)[i].homedir);
1196 centry_put_string(centry, (*info)[i].shell);
1197 centry_put_sid(centry, &(*info)[i].user_sid);
1198 centry_put_sid(centry, &(*info)[i].group_sid);
1199 if (domain->backend && domain->backend->consistent) {
1200 /* when the backend is consistent we can pre-prime some mappings */
1201 wcache_save_name_to_sid(domain, NT_STATUS_OK,
1203 (*info)[i].acct_name,
1204 &(*info)[i].user_sid,
1206 wcache_save_sid_to_name(domain, NT_STATUS_OK,
1207 &(*info)[i].user_sid,
1209 (*info)[i].acct_name,
1211 wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
1214 centry_end(centry, "UL/%s", domain->name);
1215 centry_free(centry);
1221 /* list all domain groups */
1222 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
1223 TALLOC_CTX *mem_ctx,
1224 uint32 *num_entries,
1225 struct acct_info **info)
1227 struct winbind_cache *cache = get_cache(domain);
1228 struct cache_entry *centry = NULL;
1235 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1239 *num_entries = centry_uint32(centry);
1241 if (*num_entries == 0)
1244 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1246 smb_panic_fn("enum_dom_groups out of memory");
1248 for (i=0; i<(*num_entries); i++) {
1249 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1250 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1251 (*info)[i].rid = centry_uint32(centry);
1255 status = centry->status;
1257 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1258 domain->name, nt_errstr(status) ));
1260 centry_free(centry);
1267 /* Return status value returned by seq number check */
1269 if (!NT_STATUS_IS_OK(domain->last_status))
1270 return domain->last_status;
1272 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1275 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1278 refresh_sequence_number(domain, False);
1279 centry = centry_start(domain, status);
1282 centry_put_uint32(centry, *num_entries);
1283 for (i=0; i<(*num_entries); i++) {
1284 centry_put_string(centry, (*info)[i].acct_name);
1285 centry_put_string(centry, (*info)[i].acct_desc);
1286 centry_put_uint32(centry, (*info)[i].rid);
1288 centry_end(centry, "GL/%s/domain", domain->name);
1289 centry_free(centry);
1295 /* list all domain groups */
1296 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
1297 TALLOC_CTX *mem_ctx,
1298 uint32 *num_entries,
1299 struct acct_info **info)
1301 struct winbind_cache *cache = get_cache(domain);
1302 struct cache_entry *centry = NULL;
1309 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1313 *num_entries = centry_uint32(centry);
1315 if (*num_entries == 0)
1318 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1320 smb_panic_fn("enum_dom_groups out of memory");
1322 for (i=0; i<(*num_entries); i++) {
1323 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1324 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1325 (*info)[i].rid = centry_uint32(centry);
1330 /* If we are returning cached data and the domain controller
1331 is down then we don't know whether the data is up to date
1332 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1335 if (wcache_server_down(domain)) {
1336 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1337 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1339 status = centry->status;
1341 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1342 domain->name, nt_errstr(status) ));
1344 centry_free(centry);
1351 /* Return status value returned by seq number check */
1353 if (!NT_STATUS_IS_OK(domain->last_status))
1354 return domain->last_status;
1356 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1359 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1362 refresh_sequence_number(domain, False);
1363 centry = centry_start(domain, status);
1366 centry_put_uint32(centry, *num_entries);
1367 for (i=0; i<(*num_entries); i++) {
1368 centry_put_string(centry, (*info)[i].acct_name);
1369 centry_put_string(centry, (*info)[i].acct_desc);
1370 centry_put_uint32(centry, (*info)[i].rid);
1372 centry_end(centry, "GL/%s/local", domain->name);
1373 centry_free(centry);
1379 /* convert a single name to a sid in a domain */
1380 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
1381 TALLOC_CTX *mem_ctx,
1382 enum winbindd_cmd orig_cmd,
1383 const char *domain_name,
1386 enum lsa_SidType *type)
1388 struct winbind_cache *cache = get_cache(domain);
1389 struct cache_entry *centry = NULL;
1396 fstrcpy(uname, name);
1398 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1402 status = centry->status;
1403 if (NT_STATUS_IS_OK(status)) {
1404 *type = (enum lsa_SidType)centry_uint32(centry);
1405 centry_sid(centry, mem_ctx, sid);
1408 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: %s\n",
1409 domain->name, nt_errstr(status) ));
1411 centry_free(centry);
1417 /* If the seq number check indicated that there is a problem
1418 * with this DC, then return that status... except for
1419 * access_denied. This is special because the dc may be in
1420 * "restrict anonymous = 1" mode, in which case it will deny
1421 * most unauthenticated operations, but *will* allow the LSA
1422 * name-to-sid that we try as a fallback. */
1424 if (!(NT_STATUS_IS_OK(domain->last_status)
1425 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1426 return domain->last_status;
1428 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1431 status = domain->backend->name_to_sid(domain, mem_ctx, orig_cmd,
1432 domain_name, name, sid, type);
1435 refresh_sequence_number(domain, False);
1437 if (domain->online &&
1438 (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
1439 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1441 /* Only save the reverse mapping if this was not a UPN */
1442 if (!strchr(name, '@')) {
1443 strupper_m(CONST_DISCARD(char *,domain_name));
1444 strlower_m(CONST_DISCARD(char *,name));
1445 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1452 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1454 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
1455 TALLOC_CTX *mem_ctx,
1459 enum lsa_SidType *type)
1461 struct winbind_cache *cache = get_cache(domain);
1462 struct cache_entry *centry = NULL;
1469 centry = wcache_fetch(cache, domain, "SN/%s", sid_to_string(sid_string, sid));
1473 status = centry->status;
1474 if (NT_STATUS_IS_OK(status)) {
1475 *type = (enum lsa_SidType)centry_uint32(centry);
1476 *domain_name = centry_string(centry, mem_ctx);
1477 *name = centry_string(centry, mem_ctx);
1480 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: %s\n",
1481 domain->name, nt_errstr(status) ));
1483 centry_free(centry);
1488 *domain_name = NULL;
1490 /* If the seq number check indicated that there is a problem
1491 * with this DC, then return that status... except for
1492 * access_denied. This is special because the dc may be in
1493 * "restrict anonymous = 1" mode, in which case it will deny
1494 * most unauthenticated operations, but *will* allow the LSA
1495 * sid-to-name that we try as a fallback. */
1497 if (!(NT_STATUS_IS_OK(domain->last_status)
1498 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1499 return domain->last_status;
1501 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1504 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1507 refresh_sequence_number(domain, False);
1508 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1510 /* We can't save the name to sid mapping here, as with sid history a
1511 * later name2sid would give the wrong sid. */
1516 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
1517 TALLOC_CTX *mem_ctx,
1518 const DOM_SID *domain_sid,
1523 enum lsa_SidType **types)
1525 struct winbind_cache *cache = get_cache(domain);
1527 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1531 *domain_name = NULL;
1539 if (num_rids == 0) {
1540 return NT_STATUS_OK;
1543 *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
1544 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
1546 if ((*names == NULL) || (*types == NULL)) {
1547 result = NT_STATUS_NO_MEMORY;
1551 have_mapped = have_unmapped = False;
1553 for (i=0; i<num_rids; i++) {
1555 struct cache_entry *centry;
1557 if (!sid_compose(&sid, domain_sid, rids[i])) {
1558 result = NT_STATUS_INTERNAL_ERROR;
1562 centry = wcache_fetch(cache, domain, "SN/%s",
1563 sid_string_static(&sid));
1568 (*types)[i] = SID_NAME_UNKNOWN;
1569 (*names)[i] = talloc_strdup(*names, "");
1571 if (NT_STATUS_IS_OK(centry->status)) {
1574 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
1576 dom = centry_string(centry, mem_ctx);
1577 if (*domain_name == NULL) {
1583 (*names)[i] = centry_string(centry, *names);
1585 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
1586 have_unmapped = True;
1589 /* something's definitely wrong */
1590 result = centry->status;
1594 centry_free(centry);
1598 return NT_STATUS_NONE_MAPPED;
1600 if (!have_unmapped) {
1601 return NT_STATUS_OK;
1603 return STATUS_SOME_UNMAPPED;
1607 TALLOC_FREE(*names);
1608 TALLOC_FREE(*types);
1610 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
1611 rids, num_rids, domain_name,
1615 None of the queried rids has been found so save all negative entries
1617 if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
1618 for (i = 0; i < num_rids; i++) {
1620 const char *name = "";
1621 const enum lsa_SidType type = SID_NAME_UNKNOWN;
1622 NTSTATUS status = NT_STATUS_NONE_MAPPED;
1624 if (!sid_compose(&sid, domain_sid, rids[i])) {
1625 return NT_STATUS_INTERNAL_ERROR;
1628 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
1636 Some or all of the queried rids have been found.
1638 if (!NT_STATUS_IS_OK(result) &&
1639 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
1643 refresh_sequence_number(domain, False);
1645 for (i=0; i<num_rids; i++) {
1649 if (!sid_compose(&sid, domain_sid, rids[i])) {
1650 result = NT_STATUS_INTERNAL_ERROR;
1654 status = (*types)[i] == SID_NAME_UNKNOWN ?
1655 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
1657 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
1658 (*names)[i], (*types)[i]);
1665 TALLOC_FREE(*names);
1666 TALLOC_FREE(*types);
1670 /* Lookup user information from a rid */
1671 static NTSTATUS query_user(struct winbindd_domain *domain,
1672 TALLOC_CTX *mem_ctx,
1673 const DOM_SID *user_sid,
1674 WINBIND_USERINFO *info)
1676 struct winbind_cache *cache = get_cache(domain);
1677 struct cache_entry *centry = NULL;
1683 centry = wcache_fetch(cache, domain, "U/%s", sid_string_static(user_sid));
1685 /* If we have an access denied cache entry and a cached info3 in the
1686 samlogon cache then do a query. This will force the rpc back end
1687 to return the info3 data. */
1689 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1690 netsamlogon_cache_have(user_sid)) {
1691 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1692 domain->last_status = NT_STATUS_OK;
1693 centry_free(centry);
1700 /* if status is not ok then this is a negative hit
1701 and the rest of the data doesn't matter */
1702 status = centry->status;
1703 if (NT_STATUS_IS_OK(status)) {
1704 info->acct_name = centry_string(centry, mem_ctx);
1705 info->full_name = centry_string(centry, mem_ctx);
1706 info->homedir = centry_string(centry, mem_ctx);
1707 info->shell = centry_string(centry, mem_ctx);
1708 info->primary_gid = centry_uint32(centry);
1709 centry_sid(centry, mem_ctx, &info->user_sid);
1710 centry_sid(centry, mem_ctx, &info->group_sid);
1713 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: %s\n",
1714 domain->name, nt_errstr(status) ));
1716 centry_free(centry);
1722 /* Return status value returned by seq number check */
1724 if (!NT_STATUS_IS_OK(domain->last_status))
1725 return domain->last_status;
1727 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
1730 status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
1733 refresh_sequence_number(domain, False);
1734 wcache_save_user(domain, status, info);
1740 /* Lookup groups a user is a member of. */
1741 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
1742 TALLOC_CTX *mem_ctx,
1743 const DOM_SID *user_sid,
1744 uint32 *num_groups, DOM_SID **user_gids)
1746 struct winbind_cache *cache = get_cache(domain);
1747 struct cache_entry *centry = NULL;
1755 centry = wcache_fetch(cache, domain, "UG/%s", sid_to_string(sid_string, user_sid));
1757 /* If we have an access denied cache entry and a cached info3 in the
1758 samlogon cache then do a query. This will force the rpc back end
1759 to return the info3 data. */
1761 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1762 netsamlogon_cache_have(user_sid)) {
1763 DEBUG(10, ("lookup_usergroups: cached access denied and have cached info3\n"));
1764 domain->last_status = NT_STATUS_OK;
1765 centry_free(centry);
1772 *num_groups = centry_uint32(centry);
1774 if (*num_groups == 0)
1777 (*user_gids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
1778 if (! (*user_gids)) {
1779 smb_panic_fn("lookup_usergroups out of memory");
1781 for (i=0; i<(*num_groups); i++) {
1782 centry_sid(centry, mem_ctx, &(*user_gids)[i]);
1786 status = centry->status;
1788 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status: %s\n",
1789 domain->name, nt_errstr(status) ));
1791 centry_free(centry);
1796 (*user_gids) = NULL;
1798 /* Return status value returned by seq number check */
1800 if (!NT_STATUS_IS_OK(domain->last_status))
1801 return domain->last_status;
1803 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
1806 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
1808 if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
1812 refresh_sequence_number(domain, False);
1813 centry = centry_start(domain, status);
1817 centry_put_uint32(centry, *num_groups);
1818 for (i=0; i<(*num_groups); i++) {
1819 centry_put_sid(centry, &(*user_gids)[i]);
1822 centry_end(centry, "UG/%s", sid_to_string(sid_string, user_sid));
1823 centry_free(centry);
1829 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
1830 TALLOC_CTX *mem_ctx,
1831 uint32 num_sids, const DOM_SID *sids,
1832 uint32 *num_aliases, uint32 **alias_rids)
1834 struct winbind_cache *cache = get_cache(domain);
1835 struct cache_entry *centry = NULL;
1837 char *sidlist = talloc_strdup(mem_ctx, "");
1843 if (num_sids == 0) {
1846 return NT_STATUS_OK;
1849 /* We need to cache indexed by the whole list of SIDs, the aliases
1850 * resulting might come from any of the SIDs. */
1852 for (i=0; i<num_sids; i++) {
1853 sidlist = talloc_asprintf(mem_ctx, "%s/%s", sidlist,
1854 sid_string_static(&sids[i]));
1855 if (sidlist == NULL)
1856 return NT_STATUS_NO_MEMORY;
1859 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
1864 *num_aliases = centry_uint32(centry);
1868 (*alias_rids) = TALLOC_ARRAY(mem_ctx, uint32, *num_aliases);
1870 if ((*alias_rids) == NULL) {
1871 centry_free(centry);
1872 return NT_STATUS_NO_MEMORY;
1875 (*alias_rids) = NULL;
1878 for (i=0; i<(*num_aliases); i++)
1879 (*alias_rids)[i] = centry_uint32(centry);
1881 status = centry->status;
1883 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
1884 "status %s\n", domain->name, nt_errstr(status)));
1886 centry_free(centry);
1891 (*alias_rids) = NULL;
1893 if (!NT_STATUS_IS_OK(domain->last_status))
1894 return domain->last_status;
1896 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
1897 "for domain %s\n", domain->name ));
1899 status = domain->backend->lookup_useraliases(domain, mem_ctx,
1901 num_aliases, alias_rids);
1904 refresh_sequence_number(domain, False);
1905 centry = centry_start(domain, status);
1908 centry_put_uint32(centry, *num_aliases);
1909 for (i=0; i<(*num_aliases); i++)
1910 centry_put_uint32(centry, (*alias_rids)[i]);
1911 centry_end(centry, "UA%s", sidlist);
1912 centry_free(centry);
1919 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1920 TALLOC_CTX *mem_ctx,
1921 const DOM_SID *group_sid, uint32 *num_names,
1922 DOM_SID **sid_mem, char ***names,
1923 uint32 **name_types)
1925 struct winbind_cache *cache = get_cache(domain);
1926 struct cache_entry *centry = NULL;
1934 centry = wcache_fetch(cache, domain, "GM/%s", sid_to_string(sid_string, group_sid));
1938 *num_names = centry_uint32(centry);
1940 if (*num_names == 0)
1943 (*sid_mem) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_names);
1944 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_names);
1945 (*name_types) = TALLOC_ARRAY(mem_ctx, uint32, *num_names);
1947 if (! (*sid_mem) || ! (*names) || ! (*name_types)) {
1948 smb_panic_fn("lookup_groupmem out of memory");
1951 for (i=0; i<(*num_names); i++) {
1952 centry_sid(centry, mem_ctx, &(*sid_mem)[i]);
1953 (*names)[i] = centry_string(centry, mem_ctx);
1954 (*name_types)[i] = centry_uint32(centry);
1958 status = centry->status;
1960 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status: %s\n",
1961 domain->name, nt_errstr(status)));
1963 centry_free(centry);
1970 (*name_types) = NULL;
1972 /* Return status value returned by seq number check */
1974 if (!NT_STATUS_IS_OK(domain->last_status))
1975 return domain->last_status;
1977 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
1980 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid, num_names,
1981 sid_mem, names, name_types);
1984 refresh_sequence_number(domain, False);
1985 centry = centry_start(domain, status);
1988 centry_put_uint32(centry, *num_names);
1989 for (i=0; i<(*num_names); i++) {
1990 centry_put_sid(centry, &(*sid_mem)[i]);
1991 centry_put_string(centry, (*names)[i]);
1992 centry_put_uint32(centry, (*name_types)[i]);
1994 centry_end(centry, "GM/%s", sid_to_string(sid_string, group_sid));
1995 centry_free(centry);
2001 /* find the sequence number for a domain */
2002 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
2004 refresh_sequence_number(domain, False);
2006 *seq = domain->sequence_number;
2008 return NT_STATUS_OK;
2011 /* enumerate trusted domains
2012 * (we need to have the list of trustdoms in the cache when we go offline) -
2014 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
2015 TALLOC_CTX *mem_ctx,
2016 uint32 *num_domains,
2021 struct winbind_cache *cache = get_cache(domain);
2022 struct cache_entry *centry = NULL;
2029 centry = wcache_fetch(cache, domain, "TRUSTDOMS/%s", domain->name);
2035 *num_domains = centry_uint32(centry);
2038 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
2039 (*alt_names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
2040 (*dom_sids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
2042 if (! (*dom_sids) || ! (*names) || ! (*alt_names)) {
2043 smb_panic_fn("trusted_domains out of memory");
2047 (*alt_names) = NULL;
2051 for (i=0; i<(*num_domains); i++) {
2052 (*names)[i] = centry_string(centry, mem_ctx);
2053 (*alt_names)[i] = centry_string(centry, mem_ctx);
2054 centry_sid(centry, mem_ctx, &(*dom_sids)[i]);
2057 status = centry->status;
2059 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
2060 domain->name, *num_domains, nt_errstr(status) ));
2062 centry_free(centry);
2069 (*alt_names) = NULL;
2071 /* Return status value returned by seq number check */
2073 if (!NT_STATUS_IS_OK(domain->last_status))
2074 return domain->last_status;
2076 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2079 status = domain->backend->trusted_domains(domain, mem_ctx, num_domains,
2080 names, alt_names, dom_sids);
2082 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2083 * so that the generic centry handling still applies correctly -
2086 if (!NT_STATUS_IS_ERR(status)) {
2087 status = NT_STATUS_OK;
2091 #if 0 /* Disabled as we want the trust dom list to be managed by
2092 the main parent and always to make the query. --jerry */
2095 refresh_sequence_number(domain, False);
2097 centry = centry_start(domain, status);
2101 centry_put_uint32(centry, *num_domains);
2103 for (i=0; i<(*num_domains); i++) {
2104 centry_put_string(centry, (*names)[i]);
2105 centry_put_string(centry, (*alt_names)[i]);
2106 centry_put_sid(centry, &(*dom_sids)[i]);
2109 centry_end(centry, "TRUSTDOMS/%s", domain->name);
2111 centry_free(centry);
2119 /* get lockout policy */
2120 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
2121 TALLOC_CTX *mem_ctx,
2122 SAM_UNK_INFO_12 *policy){
2123 struct winbind_cache *cache = get_cache(domain);
2124 struct cache_entry *centry = NULL;
2130 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2135 policy->duration = centry_nttime(centry);
2136 policy->reset_count = centry_nttime(centry);
2137 policy->bad_attempt_lockout = centry_uint16(centry);
2139 status = centry->status;
2141 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2142 domain->name, nt_errstr(status) ));
2144 centry_free(centry);
2148 ZERO_STRUCTP(policy);
2150 /* Return status value returned by seq number check */
2152 if (!NT_STATUS_IS_OK(domain->last_status))
2153 return domain->last_status;
2155 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2158 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2161 refresh_sequence_number(domain, False);
2162 wcache_save_lockout_policy(domain, status, policy);
2167 /* get password policy */
2168 static NTSTATUS password_policy(struct winbindd_domain *domain,
2169 TALLOC_CTX *mem_ctx,
2170 SAM_UNK_INFO_1 *policy)
2172 struct winbind_cache *cache = get_cache(domain);
2173 struct cache_entry *centry = NULL;
2179 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2184 policy->min_length_password = centry_uint16(centry);
2185 policy->password_history = centry_uint16(centry);
2186 policy->password_properties = centry_uint32(centry);
2187 policy->expire = centry_nttime(centry);
2188 policy->min_passwordage = centry_nttime(centry);
2190 status = centry->status;
2192 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2193 domain->name, nt_errstr(status) ));
2195 centry_free(centry);
2199 ZERO_STRUCTP(policy);
2201 /* Return status value returned by seq number check */
2203 if (!NT_STATUS_IS_OK(domain->last_status))
2204 return domain->last_status;
2206 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2209 status = domain->backend->password_policy(domain, mem_ctx, policy);
2212 refresh_sequence_number(domain, False);
2213 wcache_save_password_policy(domain, status, policy);
2219 /* Invalidate cached user and group lists coherently */
2221 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2224 if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
2225 strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
2226 tdb_delete(the_tdb, kbuf);
2231 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2233 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
2234 NET_USER_INFO_3 *info3)
2236 struct winbind_cache *cache;
2238 /* dont clear cached U/SID and UG/SID entries when we want to logon
2241 if (lp_winbind_offline_logon()) {
2248 cache = get_cache(domain);
2249 netsamlogon_clear_cached_user(cache->tdb, info3);
2252 void wcache_invalidate_cache(void)
2254 struct winbindd_domain *domain;
2256 for (domain = domain_list(); domain; domain = domain->next) {
2257 struct winbind_cache *cache = get_cache(domain);
2259 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2260 "entries for %s\n", domain->name));
2262 tdb_traverse(cache->tdb, traverse_fn, NULL);
2266 BOOL init_wcache(void)
2268 if (wcache == NULL) {
2269 wcache = SMB_XMALLOC_P(struct winbind_cache);
2270 ZERO_STRUCTP(wcache);
2273 if (wcache->tdb != NULL)
2276 /* when working offline we must not clear the cache on restart */
2277 wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
2278 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2279 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
2280 O_RDWR|O_CREAT, 0600);
2282 if (wcache->tdb == NULL) {
2283 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2290 /************************************************************************
2291 This is called by the parent to initialize the cache file.
2292 We don't need sophisticated locking here as we know we're the
2294 ************************************************************************/
2296 BOOL initialize_winbindd_cache(void)
2298 BOOL cache_bad = True;
2301 if (!init_wcache()) {
2302 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
2306 /* Check version number. */
2307 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
2308 vers == WINBINDD_CACHE_VERSION) {
2313 DEBUG(0,("initialize_winbindd_cache: clearing cache "
2314 "and re-creating with version number %d\n",
2315 WINBINDD_CACHE_VERSION ));
2317 tdb_close(wcache->tdb);
2320 if (unlink(lock_path("winbindd_cache.tdb")) == -1) {
2321 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
2322 lock_path("winbindd_cache.tdb"),
2326 if (!init_wcache()) {
2327 DEBUG(0,("initialize_winbindd_cache: re-initialization "
2328 "init_wcache failed.\n"));
2332 /* Write the version. */
2333 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
2334 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
2335 tdb_errorstr(wcache->tdb) ));
2340 tdb_close(wcache->tdb);
2345 void cache_store_response(pid_t pid, struct winbindd_response *response)
2352 DEBUG(10, ("Storing response for pid %d, len %d\n",
2353 pid, response->length));
2355 fstr_sprintf(key_str, "DR/%d", pid);
2356 if (tdb_store(wcache->tdb, string_tdb_data(key_str),
2357 make_tdb_data((uint8 *)response, sizeof(*response)),
2361 if (response->length == sizeof(*response))
2364 /* There's extra data */
2366 DEBUG(10, ("Storing extra data: len=%d\n",
2367 (int)(response->length - sizeof(*response))));
2369 fstr_sprintf(key_str, "DE/%d", pid);
2370 if (tdb_store(wcache->tdb, string_tdb_data(key_str),
2371 make_tdb_data((uint8 *)response->extra_data.data,
2372 response->length - sizeof(*response)),
2376 /* We could not store the extra data, make sure the tdb does not
2377 * contain a main record with wrong dangling extra data */
2379 fstr_sprintf(key_str, "DR/%d", pid);
2380 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2385 BOOL cache_retrieve_response(pid_t pid, struct winbindd_response * response)
2393 DEBUG(10, ("Retrieving response for pid %d\n", pid));
2395 fstr_sprintf(key_str, "DR/%d", pid);
2396 data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
2398 if (data.dptr == NULL)
2401 if (data.dsize != sizeof(*response))
2404 memcpy(response, data.dptr, data.dsize);
2405 SAFE_FREE(data.dptr);
2407 if (response->length == sizeof(*response)) {
2408 response->extra_data.data = NULL;
2412 /* There's extra data */
2414 DEBUG(10, ("Retrieving extra data length=%d\n",
2415 (int)(response->length - sizeof(*response))));
2417 fstr_sprintf(key_str, "DE/%d", pid);
2418 data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
2420 if (data.dptr == NULL) {
2421 DEBUG(0, ("Did not find extra data\n"));
2425 if (data.dsize != (response->length - sizeof(*response))) {
2426 DEBUG(0, ("Invalid extra data length: %d\n", (int)data.dsize));
2427 SAFE_FREE(data.dptr);
2431 dump_data(11, (uint8 *)data.dptr, data.dsize);
2433 response->extra_data.data = data.dptr;
2437 void cache_cleanup_response(pid_t pid)
2444 fstr_sprintf(key_str, "DR/%d", pid);
2445 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2447 fstr_sprintf(key_str, "DE/%d", pid);
2448 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2454 BOOL lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
2455 char **domain_name, char **name,
2456 enum lsa_SidType *type)
2458 struct winbindd_domain *domain;
2459 struct winbind_cache *cache;
2460 struct cache_entry *centry = NULL;
2463 domain = find_lookup_domain_from_sid(sid);
2464 if (domain == NULL) {
2468 cache = get_cache(domain);
2470 if (cache->tdb == NULL) {
2474 centry = wcache_fetch(cache, domain, "SN/%s", sid_string_static(sid));
2475 if (centry == NULL) {
2479 if (NT_STATUS_IS_OK(centry->status)) {
2480 *type = (enum lsa_SidType)centry_uint32(centry);
2481 *domain_name = centry_string(centry, mem_ctx);
2482 *name = centry_string(centry, mem_ctx);
2485 status = centry->status;
2486 centry_free(centry);
2487 return NT_STATUS_IS_OK(status);
2490 BOOL lookup_cached_name(TALLOC_CTX *mem_ctx,
2491 const char *domain_name,
2494 enum lsa_SidType *type)
2496 struct winbindd_domain *domain;
2497 struct winbind_cache *cache;
2498 struct cache_entry *centry = NULL;
2501 BOOL original_online_state;
2503 domain = find_lookup_domain_from_name(domain_name);
2504 if (domain == NULL) {
2508 cache = get_cache(domain);
2510 if (cache->tdb == NULL) {
2514 fstrcpy(uname, name);
2517 /* If we are doing a cached logon, temporarily set the domain
2518 offline so the cache won't expire the entry */
2520 original_online_state = domain->online;
2521 domain->online = False;
2522 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
2523 domain->online = original_online_state;
2525 if (centry == NULL) {
2529 if (NT_STATUS_IS_OK(centry->status)) {
2530 *type = (enum lsa_SidType)centry_uint32(centry);
2531 centry_sid(centry, mem_ctx, sid);
2534 status = centry->status;
2535 centry_free(centry);
2537 return NT_STATUS_IS_OK(status);
2540 void cache_name2sid(struct winbindd_domain *domain,
2541 const char *domain_name, const char *name,
2542 enum lsa_SidType type, const DOM_SID *sid)
2544 refresh_sequence_number(domain, False);
2545 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
2550 * The original idea that this cache only contains centries has
2551 * been blurred - now other stuff gets put in here. Ensure we
2552 * ignore these things on cleanup.
2555 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
2556 TDB_DATA dbuf, void *state)
2558 struct cache_entry *centry;
2560 if (is_non_centry_key(kbuf)) {
2564 centry = wcache_fetch_raw((char *)kbuf.dptr);
2569 if (!NT_STATUS_IS_OK(centry->status)) {
2570 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
2571 tdb_delete(the_tdb, kbuf);
2574 centry_free(centry);
2578 /* flush the cache */
2579 void wcache_flush_cache(void)
2584 tdb_close(wcache->tdb);
2590 /* when working offline we must not clear the cache on restart */
2591 wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
2592 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2593 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
2594 O_RDWR|O_CREAT, 0600);
2597 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2601 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
2603 DEBUG(10,("wcache_flush_cache success\n"));
2606 /* Count cached creds */
2608 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2611 int *cred_count = (int*)state;
2613 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
2619 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
2621 struct winbind_cache *cache = get_cache(domain);
2626 return NT_STATUS_INTERNAL_DB_ERROR;
2629 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
2631 return NT_STATUS_OK;
2635 struct cred_list *prev, *next;
2640 static struct cred_list *wcache_cred_list;
2642 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2645 struct cred_list *cred;
2647 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
2649 cred = SMB_MALLOC_P(struct cred_list);
2651 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2657 /* save a copy of the key */
2659 fstrcpy(cred->name, (const char *)kbuf.dptr);
2660 DLIST_ADD(wcache_cred_list, cred);
2666 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const DOM_SID *sid)
2668 struct winbind_cache *cache = get_cache(domain);
2671 struct cred_list *cred, *oldest = NULL;
2674 return NT_STATUS_INTERNAL_DB_ERROR;
2677 /* we possibly already have an entry */
2678 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
2682 DEBUG(11,("we already have an entry, deleting that\n"));
2684 fstr_sprintf(key_str, "CRED/%s", sid_string_static(sid));
2686 tdb_delete(cache->tdb, string_tdb_data(key_str));
2688 return NT_STATUS_OK;
2691 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
2693 return NT_STATUS_OK;
2694 } else if ((ret == -1) || (wcache_cred_list == NULL)) {
2695 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2698 ZERO_STRUCTP(oldest);
2700 for (cred = wcache_cred_list; cred; cred = cred->next) {
2705 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
2707 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
2709 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
2713 t = IVAL(data.dptr, 0);
2714 SAFE_FREE(data.dptr);
2717 oldest = SMB_MALLOC_P(struct cred_list);
2718 if (oldest == NULL) {
2719 status = NT_STATUS_NO_MEMORY;
2723 fstrcpy(oldest->name, cred->name);
2724 oldest->created = t;
2728 if (t < oldest->created) {
2729 fstrcpy(oldest->name, cred->name);
2730 oldest->created = t;
2734 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
2735 status = NT_STATUS_OK;
2737 status = NT_STATUS_UNSUCCESSFUL;
2740 SAFE_FREE(wcache_cred_list);
2746 /* Change the global online/offline state. */
2747 BOOL set_global_winbindd_state_offline(void)
2751 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
2753 /* Only go offline if someone has created
2754 the key "WINBINDD_OFFLINE" in the cache tdb. */
2756 if (wcache == NULL || wcache->tdb == NULL) {
2757 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
2761 if (!lp_winbind_offline_logon()) {
2762 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
2766 if (global_winbindd_offline_state) {
2767 /* Already offline. */
2771 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
2773 if (!data.dptr || data.dsize != 4) {
2774 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
2775 SAFE_FREE(data.dptr);
2778 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
2779 global_winbindd_offline_state = True;
2780 SAFE_FREE(data.dptr);
2785 void set_global_winbindd_state_online(void)
2787 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
2789 if (!lp_winbind_offline_logon()) {
2790 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
2794 if (!global_winbindd_offline_state) {
2795 /* Already online. */
2798 global_winbindd_offline_state = False;
2804 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
2805 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
2808 BOOL get_global_winbindd_state_offline(void)
2810 return global_winbindd_offline_state;
2813 /***********************************************************************
2814 Validate functions for all possible cache tdb keys.
2815 ***********************************************************************/
2817 static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
2818 struct tdb_validation_status *state)
2820 struct cache_entry *centry;
2822 centry = SMB_XMALLOC_P(struct cache_entry);
2823 centry->data = (unsigned char *)memdup(data.dptr, data.dsize);
2824 if (!centry->data) {
2828 centry->len = data.dsize;
2831 if (centry->len < 8) {
2832 /* huh? corrupt cache? */
2833 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr));
2834 centry_free(centry);
2835 state->bad_entry = True;
2836 state->success = False;
2840 centry->status = NT_STATUS(centry_uint32(centry));
2841 centry->sequence_number = centry_uint32(centry);
2845 static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2846 struct tdb_validation_status *state)
2848 if (dbuf.dsize != 8) {
2849 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
2850 keystr, (unsigned int)dbuf.dsize ));
2851 state->bad_entry = True;
2857 static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2858 struct tdb_validation_status *state)
2860 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2865 (void)centry_uint32(centry);
2866 if (NT_STATUS_IS_OK(centry->status)) {
2868 (void)centry_sid(centry, mem_ctx, &sid);
2871 centry_free(centry);
2873 if (!(state->success)) {
2876 DEBUG(10,("validate_ns: %s ok\n", keystr));
2880 static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2881 struct tdb_validation_status *state)
2883 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2888 if (NT_STATUS_IS_OK(centry->status)) {
2889 (void)centry_uint32(centry);
2890 (void)centry_string(centry, mem_ctx);
2891 (void)centry_string(centry, mem_ctx);
2894 centry_free(centry);
2896 if (!(state->success)) {
2899 DEBUG(10,("validate_sn: %s ok\n", keystr));
2903 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2904 struct tdb_validation_status *state)
2906 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2913 (void)centry_string(centry, mem_ctx);
2914 (void)centry_string(centry, mem_ctx);
2915 (void)centry_string(centry, mem_ctx);
2916 (void)centry_string(centry, mem_ctx);
2917 (void)centry_uint32(centry);
2918 (void)centry_sid(centry, mem_ctx, &sid);
2919 (void)centry_sid(centry, mem_ctx, &sid);
2921 centry_free(centry);
2923 if (!(state->success)) {
2926 DEBUG(10,("validate_u: %s ok\n", keystr));
2930 static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2931 struct tdb_validation_status *state)
2933 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2939 (void)centry_nttime(centry);
2940 (void)centry_nttime(centry);
2941 (void)centry_uint16(centry);
2943 centry_free(centry);
2945 if (!(state->success)) {
2948 DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
2952 static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2953 struct tdb_validation_status *state)
2955 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2961 (void)centry_uint16(centry);
2962 (void)centry_uint16(centry);
2963 (void)centry_uint32(centry);
2964 (void)centry_nttime(centry);
2965 (void)centry_nttime(centry);
2967 centry_free(centry);
2969 if (!(state->success)) {
2972 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
2976 static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2977 struct tdb_validation_status *state)
2979 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2985 (void)centry_time(centry);
2986 (void)centry_hash16(centry, mem_ctx);
2988 /* We only have 17 bytes more data in the salted cred case. */
2989 if (centry->len - centry->ofs == 17) {
2990 (void)centry_hash16(centry, mem_ctx);
2993 centry_free(centry);
2995 if (!(state->success)) {
2998 DEBUG(10,("validate_cred: %s ok\n", keystr));
3002 static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3003 struct tdb_validation_status *state)
3005 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3006 int32 num_entries, i;
3012 num_entries = (int32)centry_uint32(centry);
3014 for (i=0; i< num_entries; i++) {
3016 (void)centry_string(centry, mem_ctx);
3017 (void)centry_string(centry, mem_ctx);
3018 (void)centry_string(centry, mem_ctx);
3019 (void)centry_string(centry, mem_ctx);
3020 (void)centry_sid(centry, mem_ctx, &sid);
3021 (void)centry_sid(centry, mem_ctx, &sid);
3024 centry_free(centry);
3026 if (!(state->success)) {
3029 DEBUG(10,("validate_ul: %s ok\n", keystr));
3033 static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3034 struct tdb_validation_status *state)
3036 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3037 int32 num_entries, i;
3043 num_entries = centry_uint32(centry);
3045 for (i=0; i< num_entries; i++) {
3046 (void)centry_string(centry, mem_ctx);
3047 (void)centry_string(centry, mem_ctx);
3048 (void)centry_uint32(centry);
3051 centry_free(centry);
3053 if (!(state->success)) {
3056 DEBUG(10,("validate_gl: %s ok\n", keystr));
3060 static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3061 struct tdb_validation_status *state)
3063 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3064 int32 num_groups, i;
3070 num_groups = centry_uint32(centry);
3072 for (i=0; i< num_groups; i++) {
3074 centry_sid(centry, mem_ctx, &sid);
3077 centry_free(centry);
3079 if (!(state->success)) {
3082 DEBUG(10,("validate_ug: %s ok\n", keystr));
3086 static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3087 struct tdb_validation_status *state)
3089 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3090 int32 num_aliases, i;
3096 num_aliases = centry_uint32(centry);
3098 for (i=0; i < num_aliases; i++) {
3099 (void)centry_uint32(centry);
3102 centry_free(centry);
3104 if (!(state->success)) {
3107 DEBUG(10,("validate_ua: %s ok\n", keystr));
3111 static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3112 struct tdb_validation_status *state)
3114 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3121 num_names = centry_uint32(centry);
3123 for (i=0; i< num_names; i++) {
3125 centry_sid(centry, mem_ctx, &sid);
3126 (void)centry_string(centry, mem_ctx);
3127 (void)centry_uint32(centry);
3130 centry_free(centry);
3132 if (!(state->success)) {
3135 DEBUG(10,("validate_gm: %s ok\n", keystr));
3139 static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3140 struct tdb_validation_status *state)
3142 /* Can't say anything about this other than must be nonzero. */
3143 if (dbuf.dsize == 0) {
3144 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3146 state->bad_entry = True;
3147 state->success = False;
3151 DEBUG(10,("validate_dr: %s ok\n", keystr));
3155 static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3156 struct tdb_validation_status *state)
3158 /* Can't say anything about this other than must be nonzero. */
3159 if (dbuf.dsize == 0) {
3160 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3162 state->bad_entry = True;
3163 state->success = False;
3167 DEBUG(10,("validate_de: %s ok\n", keystr));
3171 static int validate_trustdoms(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3172 struct tdb_validation_status *state)
3174 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3175 int32 num_domains, i;
3181 num_domains = centry_uint32(centry);
3183 for (i=0; i< num_domains; i++) {
3185 (void)centry_string(centry, mem_ctx);
3186 (void)centry_string(centry, mem_ctx);
3187 (void)centry_sid(centry, mem_ctx, &sid);
3190 centry_free(centry);
3192 if (!(state->success)) {
3195 DEBUG(10,("validate_trustdoms: %s ok\n", keystr));
3199 static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
3201 struct tdb_validation_status *state)
3203 if (dbuf.dsize == 0) {
3204 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3205 "key %s (len ==0) ?\n", keystr));
3206 state->bad_entry = True;
3207 state->success = False;
3211 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
3212 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3216 static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3217 struct tdb_validation_status *state)
3219 if (dbuf.dsize != 4) {
3220 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3221 keystr, (unsigned int)dbuf.dsize ));
3222 state->bad_entry = True;
3223 state->success = False;
3226 DEBUG(10,("validate_offline: %s ok\n", keystr));
3230 static int validate_cache_version(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_cache_version: Corrupt cache for "
3235 "key %s (len %u != 4) ?\n",
3236 keystr, (unsigned int)dbuf.dsize));
3237 state->bad_entry = True;
3238 state->success = False;
3242 DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
3246 /***********************************************************************
3247 A list of all possible cache tdb keys with associated validation
3249 ***********************************************************************/
3251 struct key_val_struct {
3252 const char *keyname;
3253 int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
3255 {"SEQNUM/", validate_seqnum},
3256 {"NS/", validate_ns},
3257 {"SN/", validate_sn},
3259 {"LOC_POL/", validate_loc_pol},
3260 {"PWD_POL/", validate_pwd_pol},
3261 {"CRED/", validate_cred},
3262 {"UL/", validate_ul},
3263 {"GL/", validate_gl},
3264 {"UG/", validate_ug},
3265 {"UA", validate_ua},
3266 {"GM/", validate_gm},
3267 {"DR/", validate_dr},
3268 {"DE/", validate_de},
3269 {"TRUSTDOMS/", validate_trustdoms},
3270 {"TRUSTDOMCACHE/", validate_trustdomcache},
3271 {"WINBINDD_OFFLINE", validate_offline},
3272 {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
3276 /***********************************************************************
3277 Function to look at every entry in the tdb and validate it as far as
3279 ***********************************************************************/
3281 static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
3284 struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
3286 /* Paranoia check. */
3287 if (kbuf.dsize > 1024) {
3288 DEBUG(0,("cache_traverse_validate_fn: key length too large (%u) > 1024\n\n",
3289 (unsigned int)kbuf.dsize ));
3293 for (i = 0; key_val[i].keyname; i++) {
3294 size_t namelen = strlen(key_val[i].keyname);
3295 if (kbuf.dsize >= namelen && (
3296 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
3297 TALLOC_CTX *mem_ctx;
3301 keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
3305 memcpy(keystr, kbuf.dptr, kbuf.dsize);
3306 keystr[kbuf.dsize] = '\0';
3308 mem_ctx = talloc_init("validate_ctx");
3314 ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
3318 talloc_destroy(mem_ctx);
3323 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
3324 dump_data(0, (uint8 *)kbuf.dptr, kbuf.dsize);
3325 DEBUG(0,("data :\n"));
3326 dump_data(0, (uint8 *)dbuf.dptr, dbuf.dsize);
3327 v_state->unknown_key = True;
3328 v_state->success = False;
3329 return 1; /* terminate. */
3332 static void validate_panic(const char *const why)
3334 DEBUG(0,("validating cache: would panic %s\n", why ));
3335 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
3339 /***********************************************************************
3340 Try and validate every entry in the winbindd cache. If we fail here,
3341 delete the cache tdb and return non-zero - the caller (main winbindd
3342 function) will restart us as we don't know if we crashed or not.
3343 ***********************************************************************/
3345 int winbindd_validate_cache(void)
3348 const char *tdb_path = lock_path("winbindd_cache.tdb");
3349 TDB_CONTEXT *tdb = NULL;
3351 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3352 smb_panic_fn = validate_panic;
3355 tdb = tdb_open_log(tdb_path,
3356 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3357 ( lp_winbind_offline_logon()
3359 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
3363 DEBUG(0, ("winbindd_validate_cache: "
3364 "error opening/initializing tdb\n"));
3369 ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
3372 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
3373 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
3378 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
3379 smb_panic_fn = smb_panic;
3383 /***********************************************************************
3384 Try and validate every entry in the winbindd cache.
3385 ***********************************************************************/
3387 int winbindd_validate_cache_nobackup(void)
3390 const char *tdb_path = lock_path("winbindd_cache.tdb");
3392 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3393 smb_panic_fn = validate_panic;
3396 if (wcache == NULL || wcache->tdb == NULL) {
3397 ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
3399 ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
3403 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
3407 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
3409 smb_panic_fn = smb_panic;
3413 /*********************************************************************
3414 ********************************************************************/
3416 static BOOL add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
3417 struct winbindd_tdc_domain **domains,
3418 size_t *num_domains )
3420 struct winbindd_tdc_domain *list = NULL;
3423 BOOL set_only = False;
3425 /* don't allow duplicates */
3430 for ( i=0; i< (*num_domains); i++ ) {
3431 if ( strequal( new_dom->name, list[i].domain_name ) ) {
3432 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
3443 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, 1 );
3446 list = TALLOC_REALLOC_ARRAY( *domains, *domains,
3447 struct winbindd_tdc_domain,
3452 ZERO_STRUCT( list[idx] );
3458 list[idx].domain_name = talloc_strdup( list, new_dom->name );
3459 list[idx].dns_name = talloc_strdup( list, new_dom->alt_name );
3461 if ( !is_null_sid( &new_dom->sid ) )
3462 sid_copy( &list[idx].sid, &new_dom->sid );
3464 if ( new_dom->domain_flags != 0x0 )
3465 list[idx].trust_flags = new_dom->domain_flags;
3467 if ( new_dom->domain_type != 0x0 )
3468 list[idx].trust_type = new_dom->domain_type;
3470 if ( new_dom->domain_trust_attribs != 0x0 )
3471 list[idx].trust_attribs = new_dom->domain_trust_attribs;
3475 *num_domains = idx + 1;
3481 /*********************************************************************
3482 ********************************************************************/
3484 static TDB_DATA make_tdc_key( const char *domain_name )
3486 char *keystr = NULL;
3487 TDB_DATA key = { NULL, 0 };
3489 if ( !domain_name ) {
3490 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
3495 asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name );
3496 key = string_term_tdb_data(keystr);
3501 /*********************************************************************
3502 ********************************************************************/
3504 static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
3506 unsigned char **buf )
3508 unsigned char *buffer = NULL;
3513 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
3521 /* Store the number of array items first */
3522 len += tdb_pack( buffer+len, buflen-len, "d",
3525 /* now pack each domain trust record */
3526 for ( i=0; i<num_domains; i++ ) {
3529 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
3530 domains[i].domain_name,
3531 domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
3534 len += tdb_pack( buffer+len, buflen-len, "fffddd",
3535 domains[i].domain_name,
3536 domains[i].dns_name,
3537 sid_string_static(&domains[i].sid),
3538 domains[i].trust_flags,
3539 domains[i].trust_attribs,
3540 domains[i].trust_type );
3543 if ( buflen < len ) {
3545 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
3546 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
3560 /*********************************************************************
3561 ********************************************************************/
3563 static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
3564 struct winbindd_tdc_domain **domains )
3566 fstring domain_name, dns_name, sid_string;
3567 uint32 type, attribs, flags;
3571 struct winbindd_tdc_domain *list = NULL;
3573 /* get the number of domains */
3574 len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
3576 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3580 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, num_domains );
3582 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
3586 for ( i=0; i<num_domains; i++ ) {
3587 len += tdb_unpack( buf+len, buflen-len, "fffddd",
3596 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3597 TALLOC_FREE( list );
3601 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
3602 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
3603 domain_name, dns_name, sid_string,
3604 flags, attribs, type));
3606 list[i].domain_name = talloc_strdup( list, domain_name );
3607 list[i].dns_name = talloc_strdup( list, dns_name );
3608 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
3609 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
3612 list[i].trust_flags = flags;
3613 list[i].trust_attribs = attribs;
3614 list[i].trust_type = type;
3622 /*********************************************************************
3623 ********************************************************************/
3625 static BOOL wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
3627 TDB_DATA key = make_tdc_key( lp_workgroup() );
3628 TDB_DATA data = { NULL, 0 };
3634 /* See if we were asked to delete the cache entry */
3637 ret = tdb_delete( wcache->tdb, key );
3641 data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
3648 ret = tdb_store( wcache->tdb, key, data, 0 );
3651 SAFE_FREE( data.dptr );
3652 SAFE_FREE( key.dptr );
3654 return ( ret != -1 );
3657 /*********************************************************************
3658 ********************************************************************/
3660 BOOL wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
3662 TDB_DATA key = make_tdc_key( lp_workgroup() );
3663 TDB_DATA data = { NULL, 0 };
3671 data = tdb_fetch( wcache->tdb, key );
3673 SAFE_FREE( key.dptr );
3678 *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
3680 SAFE_FREE( data.dptr );
3688 /*********************************************************************
3689 ********************************************************************/
3691 BOOL wcache_tdc_add_domain( struct winbindd_domain *domain )
3693 struct winbindd_tdc_domain *dom_list = NULL;
3694 size_t num_domains = 0;
3697 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
3698 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
3699 domain->name, domain->alt_name,
3700 sid_string_static(&domain->sid),
3701 domain->domain_flags,
3702 domain->domain_trust_attribs,
3703 domain->domain_type));
3705 if ( !init_wcache() ) {
3709 /* fetch the list */
3711 wcache_tdc_fetch_list( &dom_list, &num_domains );
3713 /* add the new domain */
3715 if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
3719 /* pack the domain */
3721 if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
3729 TALLOC_FREE( dom_list );
3734 /*********************************************************************
3735 ********************************************************************/
3737 struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
3739 struct winbindd_tdc_domain *dom_list = NULL;
3740 size_t num_domains = 0;
3742 struct winbindd_tdc_domain *d = NULL;
3744 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
3746 if ( !init_wcache() ) {
3750 /* fetch the list */
3752 wcache_tdc_fetch_list( &dom_list, &num_domains );
3754 for ( i=0; i<num_domains; i++ ) {
3755 if ( strequal(name, dom_list[i].domain_name) ||
3756 strequal(name, dom_list[i].dns_name) )
3758 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
3761 d = TALLOC_P( ctx, struct winbindd_tdc_domain );
3765 d->domain_name = talloc_strdup( d, dom_list[i].domain_name );
3766 d->dns_name = talloc_strdup( d, dom_list[i].dns_name );
3767 sid_copy( &d->sid, &dom_list[i].sid );
3768 d->trust_flags = dom_list[i].trust_flags;
3769 d->trust_type = dom_list[i].trust_type;
3770 d->trust_attribs = dom_list[i].trust_attribs;
3776 TALLOC_FREE( dom_list );
3782 /*********************************************************************
3783 ********************************************************************/
3785 void wcache_tdc_clear( void )
3787 if ( !init_wcache() )
3790 wcache_tdc_store_list( NULL, 0 );
3796 /*********************************************************************
3797 ********************************************************************/
3799 static void wcache_save_user_pwinfo(struct winbindd_domain *domain,
3801 const DOM_SID *user_sid,
3802 const char *homedir,
3807 struct cache_entry *centry;
3809 if ( (centry = centry_start(domain, status)) == NULL )
3812 centry_put_string( centry, homedir );
3813 centry_put_string( centry, shell );
3814 centry_put_string( centry, gecos );
3815 centry_put_uint32( centry, gid );
3817 centry_end(centry, "NSS/PWINFO/%s", sid_string_static(user_sid) );
3819 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_static(user_sid) ));
3821 centry_free(centry);
3824 NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
3825 const DOM_SID *user_sid,
3827 ADS_STRUCT *ads, LDAPMessage *msg,
3828 char **homedir, char **shell, char **gecos,
3831 struct winbind_cache *cache = get_cache(domain);
3832 struct cache_entry *centry = NULL;
3838 centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s", sid_string_static(user_sid));
3843 *homedir = centry_string( centry, ctx );
3844 *shell = centry_string( centry, ctx );
3845 *gecos = centry_string( centry, ctx );
3846 *p_gid = centry_uint32( centry );
3848 centry_free(centry);
3850 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
3851 sid_string_static(user_sid)));
3853 return NT_STATUS_OK;
3857 nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg,
3858 homedir, shell, gecos, p_gid );
3860 if ( NT_STATUS_IS_OK(nt_status) ) {
3861 wcache_save_user_pwinfo( domain, nt_status, user_sid,
3862 *homedir, *shell, *gecos, *p_gid );
3865 if ( NT_STATUS_EQUAL( nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
3866 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
3868 set_domain_offline( domain );
3875 /* the cache backend methods are exposed via this structure */
3876 struct winbindd_methods cache_methods = {