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 2 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, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 #define DBGC_CLASS DBGC_WINBIND
33 #define WINBINDD_CACHE_VERSION 1
34 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
36 extern struct winbindd_methods reconnect_methods;
37 extern BOOL opt_nocache;
39 extern struct winbindd_methods ads_methods;
43 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
44 * Here are the list of entry types that are *not* stored
45 * as form struct cache_entry in the cache.
48 static const char *non_centry_keys[] = {
53 WINBINDD_CACHE_VERSION_KEYSTR,
57 /************************************************************************
58 Is this key a non-centry type ?
59 ************************************************************************/
61 static BOOL is_non_centry_key(TDB_DATA kbuf)
65 if (kbuf.dptr == NULL || kbuf.dsize == 0) {
68 for (i = 0; non_centry_keys[i] != NULL; i++) {
69 size_t namelen = strlen(non_centry_keys[i]);
70 if (kbuf.dsize < namelen) {
73 if (strncmp(non_centry_keys[i], (const char *)kbuf.dptr, namelen) == 0) {
80 /* Global online/offline state - False when online. winbindd starts up online
81 and sets this to true if the first query fails and there's an entry in
82 the cache tdb telling us to stay offline. */
84 static BOOL global_winbindd_offline_state;
86 struct winbind_cache {
92 uint32 sequence_number;
97 void (*smb_panic_fn)(const char *const why) = smb_panic;
99 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
101 static struct winbind_cache *wcache;
103 void winbindd_check_cache_size(time_t t)
105 static time_t last_check_time;
108 if (last_check_time == (time_t)0)
111 if (t - last_check_time < 60 && t - last_check_time > 0)
114 if (wcache == NULL || wcache->tdb == NULL) {
115 DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
119 if (fstat(tdb_fd(wcache->tdb), &st) == -1) {
120 DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno) ));
124 if (st.st_size > WINBINDD_MAX_CACHE_SIZE) {
125 DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
126 (unsigned long)st.st_size,
127 (unsigned long)WINBINDD_MAX_CACHE_SIZE));
128 wcache_flush_cache();
132 /* get the winbind_cache structure */
133 static struct winbind_cache *get_cache(struct winbindd_domain *domain)
135 struct winbind_cache *ret = wcache;
137 struct winbindd_domain *our_domain = domain;
140 /* We have to know what type of domain we are dealing with first. */
142 if ( !domain->initialized ) {
143 init_dc_connection( domain );
147 OK. listen up becasue I'm only going to say this once.
148 We have the following scenarios to consider
149 (a) trusted AD domains on a Samba DC,
150 (b) trusted AD domains and we are joined to a non-kerberos domain
151 (c) trusted AD domains and we are joined to a kerberos (AD) domain
153 For (a) we can always contact the trusted domain using krb5
154 since we have the domain trust account password
156 For (b) we can only use RPC since we have no way of
157 getting a krb5 ticket in our own domain
159 For (c) we can always use krb5 since we have a kerberos trust
164 if (!domain->backend) {
166 /* find our domain first so we can figure out if we
167 are joined to a kerberized domain */
169 if ( !domain->primary )
170 our_domain = find_our_domain();
172 if ( (our_domain->active_directory || IS_DC) && domain->active_directory ) {
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");
229 ret = IVAL(centry->data, centry->ofs);
235 pull a uint16 from a cache entry
237 static uint16 centry_uint16(struct cache_entry *centry)
240 if (!centry_check_bytes(centry, 2)) {
241 smb_panic_fn("centry_uint16");
244 ret = CVAL(centry->data, centry->ofs);
250 pull a uint8 from a cache entry
252 static uint8 centry_uint8(struct cache_entry *centry)
255 if (!centry_check_bytes(centry, 1)) {
256 smb_panic_fn("centry_uint8");
259 ret = CVAL(centry->data, centry->ofs);
265 pull a NTTIME from a cache entry
267 static NTTIME centry_nttime(struct cache_entry *centry)
270 if (!centry_check_bytes(centry, 8)) {
271 smb_panic_fn("centry_nttime");
274 ret = IVAL(centry->data, centry->ofs);
276 ret += (uint64_t)IVAL(centry->data, centry->ofs) << 32;
282 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
284 static time_t centry_time(struct cache_entry *centry)
286 return (time_t)centry_nttime(centry);
289 /* pull a string from a cache entry, using the supplied
292 static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
297 len = centry_uint8(centry);
300 /* a deliberate NULL string */
304 if (!centry_check_bytes(centry, (size_t)len)) {
305 smb_panic_fn("centry_string");
309 ret = TALLOC_ARRAY(mem_ctx, char, len+1);
311 smb_panic_fn("centry_string out of memory\n");
314 memcpy(ret,centry->data + centry->ofs, len);
320 /* pull a hash16 from a cache entry, using the supplied
323 static char *centry_hash16(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
328 len = centry_uint8(centry);
331 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
336 if (!centry_check_bytes(centry, 16)) {
340 ret = TALLOC_ARRAY(mem_ctx, char, 16);
342 smb_panic_fn("centry_hash out of memory\n");
345 memcpy(ret,centry->data + centry->ofs, 16);
350 /* pull a sid from a cache entry, using the supplied
353 static BOOL centry_sid(struct cache_entry *centry, TALLOC_CTX *mem_ctx, DOM_SID *sid)
356 sid_string = centry_string(centry, mem_ctx);
357 if ((sid_string == NULL) || (!string_to_sid(sid, sid_string))) {
363 /* the server is considered down if it can't give us a sequence number */
364 static BOOL wcache_server_down(struct winbindd_domain *domain)
371 ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
374 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
379 static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
386 DEBUG(10,("fetch_cache_seqnum: tdb == NULL\n"));
387 return NT_STATUS_UNSUCCESSFUL;
390 fstr_sprintf( key, "SEQNUM/%s", domain->name );
392 data = tdb_fetch_bystring( wcache->tdb, key );
393 if ( !data.dptr || data.dsize!=8 ) {
394 DEBUG(10,("fetch_cache_seqnum: invalid data size key [%s]\n", key ));
395 return NT_STATUS_UNSUCCESSFUL;
398 domain->sequence_number = IVAL(data.dptr, 0);
399 domain->last_seq_check = IVAL(data.dptr, 4);
401 SAFE_FREE(data.dptr);
403 /* have we expired? */
405 time_diff = now - domain->last_seq_check;
406 if ( time_diff > lp_winbind_cache_time() ) {
407 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
408 domain->name, domain->sequence_number,
409 (uint32)domain->last_seq_check));
410 return NT_STATUS_UNSUCCESSFUL;
413 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
414 domain->name, domain->sequence_number,
415 (uint32)domain->last_seq_check));
420 static NTSTATUS store_cache_seqnum( struct winbindd_domain *domain )
427 DEBUG(10,("store_cache_seqnum: tdb == NULL\n"));
428 return NT_STATUS_UNSUCCESSFUL;
431 fstr_sprintf( key_str, "SEQNUM/%s", domain->name );
433 SIVAL(buf, 0, domain->sequence_number);
434 SIVAL(buf, 4, domain->last_seq_check);
438 if ( tdb_store_bystring( wcache->tdb, key_str, data, TDB_REPLACE) == -1 ) {
439 DEBUG(10,("store_cache_seqnum: tdb_store fail key [%s]\n", key_str ));
440 return NT_STATUS_UNSUCCESSFUL;
443 DEBUG(10,("store_cache_seqnum: success [%s][%u @ %u]\n",
444 domain->name, domain->sequence_number,
445 (uint32)domain->last_seq_check));
451 refresh the domain sequence number. If force is True
452 then always refresh it, no matter how recently we fetched it
455 static void refresh_sequence_number(struct winbindd_domain *domain, BOOL force)
459 time_t t = time(NULL);
460 unsigned cache_time = lp_winbind_cache_time();
462 if ( IS_DOMAIN_OFFLINE(domain) ) {
468 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
469 /* trying to reconnect is expensive, don't do it too often */
470 if (domain->sequence_number == DOM_SEQUENCE_NONE) {
475 time_diff = t - domain->last_seq_check;
477 /* see if we have to refetch the domain sequence number */
478 if (!force && (time_diff < cache_time)) {
479 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
483 /* try to get the sequence number from the tdb cache first */
484 /* this will update the timestamp as well */
486 status = fetch_cache_seqnum( domain, t );
487 if ( NT_STATUS_IS_OK(status) )
490 /* important! make sure that we know if this is a native
491 mode domain or not. And that we can contact it. */
493 if ( winbindd_can_contact_domain( domain ) ) {
494 status = domain->backend->sequence_number(domain,
495 &domain->sequence_number);
497 /* just use the current time */
498 status = NT_STATUS_OK;
499 domain->sequence_number = time(NULL);
503 /* the above call could have set our domain->backend to NULL when
504 * coming from offline to online mode, make sure to reinitialize the
505 * backend - Guenther */
508 if (!NT_STATUS_IS_OK(status)) {
509 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status)));
510 domain->sequence_number = DOM_SEQUENCE_NONE;
513 domain->last_status = status;
514 domain->last_seq_check = time(NULL);
516 /* save the new sequence number ni the cache */
517 store_cache_seqnum( domain );
520 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
521 domain->name, domain->sequence_number));
527 decide if a cache entry has expired
529 static BOOL centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
531 /* If we've been told to be offline - stay in that state... */
532 if (lp_winbind_offline_logon() && global_winbindd_offline_state) {
533 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
534 keystr, domain->name ));
538 /* when the domain is offline return the cached entry.
539 * This deals with transient offline states... */
541 if (!domain->online) {
542 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
543 keystr, domain->name ));
547 /* if the server is OK and our cache entry came from when it was down then
548 the entry is invalid */
549 if ((domain->sequence_number != DOM_SEQUENCE_NONE) &&
550 (centry->sequence_number == DOM_SEQUENCE_NONE)) {
551 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
552 keystr, domain->name ));
556 /* if the server is down or the cache entry is not older than the
557 current sequence number then it is OK */
558 if (wcache_server_down(domain) ||
559 centry->sequence_number == domain->sequence_number) {
560 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
561 keystr, domain->name ));
565 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
566 keystr, domain->name ));
572 static struct cache_entry *wcache_fetch_raw(char *kstr)
575 struct cache_entry *centry;
578 key = string_tdb_data(kstr);
579 data = tdb_fetch(wcache->tdb, key);
585 centry = SMB_XMALLOC_P(struct cache_entry);
586 centry->data = (unsigned char *)data.dptr;
587 centry->len = data.dsize;
590 if (centry->len < 8) {
591 /* huh? corrupt cache? */
592 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr));
597 centry->status = NT_STATUS(centry_uint32(centry));
598 centry->sequence_number = centry_uint32(centry);
604 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
605 number and return status
607 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
608 struct winbindd_domain *domain,
609 const char *format, ...) PRINTF_ATTRIBUTE(3,4);
610 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
611 struct winbindd_domain *domain,
612 const char *format, ...)
616 struct cache_entry *centry;
622 refresh_sequence_number(domain, False);
624 va_start(ap, format);
625 smb_xvasprintf(&kstr, format, ap);
628 centry = wcache_fetch_raw(kstr);
629 if (centry == NULL) {
634 if (centry_expired(domain, kstr, centry)) {
636 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
637 kstr, domain->name ));
644 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
645 kstr, domain->name ));
651 static void wcache_delete(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
652 static void wcache_delete(const char *format, ...)
658 va_start(ap, format);
659 smb_xvasprintf(&kstr, format, ap);
662 key = string_tdb_data(kstr);
664 tdb_delete(wcache->tdb, key);
669 make sure we have at least len bytes available in a centry
671 static void centry_expand(struct cache_entry *centry, uint32 len)
673 if (centry->len - centry->ofs >= len)
676 centry->data = SMB_REALLOC_ARRAY(centry->data, unsigned char,
679 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
680 smb_panic_fn("out of memory in centry_expand");
685 push a uint32 into a centry
687 static void centry_put_uint32(struct cache_entry *centry, uint32 v)
689 centry_expand(centry, 4);
690 SIVAL(centry->data, centry->ofs, v);
695 push a uint16 into a centry
697 static void centry_put_uint16(struct cache_entry *centry, uint16 v)
699 centry_expand(centry, 2);
700 SIVAL(centry->data, centry->ofs, v);
705 push a uint8 into a centry
707 static void centry_put_uint8(struct cache_entry *centry, uint8 v)
709 centry_expand(centry, 1);
710 SCVAL(centry->data, centry->ofs, v);
715 push a string into a centry
717 static void centry_put_string(struct cache_entry *centry, const char *s)
722 /* null strings are marked as len 0xFFFF */
723 centry_put_uint8(centry, 0xFF);
728 /* can't handle more than 254 char strings. Truncating is probably best */
730 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len));
733 centry_put_uint8(centry, len);
734 centry_expand(centry, len);
735 memcpy(centry->data + centry->ofs, s, len);
740 push a 16 byte hash into a centry - treat as 16 byte string.
742 static void centry_put_hash16(struct cache_entry *centry, const uint8 val[16])
744 centry_put_uint8(centry, 16);
745 centry_expand(centry, 16);
746 memcpy(centry->data + centry->ofs, val, 16);
750 static void centry_put_sid(struct cache_entry *centry, const DOM_SID *sid)
753 centry_put_string(centry, sid_to_string(sid_string, sid));
757 push a NTTIME into a centry
759 static void centry_put_nttime(struct cache_entry *centry, NTTIME nt)
761 centry_expand(centry, 8);
762 SIVAL(centry->data, centry->ofs, nt & 0xFFFFFFFF);
764 SIVAL(centry->data, centry->ofs, nt >> 32);
769 push a time_t into a centry - use a 64 bit size.
770 NTTIME here is being used as a convenient 64-bit size.
772 static void centry_put_time(struct cache_entry *centry, time_t t)
774 NTTIME nt = (NTTIME)t;
775 centry_put_nttime(centry, nt);
779 start a centry for output. When finished, call centry_end()
781 struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status)
783 struct cache_entry *centry;
788 centry = SMB_XMALLOC_P(struct cache_entry);
790 centry->len = 8192; /* reasonable default */
791 centry->data = SMB_XMALLOC_ARRAY(uint8, centry->len);
793 centry->sequence_number = domain->sequence_number;
794 centry_put_uint32(centry, NT_STATUS_V(status));
795 centry_put_uint32(centry, centry->sequence_number);
800 finish a centry and write it to the tdb
802 static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
803 static void centry_end(struct cache_entry *centry, const char *format, ...)
809 va_start(ap, format);
810 smb_xvasprintf(&kstr, format, ap);
813 key = string_tdb_data(kstr);
814 data.dptr = centry->data;
815 data.dsize = centry->ofs;
817 tdb_store(wcache->tdb, key, data, TDB_REPLACE);
821 static void wcache_save_name_to_sid(struct winbindd_domain *domain,
822 NTSTATUS status, const char *domain_name,
823 const char *name, const DOM_SID *sid,
824 enum lsa_SidType type)
826 struct cache_entry *centry;
829 centry = centry_start(domain, status);
832 centry_put_uint32(centry, type);
833 centry_put_sid(centry, sid);
834 fstrcpy(uname, name);
836 centry_end(centry, "NS/%s/%s", domain_name, uname);
837 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name, uname,
838 sid_string_static(sid), nt_errstr(status)));
842 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
843 const DOM_SID *sid, const char *domain_name, const char *name, enum lsa_SidType type)
845 struct cache_entry *centry;
848 if (is_null_sid(sid)) {
852 centry = centry_start(domain, status);
855 if (NT_STATUS_IS_OK(status)) {
856 centry_put_uint32(centry, type);
857 centry_put_string(centry, domain_name);
858 centry_put_string(centry, name);
860 centry_end(centry, "SN/%s", sid_to_string(sid_string, sid));
861 DEBUG(10,("wcache_save_sid_to_name: %s -> %s (%s)\n", sid_string,
862 name, nt_errstr(status)));
867 static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status, WINBIND_USERINFO *info)
869 struct cache_entry *centry;
872 if (is_null_sid(&info->user_sid)) {
876 centry = centry_start(domain, status);
879 centry_put_string(centry, info->acct_name);
880 centry_put_string(centry, info->full_name);
881 centry_put_string(centry, info->homedir);
882 centry_put_string(centry, info->shell);
883 centry_put_uint32(centry, info->primary_gid);
884 centry_put_sid(centry, &info->user_sid);
885 centry_put_sid(centry, &info->group_sid);
886 centry_end(centry, "U/%s", sid_to_string(sid_string, &info->user_sid));
887 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
891 static void wcache_save_lockout_policy(struct winbindd_domain *domain, NTSTATUS status, SAM_UNK_INFO_12 *lockout_policy)
893 struct cache_entry *centry;
895 centry = centry_start(domain, status);
899 centry_put_nttime(centry, lockout_policy->duration);
900 centry_put_nttime(centry, lockout_policy->reset_count);
901 centry_put_uint16(centry, lockout_policy->bad_attempt_lockout);
903 centry_end(centry, "LOC_POL/%s", domain->name);
905 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
910 static void wcache_save_password_policy(struct winbindd_domain *domain, NTSTATUS status, SAM_UNK_INFO_1 *policy)
912 struct cache_entry *centry;
914 centry = centry_start(domain, status);
918 centry_put_uint16(centry, policy->min_length_password);
919 centry_put_uint16(centry, policy->password_history);
920 centry_put_uint32(centry, policy->password_properties);
921 centry_put_nttime(centry, policy->expire);
922 centry_put_nttime(centry, policy->min_passwordage);
924 centry_end(centry, "PWD_POL/%s", domain->name);
926 DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
931 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const DOM_SID *sid)
933 struct winbind_cache *cache = get_cache(domain);
939 return NT_STATUS_INTERNAL_DB_ERROR;
942 if (is_null_sid(sid)) {
943 return NT_STATUS_INVALID_SID;
946 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
947 return NT_STATUS_INVALID_SID;
950 fstr_sprintf(key_str, "CRED/%s", sid_string_static(sid));
952 data = tdb_fetch(cache->tdb, string_tdb_data(key_str));
954 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
957 SAFE_FREE(data.dptr);
961 /* Lookup creds for a SID - copes with old (unsalted) creds as well
962 as new salted ones. */
964 NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
967 const uint8 **cached_nt_pass,
968 const uint8 **cached_salt)
970 struct winbind_cache *cache = get_cache(domain);
971 struct cache_entry *centry = NULL;
977 return NT_STATUS_INTERNAL_DB_ERROR;
980 if (is_null_sid(sid)) {
981 return NT_STATUS_INVALID_SID;
984 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
985 return NT_STATUS_INVALID_SID;
988 /* Try and get a salted cred first. If we can't
989 fall back to an unsalted cred. */
991 centry = wcache_fetch(cache, domain, "CRED/%s", sid_string_static(sid));
993 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
994 sid_string_static(sid)));
995 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
998 t = centry_time(centry);
1000 /* In the salted case this isn't actually the nt_hash itself,
1001 but the MD5 of the salt + nt_hash. Let the caller
1002 sort this out. It can tell as we only return the cached_salt
1003 if we are returning a salted cred. */
1005 *cached_nt_pass = (const uint8 *)centry_hash16(centry, mem_ctx);
1006 if (*cached_nt_pass == NULL) {
1007 const char *sidstr = sid_string_static(sid);
1009 /* Bad (old) cred cache. Delete and pretend we
1011 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1013 wcache_delete("CRED/%s", sidstr);
1014 centry_free(centry);
1015 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1018 /* We only have 17 bytes more data in the salted cred case. */
1019 if (centry->len - centry->ofs == 17) {
1020 *cached_salt = (const uint8 *)centry_hash16(centry, mem_ctx);
1022 *cached_salt = NULL;
1026 dump_data(100, *cached_nt_pass, NT_HASH_LEN);
1028 dump_data(100, *cached_salt, NT_HASH_LEN);
1031 status = centry->status;
1033 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1034 sid_string_static(sid), nt_errstr(status) ));
1036 centry_free(centry);
1040 /* Store creds for a SID - only writes out new salted ones. */
1042 NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
1043 TALLOC_CTX *mem_ctx,
1045 const uint8 nt_pass[NT_HASH_LEN])
1047 struct cache_entry *centry;
1050 uint8 cred_salt[NT_HASH_LEN];
1051 uint8 salted_hash[NT_HASH_LEN];
1053 if (is_null_sid(sid)) {
1054 return NT_STATUS_INVALID_SID;
1057 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1058 return NT_STATUS_INVALID_SID;
1061 centry = centry_start(domain, NT_STATUS_OK);
1063 return NT_STATUS_INTERNAL_DB_ERROR;
1067 dump_data(100, nt_pass, NT_HASH_LEN);
1070 centry_put_time(centry, time(NULL));
1072 /* Create a salt and then salt the hash. */
1073 generate_random_buffer(cred_salt, NT_HASH_LEN);
1074 E_md5hash(cred_salt, nt_pass, salted_hash);
1076 centry_put_hash16(centry, salted_hash);
1077 centry_put_hash16(centry, cred_salt);
1078 centry_end(centry, "CRED/%s", sid_to_string(sid_string, sid));
1080 DEBUG(10,("wcache_save_creds: %s\n", sid_string));
1082 centry_free(centry);
1084 return NT_STATUS_OK;
1088 /* Query display info. This is the basic user list fn */
1089 static NTSTATUS query_user_list(struct winbindd_domain *domain,
1090 TALLOC_CTX *mem_ctx,
1091 uint32 *num_entries,
1092 WINBIND_USERINFO **info)
1094 struct winbind_cache *cache = get_cache(domain);
1095 struct cache_entry *centry = NULL;
1097 unsigned int i, retry;
1102 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1106 *num_entries = centry_uint32(centry);
1108 if (*num_entries == 0)
1111 (*info) = TALLOC_ARRAY(mem_ctx, WINBIND_USERINFO, *num_entries);
1113 smb_panic_fn("query_user_list out of memory");
1114 centry_free(centry);
1115 return NT_STATUS_NO_MEMORY;
1117 for (i=0; i<(*num_entries); i++) {
1118 (*info)[i].acct_name = centry_string(centry, mem_ctx);
1119 (*info)[i].full_name = centry_string(centry, mem_ctx);
1120 (*info)[i].homedir = centry_string(centry, mem_ctx);
1121 (*info)[i].shell = centry_string(centry, mem_ctx);
1122 centry_sid(centry, mem_ctx, &(*info)[i].user_sid);
1123 centry_sid(centry, mem_ctx, &(*info)[i].group_sid);
1127 status = centry->status;
1129 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1130 domain->name, nt_errstr(status) ));
1132 centry_free(centry);
1139 /* Return status value returned by seq number check */
1141 if (!NT_STATUS_IS_OK(domain->last_status))
1142 return domain->last_status;
1144 /* Put the query_user_list() in a retry loop. There appears to be
1145 * some bug either with Windows 2000 or Samba's handling of large
1146 * rpc replies. This manifests itself as sudden disconnection
1147 * at a random point in the enumeration of a large (60k) user list.
1148 * The retry loop simply tries the operation again. )-: It's not
1149 * pretty but an acceptable workaround until we work out what the
1150 * real problem is. */
1155 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1158 status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
1159 if (!NT_STATUS_IS_OK(status))
1160 DEBUG(3, ("query_user_list: returned 0x%08x, "
1161 "retrying\n", NT_STATUS_V(status)));
1162 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1163 DEBUG(3, ("query_user_list: flushing "
1164 "connection cache\n"));
1165 invalidate_cm_connection(&domain->conn);
1168 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
1172 refresh_sequence_number(domain, False);
1173 centry = centry_start(domain, status);
1176 centry_put_uint32(centry, *num_entries);
1177 for (i=0; i<(*num_entries); i++) {
1178 centry_put_string(centry, (*info)[i].acct_name);
1179 centry_put_string(centry, (*info)[i].full_name);
1180 centry_put_string(centry, (*info)[i].homedir);
1181 centry_put_string(centry, (*info)[i].shell);
1182 centry_put_sid(centry, &(*info)[i].user_sid);
1183 centry_put_sid(centry, &(*info)[i].group_sid);
1184 if (domain->backend && domain->backend->consistent) {
1185 /* when the backend is consistent we can pre-prime some mappings */
1186 wcache_save_name_to_sid(domain, NT_STATUS_OK,
1188 (*info)[i].acct_name,
1189 &(*info)[i].user_sid,
1191 wcache_save_sid_to_name(domain, NT_STATUS_OK,
1192 &(*info)[i].user_sid,
1194 (*info)[i].acct_name,
1196 wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
1199 centry_end(centry, "UL/%s", domain->name);
1200 centry_free(centry);
1206 /* list all domain groups */
1207 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
1208 TALLOC_CTX *mem_ctx,
1209 uint32 *num_entries,
1210 struct acct_info **info)
1212 struct winbind_cache *cache = get_cache(domain);
1213 struct cache_entry *centry = NULL;
1220 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1224 *num_entries = centry_uint32(centry);
1226 if (*num_entries == 0)
1229 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1231 smb_panic_fn("enum_dom_groups out of memory");
1232 centry_free(centry);
1233 return NT_STATUS_NO_MEMORY;
1235 for (i=0; i<(*num_entries); i++) {
1236 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1237 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1238 (*info)[i].rid = centry_uint32(centry);
1242 status = centry->status;
1244 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1245 domain->name, nt_errstr(status) ));
1247 centry_free(centry);
1254 /* Return status value returned by seq number check */
1256 if (!NT_STATUS_IS_OK(domain->last_status))
1257 return domain->last_status;
1259 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1262 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1265 refresh_sequence_number(domain, False);
1266 centry = centry_start(domain, status);
1269 centry_put_uint32(centry, *num_entries);
1270 for (i=0; i<(*num_entries); i++) {
1271 centry_put_string(centry, (*info)[i].acct_name);
1272 centry_put_string(centry, (*info)[i].acct_desc);
1273 centry_put_uint32(centry, (*info)[i].rid);
1275 centry_end(centry, "GL/%s/domain", domain->name);
1276 centry_free(centry);
1282 /* list all domain groups */
1283 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
1284 TALLOC_CTX *mem_ctx,
1285 uint32 *num_entries,
1286 struct acct_info **info)
1288 struct winbind_cache *cache = get_cache(domain);
1289 struct cache_entry *centry = NULL;
1296 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1300 *num_entries = centry_uint32(centry);
1302 if (*num_entries == 0)
1305 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1307 smb_panic_fn("enum_dom_groups out of memory");
1308 centry_free(centry);
1309 return NT_STATUS_NO_MEMORY;
1311 for (i=0; i<(*num_entries); i++) {
1312 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1313 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1314 (*info)[i].rid = centry_uint32(centry);
1319 /* If we are returning cached data and the domain controller
1320 is down then we don't know whether the data is up to date
1321 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1324 if (wcache_server_down(domain)) {
1325 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1326 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1328 status = centry->status;
1330 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1331 domain->name, nt_errstr(status) ));
1333 centry_free(centry);
1340 /* Return status value returned by seq number check */
1342 if (!NT_STATUS_IS_OK(domain->last_status))
1343 return domain->last_status;
1345 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1348 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1351 refresh_sequence_number(domain, False);
1352 centry = centry_start(domain, status);
1355 centry_put_uint32(centry, *num_entries);
1356 for (i=0; i<(*num_entries); i++) {
1357 centry_put_string(centry, (*info)[i].acct_name);
1358 centry_put_string(centry, (*info)[i].acct_desc);
1359 centry_put_uint32(centry, (*info)[i].rid);
1361 centry_end(centry, "GL/%s/local", domain->name);
1362 centry_free(centry);
1368 /* convert a single name to a sid in a domain */
1369 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
1370 TALLOC_CTX *mem_ctx,
1371 const char *domain_name,
1374 enum lsa_SidType *type)
1376 struct winbind_cache *cache = get_cache(domain);
1377 struct cache_entry *centry = NULL;
1384 fstrcpy(uname, name);
1386 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1389 *type = (enum lsa_SidType)centry_uint32(centry);
1390 status = centry->status;
1391 if (NT_STATUS_IS_OK(status)) {
1392 centry_sid(centry, mem_ctx, sid);
1395 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: %s\n",
1396 domain->name, nt_errstr(status) ));
1398 centry_free(centry);
1404 /* If the seq number check indicated that there is a problem
1405 * with this DC, then return that status... except for
1406 * access_denied. This is special because the dc may be in
1407 * "restrict anonymous = 1" mode, in which case it will deny
1408 * most unauthenticated operations, but *will* allow the LSA
1409 * name-to-sid that we try as a fallback. */
1411 if (!(NT_STATUS_IS_OK(domain->last_status)
1412 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1413 return domain->last_status;
1415 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1418 status = domain->backend->name_to_sid(domain, mem_ctx, domain_name, name, sid, type);
1421 refresh_sequence_number(domain, False);
1423 if (domain->online && !is_null_sid(sid)) {
1424 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1427 if (NT_STATUS_IS_OK(status)) {
1428 strupper_m(CONST_DISCARD(char *,domain_name));
1429 strlower_m(CONST_DISCARD(char *,name));
1430 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1436 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1438 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
1439 TALLOC_CTX *mem_ctx,
1443 enum lsa_SidType *type)
1445 struct winbind_cache *cache = get_cache(domain);
1446 struct cache_entry *centry = NULL;
1453 centry = wcache_fetch(cache, domain, "SN/%s", sid_to_string(sid_string, sid));
1456 if (NT_STATUS_IS_OK(centry->status)) {
1457 *type = (enum lsa_SidType)centry_uint32(centry);
1458 *domain_name = centry_string(centry, mem_ctx);
1459 *name = centry_string(centry, mem_ctx);
1461 status = centry->status;
1463 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: %s\n",
1464 domain->name, nt_errstr(status) ));
1466 centry_free(centry);
1471 *domain_name = NULL;
1473 /* If the seq number check indicated that there is a problem
1474 * with this DC, then return that status... except for
1475 * access_denied. This is special because the dc may be in
1476 * "restrict anonymous = 1" mode, in which case it will deny
1477 * most unauthenticated operations, but *will* allow the LSA
1478 * sid-to-name that we try as a fallback. */
1480 if (!(NT_STATUS_IS_OK(domain->last_status)
1481 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1482 return domain->last_status;
1484 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1487 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1490 refresh_sequence_number(domain, False);
1491 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1493 /* We can't save the name to sid mapping here, as with sid history a
1494 * later name2sid would give the wrong sid. */
1499 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
1500 TALLOC_CTX *mem_ctx,
1501 const DOM_SID *domain_sid,
1506 enum lsa_SidType **types)
1508 struct winbind_cache *cache = get_cache(domain);
1510 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1514 *domain_name = NULL;
1522 if (num_rids == 0) {
1523 return NT_STATUS_OK;
1526 *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
1527 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
1529 if ((*names == NULL) || (*types == NULL)) {
1530 result = NT_STATUS_NO_MEMORY;
1534 have_mapped = have_unmapped = False;
1536 for (i=0; i<num_rids; i++) {
1538 struct cache_entry *centry;
1540 if (!sid_compose(&sid, domain_sid, rids[i])) {
1541 result = NT_STATUS_INTERNAL_ERROR;
1545 centry = wcache_fetch(cache, domain, "SN/%s",
1546 sid_string_static(&sid));
1551 (*types)[i] = SID_NAME_UNKNOWN;
1552 (*names)[i] = talloc_strdup(*names, "");
1554 if (NT_STATUS_IS_OK(centry->status)) {
1557 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
1558 dom = centry_string(centry, mem_ctx);
1559 if (*domain_name == NULL) {
1564 (*names)[i] = centry_string(centry, *names);
1566 have_unmapped = True;
1569 centry_free(centry);
1573 return NT_STATUS_NONE_MAPPED;
1575 if (!have_unmapped) {
1576 return NT_STATUS_OK;
1578 return STATUS_SOME_UNMAPPED;
1582 TALLOC_FREE(*names);
1583 TALLOC_FREE(*types);
1585 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
1586 rids, num_rids, domain_name,
1589 if (!NT_STATUS_IS_OK(result) &&
1590 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
1594 refresh_sequence_number(domain, False);
1596 for (i=0; i<num_rids; i++) {
1600 if (!sid_compose(&sid, domain_sid, rids[i])) {
1601 result = NT_STATUS_INTERNAL_ERROR;
1605 status = (*types)[i] == SID_NAME_UNKNOWN ?
1606 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
1608 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
1609 (*names)[i], (*types)[i]);
1616 TALLOC_FREE(*names);
1617 TALLOC_FREE(*types);
1621 /* Lookup user information from a rid */
1622 static NTSTATUS query_user(struct winbindd_domain *domain,
1623 TALLOC_CTX *mem_ctx,
1624 const DOM_SID *user_sid,
1625 WINBIND_USERINFO *info)
1627 struct winbind_cache *cache = get_cache(domain);
1628 struct cache_entry *centry = NULL;
1634 centry = wcache_fetch(cache, domain, "U/%s", sid_string_static(user_sid));
1636 /* If we have an access denied cache entry and a cached info3 in the
1637 samlogon cache then do a query. This will force the rpc back end
1638 to return the info3 data. */
1640 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1641 netsamlogon_cache_have(user_sid)) {
1642 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1643 domain->last_status = NT_STATUS_OK;
1644 centry_free(centry);
1651 info->acct_name = centry_string(centry, mem_ctx);
1652 info->full_name = centry_string(centry, mem_ctx);
1653 info->homedir = centry_string(centry, mem_ctx);
1654 info->shell = centry_string(centry, mem_ctx);
1655 info->primary_gid = centry_uint32(centry);
1656 centry_sid(centry, mem_ctx, &info->user_sid);
1657 centry_sid(centry, mem_ctx, &info->group_sid);
1658 status = centry->status;
1660 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: %s\n",
1661 domain->name, nt_errstr(status) ));
1663 centry_free(centry);
1669 /* Return status value returned by seq number check */
1671 if (!NT_STATUS_IS_OK(domain->last_status))
1672 return domain->last_status;
1674 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
1677 status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
1680 refresh_sequence_number(domain, False);
1681 wcache_save_user(domain, status, info);
1687 /* Lookup groups a user is a member of. */
1688 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
1689 TALLOC_CTX *mem_ctx,
1690 const DOM_SID *user_sid,
1691 uint32 *num_groups, DOM_SID **user_gids)
1693 struct winbind_cache *cache = get_cache(domain);
1694 struct cache_entry *centry = NULL;
1702 centry = wcache_fetch(cache, domain, "UG/%s", sid_to_string(sid_string, user_sid));
1704 /* If we have an access denied cache entry and a cached info3 in the
1705 samlogon cache then do a query. This will force the rpc back end
1706 to return the info3 data. */
1708 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1709 netsamlogon_cache_have(user_sid)) {
1710 DEBUG(10, ("lookup_usergroups: cached access denied and have cached info3\n"));
1711 domain->last_status = NT_STATUS_OK;
1712 centry_free(centry);
1719 *num_groups = centry_uint32(centry);
1721 if (*num_groups == 0)
1724 (*user_gids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
1725 if (! (*user_gids)) {
1726 smb_panic_fn("lookup_usergroups out of memory");
1727 centry_free(centry);
1728 return NT_STATUS_NO_MEMORY;
1730 for (i=0; i<(*num_groups); i++) {
1731 centry_sid(centry, mem_ctx, &(*user_gids)[i]);
1735 status = centry->status;
1737 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status: %s\n",
1738 domain->name, nt_errstr(status) ));
1740 centry_free(centry);
1745 (*user_gids) = NULL;
1747 /* Return status value returned by seq number check */
1749 if (!NT_STATUS_IS_OK(domain->last_status))
1750 return domain->last_status;
1752 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
1755 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
1757 if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
1761 refresh_sequence_number(domain, False);
1762 centry = centry_start(domain, status);
1765 centry_put_uint32(centry, *num_groups);
1766 for (i=0; i<(*num_groups); i++) {
1767 centry_put_sid(centry, &(*user_gids)[i]);
1769 centry_end(centry, "UG/%s", sid_to_string(sid_string, user_sid));
1770 centry_free(centry);
1776 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
1777 TALLOC_CTX *mem_ctx,
1778 uint32 num_sids, const DOM_SID *sids,
1779 uint32 *num_aliases, uint32 **alias_rids)
1781 struct winbind_cache *cache = get_cache(domain);
1782 struct cache_entry *centry = NULL;
1784 char *sidlist = talloc_strdup(mem_ctx, "");
1790 if (num_sids == 0) {
1793 return NT_STATUS_OK;
1796 /* We need to cache indexed by the whole list of SIDs, the aliases
1797 * resulting might come from any of the SIDs. */
1799 for (i=0; i<num_sids; i++) {
1800 sidlist = talloc_asprintf(mem_ctx, "%s/%s", sidlist,
1801 sid_string_static(&sids[i]));
1802 if (sidlist == NULL)
1803 return NT_STATUS_NO_MEMORY;
1806 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
1811 *num_aliases = centry_uint32(centry);
1815 (*alias_rids) = TALLOC_ARRAY(mem_ctx, uint32, *num_aliases);
1817 if ((*alias_rids) == NULL) {
1818 centry_free(centry);
1819 return NT_STATUS_NO_MEMORY;
1822 (*alias_rids) = NULL;
1825 for (i=0; i<(*num_aliases); i++)
1826 (*alias_rids)[i] = centry_uint32(centry);
1828 status = centry->status;
1830 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
1831 "status %s\n", domain->name, nt_errstr(status)));
1833 centry_free(centry);
1838 (*alias_rids) = NULL;
1840 if (!NT_STATUS_IS_OK(domain->last_status))
1841 return domain->last_status;
1843 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
1844 "for domain %s\n", domain->name ));
1846 status = domain->backend->lookup_useraliases(domain, mem_ctx,
1848 num_aliases, alias_rids);
1851 refresh_sequence_number(domain, False);
1852 centry = centry_start(domain, status);
1855 centry_put_uint32(centry, *num_aliases);
1856 for (i=0; i<(*num_aliases); i++)
1857 centry_put_uint32(centry, (*alias_rids)[i]);
1858 centry_end(centry, "UA%s", sidlist);
1859 centry_free(centry);
1866 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1867 TALLOC_CTX *mem_ctx,
1868 const DOM_SID *group_sid, uint32 *num_names,
1869 DOM_SID **sid_mem, char ***names,
1870 uint32 **name_types)
1872 struct winbind_cache *cache = get_cache(domain);
1873 struct cache_entry *centry = NULL;
1881 centry = wcache_fetch(cache, domain, "GM/%s", sid_to_string(sid_string, group_sid));
1885 *num_names = centry_uint32(centry);
1887 if (*num_names == 0)
1890 (*sid_mem) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_names);
1891 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_names);
1892 (*name_types) = TALLOC_ARRAY(mem_ctx, uint32, *num_names);
1894 if (! (*sid_mem) || ! (*names) || ! (*name_types)) {
1895 smb_panic_fn("lookup_groupmem out of memory");
1896 centry_free(centry);
1897 return NT_STATUS_NO_MEMORY;
1900 for (i=0; i<(*num_names); i++) {
1901 centry_sid(centry, mem_ctx, &(*sid_mem)[i]);
1902 (*names)[i] = centry_string(centry, mem_ctx);
1903 (*name_types)[i] = centry_uint32(centry);
1907 status = centry->status;
1909 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status: %s\n",
1910 domain->name, nt_errstr(status)));
1912 centry_free(centry);
1919 (*name_types) = NULL;
1921 /* Return status value returned by seq number check */
1923 if (!NT_STATUS_IS_OK(domain->last_status))
1924 return domain->last_status;
1926 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
1929 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid, num_names,
1930 sid_mem, names, name_types);
1933 refresh_sequence_number(domain, False);
1934 centry = centry_start(domain, status);
1937 centry_put_uint32(centry, *num_names);
1938 for (i=0; i<(*num_names); i++) {
1939 centry_put_sid(centry, &(*sid_mem)[i]);
1940 centry_put_string(centry, (*names)[i]);
1941 centry_put_uint32(centry, (*name_types)[i]);
1943 centry_end(centry, "GM/%s", sid_to_string(sid_string, group_sid));
1944 centry_free(centry);
1950 /* find the sequence number for a domain */
1951 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
1953 refresh_sequence_number(domain, False);
1955 *seq = domain->sequence_number;
1957 return NT_STATUS_OK;
1960 /* enumerate trusted domains
1961 * (we need to have the list of trustdoms in the cache when we go offline) -
1963 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1964 TALLOC_CTX *mem_ctx,
1965 uint32 *num_domains,
1970 struct winbind_cache *cache = get_cache(domain);
1971 struct cache_entry *centry = NULL;
1978 centry = wcache_fetch(cache, domain, "TRUSTDOMS/%s", domain->name);
1984 *num_domains = centry_uint32(centry);
1987 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
1988 (*alt_names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
1989 (*dom_sids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
1991 if (! (*dom_sids) || ! (*names) || ! (*alt_names)) {
1992 smb_panic_fn("trusted_domains out of memory");
1993 centry_free(centry);
1994 return NT_STATUS_NO_MEMORY;
1998 (*alt_names) = NULL;
2002 for (i=0; i<(*num_domains); i++) {
2003 (*names)[i] = centry_string(centry, mem_ctx);
2004 (*alt_names)[i] = centry_string(centry, mem_ctx);
2005 centry_sid(centry, mem_ctx, &(*dom_sids)[i]);
2008 status = centry->status;
2010 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
2011 domain->name, *num_domains, nt_errstr(status) ));
2013 centry_free(centry);
2020 (*alt_names) = NULL;
2022 /* Return status value returned by seq number check */
2024 if (!NT_STATUS_IS_OK(domain->last_status))
2025 return domain->last_status;
2027 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2030 status = domain->backend->trusted_domains(domain, mem_ctx, num_domains,
2031 names, alt_names, dom_sids);
2033 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2034 * so that the generic centry handling still applies correctly -
2037 if (!NT_STATUS_IS_ERR(status)) {
2038 status = NT_STATUS_OK;
2042 #if 0 /* Disabled as we want the trust dom list to be managed by
2043 the main parent and always to make the query. --jerry */
2046 refresh_sequence_number(domain, False);
2048 centry = centry_start(domain, status);
2052 centry_put_uint32(centry, *num_domains);
2054 for (i=0; i<(*num_domains); i++) {
2055 centry_put_string(centry, (*names)[i]);
2056 centry_put_string(centry, (*alt_names)[i]);
2057 centry_put_sid(centry, &(*dom_sids)[i]);
2060 centry_end(centry, "TRUSTDOMS/%s", domain->name);
2062 centry_free(centry);
2070 /* get lockout policy */
2071 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
2072 TALLOC_CTX *mem_ctx,
2073 SAM_UNK_INFO_12 *policy){
2074 struct winbind_cache *cache = get_cache(domain);
2075 struct cache_entry *centry = NULL;
2081 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2086 policy->duration = centry_nttime(centry);
2087 policy->reset_count = centry_nttime(centry);
2088 policy->bad_attempt_lockout = centry_uint16(centry);
2090 status = centry->status;
2092 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2093 domain->name, nt_errstr(status) ));
2095 centry_free(centry);
2099 ZERO_STRUCTP(policy);
2101 /* Return status value returned by seq number check */
2103 if (!NT_STATUS_IS_OK(domain->last_status))
2104 return domain->last_status;
2106 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2109 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2112 refresh_sequence_number(domain, False);
2113 wcache_save_lockout_policy(domain, status, policy);
2118 /* get password policy */
2119 static NTSTATUS password_policy(struct winbindd_domain *domain,
2120 TALLOC_CTX *mem_ctx,
2121 SAM_UNK_INFO_1 *policy)
2123 struct winbind_cache *cache = get_cache(domain);
2124 struct cache_entry *centry = NULL;
2130 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2135 policy->min_length_password = centry_uint16(centry);
2136 policy->password_history = centry_uint16(centry);
2137 policy->password_properties = centry_uint32(centry);
2138 policy->expire = centry_nttime(centry);
2139 policy->min_passwordage = centry_nttime(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,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2160 status = domain->backend->password_policy(domain, mem_ctx, policy);
2163 refresh_sequence_number(domain, False);
2164 wcache_save_password_policy(domain, status, policy);
2170 /* Invalidate cached user and group lists coherently */
2172 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2175 if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
2176 strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
2177 tdb_delete(the_tdb, kbuf);
2182 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2184 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
2185 NET_USER_INFO_3 *info3)
2187 struct winbind_cache *cache;
2189 /* dont clear cached U/SID and UG/SID entries when we want to logon
2192 if (lp_winbind_offline_logon()) {
2199 cache = get_cache(domain);
2200 netsamlogon_clear_cached_user(cache->tdb, info3);
2203 void wcache_invalidate_cache(void)
2205 struct winbindd_domain *domain;
2207 for (domain = domain_list(); domain; domain = domain->next) {
2208 struct winbind_cache *cache = get_cache(domain);
2210 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2211 "entries for %s\n", domain->name));
2213 tdb_traverse(cache->tdb, traverse_fn, NULL);
2217 BOOL init_wcache(void)
2219 if (wcache == NULL) {
2220 wcache = SMB_XMALLOC_P(struct winbind_cache);
2221 ZERO_STRUCTP(wcache);
2224 if (wcache->tdb != NULL)
2227 /* when working offline we must not clear the cache on restart */
2228 wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
2229 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2230 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
2231 O_RDWR|O_CREAT, 0600);
2233 if (wcache->tdb == NULL) {
2234 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2241 /************************************************************************
2242 This is called by the parent to initialize the cache file.
2243 We don't need sophisticated locking here as we know we're the
2245 ************************************************************************/
2247 BOOL initialize_winbindd_cache(void)
2249 BOOL cache_bad = True;
2252 if (!init_wcache()) {
2253 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
2257 /* Check version number. */
2258 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
2259 vers == WINBINDD_CACHE_VERSION) {
2264 DEBUG(0,("initialize_winbindd_cache: clearing cache "
2265 "and re-creating with version number %d\n",
2266 WINBINDD_CACHE_VERSION ));
2268 tdb_close(wcache->tdb);
2271 if (unlink(lock_path("winbindd_cache.tdb")) == -1) {
2272 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
2273 lock_path("winbindd_cache.tdb"),
2277 if (!init_wcache()) {
2278 DEBUG(0,("initialize_winbindd_cache: re-initialization "
2279 "init_wcache failed.\n"));
2283 /* Write the version. */
2284 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
2285 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
2286 tdb_errorstr(wcache->tdb) ));
2291 tdb_close(wcache->tdb);
2296 void cache_store_response(pid_t pid, struct winbindd_response *response)
2303 DEBUG(10, ("Storing response for pid %d, len %d\n",
2304 pid, response->length));
2306 fstr_sprintf(key_str, "DR/%d", pid);
2307 if (tdb_store(wcache->tdb, string_tdb_data(key_str),
2308 make_tdb_data((uint8 *)response, sizeof(*response)),
2312 if (response->length == sizeof(*response))
2315 /* There's extra data */
2317 DEBUG(10, ("Storing extra data: len=%d\n",
2318 (int)(response->length - sizeof(*response))));
2320 fstr_sprintf(key_str, "DE/%d", pid);
2321 if (tdb_store(wcache->tdb, string_tdb_data(key_str),
2322 make_tdb_data((uint8 *)response->extra_data.data,
2323 response->length - sizeof(*response)),
2327 /* We could not store the extra data, make sure the tdb does not
2328 * contain a main record with wrong dangling extra data */
2330 fstr_sprintf(key_str, "DR/%d", pid);
2331 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2336 BOOL cache_retrieve_response(pid_t pid, struct winbindd_response * response)
2344 DEBUG(10, ("Retrieving response for pid %d\n", pid));
2346 fstr_sprintf(key_str, "DR/%d", pid);
2347 data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
2349 if (data.dptr == NULL)
2352 if (data.dsize != sizeof(*response))
2355 memcpy(response, data.dptr, data.dsize);
2356 SAFE_FREE(data.dptr);
2358 if (response->length == sizeof(*response)) {
2359 response->extra_data.data = NULL;
2363 /* There's extra data */
2365 DEBUG(10, ("Retrieving extra data length=%d\n",
2366 (int)(response->length - sizeof(*response))));
2368 fstr_sprintf(key_str, "DE/%d", pid);
2369 data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
2371 if (data.dptr == NULL) {
2372 DEBUG(0, ("Did not find extra data\n"));
2376 if (data.dsize != (response->length - sizeof(*response))) {
2377 DEBUG(0, ("Invalid extra data length: %d\n", (int)data.dsize));
2378 SAFE_FREE(data.dptr);
2382 dump_data(11, (uint8 *)data.dptr, data.dsize);
2384 response->extra_data.data = data.dptr;
2388 void cache_cleanup_response(pid_t pid)
2395 fstr_sprintf(key_str, "DR/%d", pid);
2396 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2398 fstr_sprintf(key_str, "DE/%d", pid);
2399 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2405 BOOL lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
2406 char **domain_name, char **name,
2407 enum lsa_SidType *type)
2409 struct winbindd_domain *domain;
2410 struct winbind_cache *cache;
2411 struct cache_entry *centry = NULL;
2414 domain = find_lookup_domain_from_sid(sid);
2415 if (domain == NULL) {
2419 cache = get_cache(domain);
2421 if (cache->tdb == NULL) {
2425 centry = wcache_fetch(cache, domain, "SN/%s", sid_string_static(sid));
2426 if (centry == NULL) {
2430 if (NT_STATUS_IS_OK(centry->status)) {
2431 *type = (enum lsa_SidType)centry_uint32(centry);
2432 *domain_name = centry_string(centry, mem_ctx);
2433 *name = centry_string(centry, mem_ctx);
2436 status = centry->status;
2437 centry_free(centry);
2438 return NT_STATUS_IS_OK(status);
2441 BOOL lookup_cached_name(TALLOC_CTX *mem_ctx,
2442 const char *domain_name,
2445 enum lsa_SidType *type)
2447 struct winbindd_domain *domain;
2448 struct winbind_cache *cache;
2449 struct cache_entry *centry = NULL;
2452 BOOL original_online_state;
2454 domain = find_lookup_domain_from_name(domain_name);
2455 if (domain == NULL) {
2459 cache = get_cache(domain);
2461 if (cache->tdb == NULL) {
2465 fstrcpy(uname, name);
2468 /* If we are doing a cached logon, temporarily set the domain
2469 offline so the cache won't expire the entry */
2471 original_online_state = domain->online;
2472 domain->online = False;
2473 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
2474 domain->online = original_online_state;
2476 if (centry == NULL) {
2480 if (NT_STATUS_IS_OK(centry->status)) {
2481 *type = (enum lsa_SidType)centry_uint32(centry);
2482 centry_sid(centry, mem_ctx, sid);
2485 status = centry->status;
2486 centry_free(centry);
2488 return NT_STATUS_IS_OK(status);
2491 void cache_name2sid(struct winbindd_domain *domain,
2492 const char *domain_name, const char *name,
2493 enum lsa_SidType type, const DOM_SID *sid)
2495 refresh_sequence_number(domain, False);
2496 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
2501 * The original idea that this cache only contains centries has
2502 * been blurred - now other stuff gets put in here. Ensure we
2503 * ignore these things on cleanup.
2506 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
2507 TDB_DATA dbuf, void *state)
2509 struct cache_entry *centry;
2511 if (is_non_centry_key(kbuf)) {
2515 centry = wcache_fetch_raw((char *)kbuf.dptr);
2520 if (!NT_STATUS_IS_OK(centry->status)) {
2521 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
2522 tdb_delete(the_tdb, kbuf);
2525 centry_free(centry);
2529 /* flush the cache */
2530 void wcache_flush_cache(void)
2535 tdb_close(wcache->tdb);
2541 /* when working offline we must not clear the cache on restart */
2542 wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
2543 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2544 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
2545 O_RDWR|O_CREAT, 0600);
2548 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2552 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
2554 DEBUG(10,("wcache_flush_cache success\n"));
2557 /* Count cached creds */
2559 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2562 int *cred_count = (int*)state;
2564 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
2570 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
2572 struct winbind_cache *cache = get_cache(domain);
2577 return NT_STATUS_INTERNAL_DB_ERROR;
2580 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
2582 return NT_STATUS_OK;
2586 struct cred_list *prev, *next;
2591 static struct cred_list *wcache_cred_list;
2593 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2596 struct cred_list *cred;
2598 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
2600 cred = SMB_MALLOC_P(struct cred_list);
2602 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2608 /* save a copy of the key */
2610 fstrcpy(cred->name, (const char *)kbuf.dptr);
2611 DLIST_ADD(wcache_cred_list, cred);
2617 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const DOM_SID *sid)
2619 struct winbind_cache *cache = get_cache(domain);
2622 struct cred_list *cred, *oldest = NULL;
2625 return NT_STATUS_INTERNAL_DB_ERROR;
2628 /* we possibly already have an entry */
2629 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
2633 DEBUG(11,("we already have an entry, deleting that\n"));
2635 fstr_sprintf(key_str, "CRED/%s", sid_string_static(sid));
2637 tdb_delete(cache->tdb, string_tdb_data(key_str));
2639 return NT_STATUS_OK;
2642 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
2644 return NT_STATUS_OK;
2645 } else if ((ret == -1) || (wcache_cred_list == NULL)) {
2646 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2649 ZERO_STRUCTP(oldest);
2651 for (cred = wcache_cred_list; cred; cred = cred->next) {
2656 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
2658 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
2660 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
2664 t = IVAL(data.dptr, 0);
2665 SAFE_FREE(data.dptr);
2668 oldest = SMB_MALLOC_P(struct cred_list);
2669 if (oldest == NULL) {
2670 status = NT_STATUS_NO_MEMORY;
2674 fstrcpy(oldest->name, cred->name);
2675 oldest->created = t;
2679 if (t < oldest->created) {
2680 fstrcpy(oldest->name, cred->name);
2681 oldest->created = t;
2685 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
2686 status = NT_STATUS_OK;
2688 status = NT_STATUS_UNSUCCESSFUL;
2691 SAFE_FREE(wcache_cred_list);
2697 /* Change the global online/offline state. */
2698 BOOL set_global_winbindd_state_offline(void)
2702 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
2704 /* Only go offline if someone has created
2705 the key "WINBINDD_OFFLINE" in the cache tdb. */
2707 if (wcache == NULL || wcache->tdb == NULL) {
2708 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
2712 if (!lp_winbind_offline_logon()) {
2713 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
2717 if (global_winbindd_offline_state) {
2718 /* Already offline. */
2722 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
2724 if (!data.dptr || data.dsize != 4) {
2725 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
2726 SAFE_FREE(data.dptr);
2729 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
2730 global_winbindd_offline_state = True;
2731 SAFE_FREE(data.dptr);
2736 void set_global_winbindd_state_online(void)
2738 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
2740 if (!lp_winbind_offline_logon()) {
2741 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
2745 if (!global_winbindd_offline_state) {
2746 /* Already online. */
2749 global_winbindd_offline_state = False;
2755 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
2756 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
2759 BOOL get_global_winbindd_state_offline(void)
2761 return global_winbindd_offline_state;
2764 /***********************************************************************
2765 Validate functions for all possible cache tdb keys.
2766 ***********************************************************************/
2768 struct validation_status {
2776 static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
2777 struct validation_status *state)
2779 struct cache_entry *centry;
2781 centry = SMB_XMALLOC_P(struct cache_entry);
2782 centry->data = (unsigned char *)memdup(data.dptr, data.dsize);
2783 if (!centry->data) {
2787 centry->len = data.dsize;
2790 if (centry->len < 8) {
2791 /* huh? corrupt cache? */
2792 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr));
2793 centry_free(centry);
2794 state->bad_entry = True;
2795 state->success = False;
2799 centry->status = NT_STATUS(centry_uint32(centry));
2800 centry->sequence_number = centry_uint32(centry);
2804 static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2805 struct validation_status *state)
2807 if (dbuf.dsize != 8) {
2808 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
2809 keystr, (unsigned int)dbuf.dsize ));
2810 state->bad_entry = True;
2816 static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2817 struct validation_status *state)
2819 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2824 (void)centry_uint32(centry);
2825 if (NT_STATUS_IS_OK(centry->status)) {
2827 (void)centry_sid(centry, mem_ctx, &sid);
2830 centry_free(centry);
2832 if (!(state->success)) {
2835 DEBUG(10,("validate_ns: %s ok\n", keystr));
2839 static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2840 struct validation_status *state)
2842 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2847 if (NT_STATUS_IS_OK(centry->status)) {
2848 (void)centry_uint32(centry);
2849 (void)centry_string(centry, mem_ctx);
2850 (void)centry_string(centry, mem_ctx);
2853 centry_free(centry);
2855 if (!(state->success)) {
2858 DEBUG(10,("validate_sn: %s ok\n", keystr));
2862 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2863 struct validation_status *state)
2865 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2872 (void)centry_string(centry, mem_ctx);
2873 (void)centry_string(centry, mem_ctx);
2874 (void)centry_string(centry, mem_ctx);
2875 (void)centry_string(centry, mem_ctx);
2876 (void)centry_uint32(centry);
2877 (void)centry_sid(centry, mem_ctx, &sid);
2878 (void)centry_sid(centry, mem_ctx, &sid);
2880 centry_free(centry);
2882 if (!(state->success)) {
2885 DEBUG(10,("validate_u: %s ok\n", keystr));
2889 static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2890 struct validation_status *state)
2892 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2898 (void)centry_nttime(centry);
2899 (void)centry_nttime(centry);
2900 (void)centry_uint16(centry);
2902 centry_free(centry);
2904 if (!(state->success)) {
2907 DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
2911 static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2912 struct validation_status *state)
2914 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2920 (void)centry_uint16(centry);
2921 (void)centry_uint16(centry);
2922 (void)centry_uint32(centry);
2923 (void)centry_nttime(centry);
2924 (void)centry_nttime(centry);
2926 centry_free(centry);
2928 if (!(state->success)) {
2931 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
2935 static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2936 struct validation_status *state)
2938 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2944 (void)centry_time(centry);
2945 (void)centry_hash16(centry, mem_ctx);
2947 /* We only have 17 bytes more data in the salted cred case. */
2948 if (centry->len - centry->ofs == 17) {
2949 (void)centry_hash16(centry, mem_ctx);
2952 centry_free(centry);
2954 if (!(state->success)) {
2957 DEBUG(10,("validate_cred: %s ok\n", keystr));
2961 static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2962 struct validation_status *state)
2964 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2965 int32 num_entries, i;
2971 num_entries = (int32)centry_uint32(centry);
2973 for (i=0; i< num_entries; i++) {
2975 (void)centry_string(centry, mem_ctx);
2976 (void)centry_string(centry, mem_ctx);
2977 (void)centry_string(centry, mem_ctx);
2978 (void)centry_string(centry, mem_ctx);
2979 (void)centry_sid(centry, mem_ctx, &sid);
2980 (void)centry_sid(centry, mem_ctx, &sid);
2983 centry_free(centry);
2985 if (!(state->success)) {
2988 DEBUG(10,("validate_ul: %s ok\n", keystr));
2992 static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
2993 struct validation_status *state)
2995 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
2996 int32 num_entries, i;
3002 num_entries = centry_uint32(centry);
3004 for (i=0; i< num_entries; i++) {
3005 (void)centry_string(centry, mem_ctx);
3006 (void)centry_string(centry, mem_ctx);
3007 (void)centry_uint32(centry);
3010 centry_free(centry);
3012 if (!(state->success)) {
3015 DEBUG(10,("validate_gl: %s ok\n", keystr));
3019 static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3020 struct validation_status *state)
3022 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3023 int32 num_groups, i;
3029 num_groups = centry_uint32(centry);
3031 for (i=0; i< num_groups; i++) {
3033 centry_sid(centry, mem_ctx, &sid);
3036 centry_free(centry);
3038 if (!(state->success)) {
3041 DEBUG(10,("validate_ug: %s ok\n", keystr));
3045 static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3046 struct validation_status *state)
3048 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3049 int32 num_aliases, i;
3055 num_aliases = centry_uint32(centry);
3057 for (i=0; i < num_aliases; i++) {
3058 (void)centry_uint32(centry);
3061 centry_free(centry);
3063 if (!(state->success)) {
3066 DEBUG(10,("validate_ua: %s ok\n", keystr));
3070 static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3071 struct validation_status *state)
3073 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3080 num_names = centry_uint32(centry);
3082 for (i=0; i< num_names; i++) {
3084 centry_sid(centry, mem_ctx, &sid);
3085 (void)centry_string(centry, mem_ctx);
3086 (void)centry_uint32(centry);
3089 centry_free(centry);
3091 if (!(state->success)) {
3094 DEBUG(10,("validate_gm: %s ok\n", keystr));
3098 static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3099 struct validation_status *state)
3101 /* Can't say anything about this other than must be nonzero. */
3102 if (dbuf.dsize == 0) {
3103 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3105 state->bad_entry = True;
3106 state->success = False;
3110 DEBUG(10,("validate_dr: %s ok\n", keystr));
3114 static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3115 struct validation_status *state)
3117 /* Can't say anything about this other than must be nonzero. */
3118 if (dbuf.dsize == 0) {
3119 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3121 state->bad_entry = True;
3122 state->success = False;
3126 DEBUG(10,("validate_de: %s ok\n", keystr));
3130 static int validate_trustdoms(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3131 struct validation_status *state)
3133 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3134 int32 num_domains, i;
3140 num_domains = centry_uint32(centry);
3142 for (i=0; i< num_domains; i++) {
3144 (void)centry_string(centry, mem_ctx);
3145 (void)centry_string(centry, mem_ctx);
3146 (void)centry_sid(centry, mem_ctx, &sid);
3149 centry_free(centry);
3151 if (!(state->success)) {
3154 DEBUG(10,("validate_trustdoms: %s ok\n", keystr));
3158 static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
3160 struct validation_status *state)
3162 if (dbuf.dsize == 0) {
3163 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3164 "key %s (len ==0) ?\n", keystr));
3165 state->bad_entry = True;
3166 state->success = False;
3170 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
3171 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3175 static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3176 struct validation_status *state)
3178 if (dbuf.dsize != 4) {
3179 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3180 keystr, (unsigned int)dbuf.dsize ));
3181 state->bad_entry = True;
3182 state->success = False;
3185 DEBUG(10,("validate_offline: %s ok\n", keystr));
3189 static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3190 struct validation_status *state)
3192 if (dbuf.dsize != 4) {
3193 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3194 "key %s (len %u != 4) ?\n",
3195 keystr, (unsigned int)dbuf.dsize));
3196 state->bad_entry = True;
3197 state->success = False;
3201 DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
3205 /***********************************************************************
3206 A list of all possible cache tdb keys with associated validation
3208 ***********************************************************************/
3210 struct key_val_struct {
3211 const char *keyname;
3212 int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct validation_status* state);
3214 {"SEQNUM/", validate_seqnum},
3215 {"NS/", validate_ns},
3216 {"SN/", validate_sn},
3218 {"LOC_POL/", validate_loc_pol},
3219 {"PWD_POL/", validate_pwd_pol},
3220 {"CRED/", validate_cred},
3221 {"UL/", validate_ul},
3222 {"GL/", validate_gl},
3223 {"UG/", validate_ug},
3224 {"UA", validate_ua},
3225 {"GM/", validate_gm},
3226 {"DR/", validate_dr},
3227 {"DE/", validate_de},
3228 {"TRUSTDOMS/", validate_trustdoms},
3229 {"TRUSTDOMCACHE/", validate_trustdomcache},
3230 {"WINBINDD_OFFLINE", validate_offline},
3231 {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
3235 /***********************************************************************
3236 Function to look at every entry in the tdb and validate it as far as
3238 ***********************************************************************/
3240 static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
3243 struct validation_status *v_state = (struct validation_status *)state;
3245 /* Paranoia check. */
3246 if (kbuf.dsize > 1024) {
3247 DEBUG(0,("cache_traverse_validate_fn: key length too large (%u) > 1024\n\n",
3248 (unsigned int)kbuf.dsize ));
3252 for (i = 0; key_val[i].keyname; i++) {
3253 size_t namelen = strlen(key_val[i].keyname);
3254 if (kbuf.dsize >= namelen && (
3255 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
3256 TALLOC_CTX *mem_ctx;
3260 keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
3264 memcpy(keystr, kbuf.dptr, kbuf.dsize);
3265 keystr[kbuf.dsize] = '\0';
3267 mem_ctx = talloc_init("validate_ctx");
3273 ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
3277 talloc_destroy(mem_ctx);
3282 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
3283 dump_data(0, (uint8 *)kbuf.dptr, kbuf.dsize);
3284 DEBUG(0,("data :\n"));
3285 dump_data(0, (uint8 *)dbuf.dptr, dbuf.dsize);
3286 v_state->unknown_key = True;
3287 v_state->success = False;
3288 return 1; /* terminate. */
3291 static void validate_panic(const char *const why)
3293 DEBUG(0,("validating cache: would panic %s\n", why ));
3294 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
3298 /***********************************************************************
3299 Try and validate every entry in the winbindd cache. If we fail here,
3300 delete the cache tdb and return non-zero - the caller (main winbindd
3301 function) will restart us as we don't know if we crashed or not.
3302 ***********************************************************************/
3305 * internal validation function, executed by the child.
3307 static int winbindd_validate_cache_child(const char *cache_path, int pfd)
3311 int num_entries = 0;
3312 TDB_CONTEXT *tdb = NULL;
3313 struct validation_status v_status;
3315 v_status.tdb_error = False;
3316 v_status.bad_freelist = False;
3317 v_status.bad_entry = False;
3318 v_status.unknown_key = False;
3319 v_status.success = True;
3321 tdb = tdb_open_log(cache_path,
3322 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3323 lp_winbind_offline_logon()
3325 : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
3326 O_RDWR|O_CREAT, 0600);
3328 v_status.tdb_error = True;
3329 v_status.success = False;
3335 /* Check the cache freelist is good. */
3336 if (tdb_validate_freelist(tdb, &num_entries) == -1) {
3337 DEBUG(0,("winbindd_validate_cache_child: bad freelist in cache %s\n",
3339 v_status.bad_freelist = True;
3340 v_status.success = False;
3344 DEBUG(10,("winbindd_validate_cache_child: cache %s freelist has %d entries\n",
3345 cache_path, num_entries));
3347 /* Now traverse the cache to validate it. */
3348 num_entries = tdb_traverse(tdb, cache_traverse_validate_fn, (void *)&v_status);
3349 if (num_entries == -1 || !(v_status.success)) {
3350 DEBUG(0,("winbindd_validate_cache_child: cache %s traverse failed\n",
3352 if (!(v_status.success)) {
3353 if (v_status.bad_entry) {
3354 DEBUGADD(0, (" -> bad entry found\n"));
3356 if (v_status.unknown_key) {
3357 DEBUGADD(0, (" -> unknown key encountered\n"));
3363 DEBUG(10,("winbindd_validate_cache_child: cache %s is good "
3364 "with %d entries\n", cache_path, num_entries));
3365 ret = 0; /* Cache is good. */
3372 else if (tfd != -1) {
3377 DEBUG(10, ("winbindd_validate_cache_child: writing status to pipe\n"));
3378 write (pfd, (const char *)&v_status, sizeof(v_status));
3384 int winbindd_validate_cache(void)
3386 pid_t child_pid = -1;
3387 int child_status = 0;
3391 struct validation_status v_status;
3393 const char *cache_path = lock_path("winbindd_cache.tdb");
3395 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3396 smb_panic_fn = validate_panic;
3398 /* fork and let the child do the validation.
3399 * benefit: no need to twist signal handlers and panic functions.
3400 * just let the child panic. we catch the signal.
3401 * communicate the extended status struct over a pipe. */
3403 if (pipe(pipe_fds) != 0) {
3404 DEBUG(0, ("winbindd_validate_cache: unable to create pipe, "
3405 "error %s", strerror(errno)));
3406 smb_panic("winbind_validate_cache: unable to create pipe.");
3409 DEBUG(10, ("winbindd_validate_cache: forking to let child do validation.\n"));
3410 child_pid = sys_fork();
3411 if (child_pid == 0) {
3412 DEBUG(10, ("winbindd_validate_cache (validation child): created\n"));
3413 close(pipe_fds[0]); /* close reading fd */
3414 DEBUG(10, ("winbindd_validate_cache (validation child): "
3415 "calling winbindd_validate_cache_child\n"));
3416 exit(winbindd_validate_cache_child(cache_path, pipe_fds[1]));
3418 else if (child_pid < 0) {
3419 smb_panic("winbindd_validate_cache: fork for validation failed.");
3424 DEBUG(10, ("winbindd_validate_cache: fork succeeded, child PID = %d\n",
3426 close(pipe_fds[1]); /* close writing fd */
3428 v_status.success = True;
3429 v_status.bad_entry = False;
3430 v_status.unknown_key = False;
3432 DEBUG(10, ("winbindd_validate_cache: reading from pipe.\n"));
3433 bytes_read = read(pipe_fds[0], (void *)&v_status, sizeof(v_status));
3436 if (bytes_read != sizeof(v_status)) {
3437 DEBUG(10, ("winbindd_validate_cache: read %d bytes from pipe "
3438 "but expected %d", bytes_read, sizeof(v_status)));
3439 DEBUGADD(10, (" -> assuming child crashed\n"));
3440 v_status.success = False;
3443 DEBUG(10, ("winbindd_validate_cache: read status from child\n"));
3444 DEBUGADD(10, (" * tdb error: %s\n", v_status.tdb_error ? "yes" : "no"));
3445 DEBUGADD(10, (" * bad freelist: %s\n", v_status.bad_freelist ? "yes" : "no"));
3446 DEBUGADD(10, (" * bad entry: %s\n", v_status.bad_entry ? "yes" : "no"));
3447 DEBUGADD(10, (" * unknown key: %s\n", v_status.unknown_key ? "yes" : "no"));
3448 DEBUGADD(10, (" => overall success: %s\n", v_status.success ? "yes" : "no"));
3451 if (!v_status.success) {
3452 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
3453 DEBUGADD(10, ("removing tdb %s.\n", cache_path));
3457 DEBUG(10, ("winbindd_validate_cache: waiting for child to finish...\n"));
3458 while ((wait_pid = sys_waitpid(child_pid, &child_status, 0)) < 0) {
3459 if (errno == EINTR) {
3460 DEBUG(10, ("winbindd_validate_cache: got signal during "
3461 "waitpid, retrying\n"));
3465 DEBUG(0, ("winbindd_validate_cache: waitpid failed with "
3466 "errno %s\n", strerror(errno)));
3467 smb_panic("winbindd_validate_cache: waitpid failed.");
3469 if (wait_pid != child_pid) {
3470 DEBUG(0, ("winbindd_validate_cache: waitpid returned pid %d, "
3471 "but %d was expexted\n", wait_pid, child_pid));
3472 smb_panic("winbindd_validate_cache: waitpid returned "
3477 DEBUG(10, ("winbindd_validate_cache: validating child returned.\n"));
3478 if (WIFEXITED(child_status)) {
3479 DEBUG(10, ("winbindd_validate_cache: child exited, code %d.\n",
3480 WEXITSTATUS(child_status)));
3481 ret = WEXITSTATUS(child_status);
3483 if (WIFSIGNALED(child_status)) {
3484 DEBUG(10, ("winbindd_validate_cache: child terminated "
3486 WTERMSIG(child_status),
3487 #if defined(WCOREDUMP)
3488 WCOREDUMP(child_status)?" (core dumped)":""
3493 ret = WTERMSIG(child_status);
3495 if (WIFSTOPPED(child_status)) {
3496 DEBUG(10, ("winbindd_validate_cache: child was stopped "
3498 WSTOPSIG(child_status)));
3499 ret = WSTOPSIG(child_status);
3502 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
3503 smb_panic_fn = smb_panic;
3507 /*********************************************************************
3508 ********************************************************************/
3510 static BOOL add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
3511 struct winbindd_tdc_domain **domains,
3512 size_t *num_domains )
3514 struct winbindd_tdc_domain *list = NULL;
3517 BOOL set_only = False;
3519 /* don't allow duplicates */
3524 for ( i=0; i< (*num_domains); i++ ) {
3525 if ( strequal( new_dom->name, list[i].domain_name ) ) {
3526 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
3537 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, 1 );
3540 list = TALLOC_REALLOC_ARRAY( *domains, *domains,
3541 struct winbindd_tdc_domain,
3546 ZERO_STRUCT( list[idx] );
3552 list[idx].domain_name = talloc_strdup( list, new_dom->name );
3553 list[idx].dns_name = talloc_strdup( list, new_dom->alt_name );
3555 if ( !is_null_sid( &new_dom->sid ) )
3556 sid_copy( &list[idx].sid, &new_dom->sid );
3558 if ( new_dom->domain_flags != 0x0 )
3559 list[idx].trust_flags = new_dom->domain_flags;
3561 if ( new_dom->domain_type != 0x0 )
3562 list[idx].trust_type = new_dom->domain_type;
3564 if ( new_dom->domain_trust_attribs != 0x0 )
3565 list[idx].trust_attribs = new_dom->domain_trust_attribs;
3569 *num_domains = idx + 1;
3575 /*********************************************************************
3576 ********************************************************************/
3578 static TDB_DATA make_tdc_key( const char *domain_name )
3580 char *keystr = NULL;
3581 TDB_DATA key = { NULL, 0 };
3583 if ( !domain_name ) {
3584 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
3589 asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name );
3590 key.dptr = (unsigned char*)keystr;
3591 key.dsize = strlen_m(keystr) + 1;
3596 /*********************************************************************
3597 ********************************************************************/
3599 static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
3601 unsigned char **buf )
3603 unsigned char *buffer = NULL;
3608 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
3616 /* Store the number of array items first */
3617 len += tdb_pack( buffer+len, buflen-len, "d",
3620 /* now pack each domain trust record */
3621 for ( i=0; i<num_domains; i++ ) {
3624 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
3625 domains[i].domain_name,
3626 domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
3629 len += tdb_pack( buffer+len, buflen-len, "fffddd",
3630 domains[i].domain_name,
3631 domains[i].dns_name,
3632 sid_string_static(&domains[i].sid),
3633 domains[i].trust_flags,
3634 domains[i].trust_attribs,
3635 domains[i].trust_type );
3638 if ( buflen < len ) {
3639 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
3640 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
3654 /*********************************************************************
3655 ********************************************************************/
3657 static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
3658 struct winbindd_tdc_domain **domains )
3660 fstring domain_name, dns_name, sid_string;
3661 uint32 type, attribs, flags;
3665 struct winbindd_tdc_domain *list = NULL;
3667 /* get the number of domains */
3668 len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
3670 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3674 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, num_domains );
3676 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
3680 for ( i=0; i<num_domains; i++ ) {
3681 len += tdb_unpack( buf+len, buflen-len, "fffddd",
3690 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3691 TALLOC_FREE( list );
3695 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
3696 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
3697 domain_name, dns_name, sid_string,
3698 flags, attribs, type));
3700 list[i].domain_name = talloc_strdup( list, domain_name );
3701 list[i].dns_name = talloc_strdup( list, dns_name );
3702 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
3703 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
3706 list[i].trust_flags = flags;
3707 list[i].trust_attribs = attribs;
3708 list[i].trust_type = type;
3716 /*********************************************************************
3717 ********************************************************************/
3719 static BOOL wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
3721 TDB_DATA key = make_tdc_key( lp_workgroup() );
3722 TDB_DATA data = { NULL, 0 };
3728 /* See if we were asked to delete the cache entry */
3731 ret = tdb_delete( wcache->tdb, key );
3735 data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
3742 ret = tdb_store( wcache->tdb, key, data, 0 );
3745 SAFE_FREE( data.dptr );
3746 SAFE_FREE( key.dptr );
3748 return ( ret != -1 );
3751 /*********************************************************************
3752 ********************************************************************/
3754 BOOL wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
3756 TDB_DATA key = make_tdc_key( lp_workgroup() );
3757 TDB_DATA data = { NULL, 0 };
3765 data = tdb_fetch( wcache->tdb, key );
3767 SAFE_FREE( key.dptr );
3772 *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
3774 SAFE_FREE( data.dptr );
3782 /*********************************************************************
3783 ********************************************************************/
3785 BOOL wcache_tdc_add_domain( struct winbindd_domain *domain )
3787 struct winbindd_tdc_domain *dom_list = NULL;
3788 size_t num_domains = 0;
3791 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
3792 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
3793 domain->name, domain->alt_name,
3794 sid_string_static(&domain->sid),
3795 domain->domain_flags,
3796 domain->domain_trust_attribs,
3797 domain->domain_type));
3799 if ( !init_wcache() ) {
3803 /* fetch the list */
3805 wcache_tdc_fetch_list( &dom_list, &num_domains );
3807 /* add the new domain */
3809 if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
3813 /* pack the domain */
3815 if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
3823 TALLOC_FREE( dom_list );
3828 /*********************************************************************
3829 ********************************************************************/
3831 struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
3833 struct winbindd_tdc_domain *dom_list = NULL;
3834 size_t num_domains = 0;
3836 struct winbindd_tdc_domain *d = NULL;
3838 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
3840 if ( !init_wcache() ) {
3844 /* fetch the list */
3846 wcache_tdc_fetch_list( &dom_list, &num_domains );
3848 for ( i=0; i<num_domains; i++ ) {
3849 if ( strequal(name, dom_list[i].domain_name) ||
3850 strequal(name, dom_list[i].dns_name) )
3852 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
3855 d = TALLOC_P( ctx, struct winbindd_tdc_domain );
3859 d->domain_name = talloc_strdup( d, dom_list[i].domain_name );
3860 d->dns_name = talloc_strdup( d, dom_list[i].dns_name );
3861 sid_copy( &d->sid, &dom_list[i].sid );
3862 d->trust_flags = dom_list[i].trust_flags;
3863 d->trust_type = dom_list[i].trust_type;
3864 d->trust_attribs = dom_list[i].trust_attribs;
3870 TALLOC_FREE( dom_list );
3876 /*********************************************************************
3877 ********************************************************************/
3879 void wcache_tdc_clear( void )
3881 if ( !init_wcache() )
3884 wcache_tdc_store_list( NULL, 0 );
3890 /*********************************************************************
3891 ********************************************************************/
3893 static void wcache_save_user_pwinfo(struct winbindd_domain *domain,
3895 const DOM_SID *user_sid,
3896 const char *homedir,
3901 struct cache_entry *centry;
3903 if ( (centry = centry_start(domain, status)) == NULL )
3906 centry_put_string( centry, homedir );
3907 centry_put_string( centry, shell );
3908 centry_put_string( centry, gecos );
3909 centry_put_uint32( centry, gid );
3911 centry_end(centry, "NSS/PWINFO/%s", sid_string_static(user_sid) );
3913 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_static(user_sid) ));
3915 centry_free(centry);
3918 NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
3919 const DOM_SID *user_sid,
3921 ADS_STRUCT *ads, LDAPMessage *msg,
3922 char **homedir, char **shell, char **gecos,
3925 struct winbind_cache *cache = get_cache(domain);
3926 struct cache_entry *centry = NULL;
3932 centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s", sid_string_static(user_sid));
3937 *homedir = centry_string( centry, ctx );
3938 *shell = centry_string( centry, ctx );
3939 *gecos = centry_string( centry, ctx );
3940 *p_gid = centry_uint32( centry );
3942 centry_free(centry);
3944 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
3945 sid_string_static(user_sid)));
3947 return NT_STATUS_OK;
3951 nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg,
3952 homedir, shell, gecos, p_gid );
3954 if ( NT_STATUS_IS_OK(nt_status) ) {
3955 wcache_save_user_pwinfo( domain, nt_status, user_sid,
3956 *homedir, *shell, *gecos, *p_gid );
3959 if ( NT_STATUS_EQUAL( nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
3960 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
3962 set_domain_offline( domain );
3969 /* the cache backend methods are exposed via this structure */
3970 struct winbindd_methods cache_methods = {