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/>.
28 #include "tdb_validate.h"
29 #include "../libcli/auth/libcli_auth.h"
32 #define DBGC_CLASS DBGC_WINBIND
34 #define WINBINDD_CACHE_VERSION 1
35 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
37 extern struct winbindd_methods reconnect_methods;
39 extern struct winbindd_methods ads_methods;
41 extern struct winbindd_methods builtin_passdb_methods;
44 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
45 * Here are the list of entry types that are *not* stored
46 * as form struct cache_entry in the cache.
49 static const char *non_centry_keys[] = {
54 WINBINDD_CACHE_VERSION_KEYSTR,
58 /************************************************************************
59 Is this key a non-centry type ?
60 ************************************************************************/
62 static bool is_non_centry_key(TDB_DATA kbuf)
66 if (kbuf.dptr == NULL || kbuf.dsize == 0) {
69 for (i = 0; non_centry_keys[i] != NULL; i++) {
70 size_t namelen = strlen(non_centry_keys[i]);
71 if (kbuf.dsize < namelen) {
74 if (strncmp(non_centry_keys[i], (const char *)kbuf.dptr, namelen) == 0) {
81 /* Global online/offline state - False when online. winbindd starts up online
82 and sets this to true if the first query fails and there's an entry in
83 the cache tdb telling us to stay offline. */
85 static bool global_winbindd_offline_state;
87 struct winbind_cache {
93 uint32 sequence_number;
98 void (*smb_panic_fn)(const char *const why) = smb_panic;
100 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
102 static struct winbind_cache *wcache;
104 void winbindd_check_cache_size(time_t t)
106 static time_t last_check_time;
109 if (last_check_time == (time_t)0)
112 if (t - last_check_time < 60 && t - last_check_time > 0)
115 if (wcache == NULL || wcache->tdb == NULL) {
116 DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
120 if (fstat(tdb_fd(wcache->tdb), &st) == -1) {
121 DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno) ));
125 if (st.st_size > WINBINDD_MAX_CACHE_SIZE) {
126 DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
127 (unsigned long)st.st_size,
128 (unsigned long)WINBINDD_MAX_CACHE_SIZE));
129 wcache_flush_cache();
133 /* get the winbind_cache structure */
134 static struct winbind_cache *get_cache(struct winbindd_domain *domain)
136 struct winbind_cache *ret = wcache;
138 /* We have to know what type of domain we are dealing with first. */
140 if (domain->internal) {
141 domain->backend = &builtin_passdb_methods;
142 domain->initialized = True;
144 if ( !domain->initialized ) {
145 init_dc_connection( domain );
149 OK. listen up becasue I'm only going to say this once.
150 We have the following scenarios to consider
151 (a) trusted AD domains on a Samba DC,
152 (b) trusted AD domains and we are joined to a non-kerberos domain
153 (c) trusted AD domains and we are joined to a kerberos (AD) domain
155 For (a) we can always contact the trusted domain using krb5
156 since we have the domain trust account password
158 For (b) we can only use RPC since we have no way of
159 getting a krb5 ticket in our own domain
161 For (c) we can always use krb5 since we have a kerberos trust
166 if (!domain->backend) {
168 struct winbindd_domain *our_domain = domain;
170 /* find our domain first so we can figure out if we
171 are joined to a kerberized domain */
173 if ( !domain->primary )
174 our_domain = find_our_domain();
176 if ((our_domain->active_directory || IS_DC)
177 && domain->active_directory
178 && !lp_winbind_rpc_only()) {
179 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain->name));
180 domain->backend = &ads_methods;
182 #endif /* HAVE_ADS */
183 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain->name));
184 domain->backend = &reconnect_methods;
187 #endif /* HAVE_ADS */
193 ret = SMB_XMALLOC_P(struct winbind_cache);
197 wcache_flush_cache();
203 free a centry structure
205 static void centry_free(struct cache_entry *centry)
209 SAFE_FREE(centry->data);
213 static bool centry_check_bytes(struct cache_entry *centry, size_t nbytes)
215 if (centry->len - centry->ofs < nbytes) {
216 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
217 (unsigned int)nbytes,
218 centry->len - centry->ofs));
225 pull a uint32 from a cache entry
227 static uint32 centry_uint32(struct cache_entry *centry)
231 if (!centry_check_bytes(centry, 4)) {
232 smb_panic_fn("centry_uint32");
234 ret = IVAL(centry->data, centry->ofs);
240 pull a uint16 from a cache entry
242 static uint16 centry_uint16(struct cache_entry *centry)
245 if (!centry_check_bytes(centry, 2)) {
246 smb_panic_fn("centry_uint16");
248 ret = CVAL(centry->data, centry->ofs);
254 pull a uint8 from a cache entry
256 static uint8 centry_uint8(struct cache_entry *centry)
259 if (!centry_check_bytes(centry, 1)) {
260 smb_panic_fn("centry_uint8");
262 ret = CVAL(centry->data, centry->ofs);
268 pull a NTTIME from a cache entry
270 static NTTIME centry_nttime(struct cache_entry *centry)
273 if (!centry_check_bytes(centry, 8)) {
274 smb_panic_fn("centry_nttime");
276 ret = IVAL(centry->data, centry->ofs);
278 ret += (uint64_t)IVAL(centry->data, centry->ofs) << 32;
284 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
286 static time_t centry_time(struct cache_entry *centry)
288 return (time_t)centry_nttime(centry);
291 /* pull a string from a cache entry, using the supplied
294 static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
299 len = centry_uint8(centry);
302 /* a deliberate NULL string */
306 if (!centry_check_bytes(centry, (size_t)len)) {
307 smb_panic_fn("centry_string");
310 ret = TALLOC_ARRAY(mem_ctx, char, len+1);
312 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");
344 memcpy(ret,centry->data + centry->ofs, 16);
349 /* pull a sid from a cache entry, using the supplied
352 static bool centry_sid(struct cache_entry *centry, struct dom_sid *sid)
357 sid_string = centry_string(centry, talloc_tos());
358 if (sid_string == NULL) {
361 ret = string_to_sid(sid, sid_string);
362 TALLOC_FREE(sid_string);
368 pull a NTSTATUS from a cache entry
370 static NTSTATUS centry_ntstatus(struct cache_entry *centry)
374 status = NT_STATUS(centry_uint32(centry));
379 /* the server is considered down if it can't give us a sequence number */
380 static bool wcache_server_down(struct winbindd_domain *domain)
387 ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
390 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
395 static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
402 DEBUG(10,("fetch_cache_seqnum: tdb == NULL\n"));
403 return NT_STATUS_UNSUCCESSFUL;
406 fstr_sprintf( key, "SEQNUM/%s", domain->name );
408 data = tdb_fetch_bystring( wcache->tdb, key );
409 if ( !data.dptr || data.dsize!=8 ) {
410 DEBUG(10,("fetch_cache_seqnum: invalid data size key [%s]\n", key ));
411 return NT_STATUS_UNSUCCESSFUL;
414 domain->sequence_number = IVAL(data.dptr, 0);
415 domain->last_seq_check = IVAL(data.dptr, 4);
417 SAFE_FREE(data.dptr);
419 /* have we expired? */
421 time_diff = now - domain->last_seq_check;
422 if ( time_diff > lp_winbind_cache_time() ) {
423 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
424 domain->name, domain->sequence_number,
425 (uint32)domain->last_seq_check));
426 return NT_STATUS_UNSUCCESSFUL;
429 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
430 domain->name, domain->sequence_number,
431 (uint32)domain->last_seq_check));
436 static NTSTATUS store_cache_seqnum( struct winbindd_domain *domain )
443 DEBUG(10,("store_cache_seqnum: tdb == NULL\n"));
444 return NT_STATUS_UNSUCCESSFUL;
447 fstr_sprintf( key_str, "SEQNUM/%s", domain->name );
449 SIVAL(buf, 0, domain->sequence_number);
450 SIVAL(buf, 4, domain->last_seq_check);
454 if ( tdb_store_bystring( wcache->tdb, key_str, data, TDB_REPLACE) == -1 ) {
455 DEBUG(10,("store_cache_seqnum: tdb_store fail key [%s]\n", key_str ));
456 return NT_STATUS_UNSUCCESSFUL;
459 DEBUG(10,("store_cache_seqnum: success [%s][%u @ %u]\n",
460 domain->name, domain->sequence_number,
461 (uint32)domain->last_seq_check));
467 refresh the domain sequence number. If force is true
468 then always refresh it, no matter how recently we fetched it
471 static void refresh_sequence_number(struct winbindd_domain *domain, bool force)
475 time_t t = time(NULL);
476 unsigned cache_time = lp_winbind_cache_time();
478 if ( IS_DOMAIN_OFFLINE(domain) ) {
484 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
485 /* trying to reconnect is expensive, don't do it too often */
486 if (domain->sequence_number == DOM_SEQUENCE_NONE) {
491 time_diff = t - domain->last_seq_check;
493 /* see if we have to refetch the domain sequence number */
494 if (!force && (time_diff < cache_time) &&
495 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
496 NT_STATUS_IS_OK(domain->last_status)) {
497 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
501 /* try to get the sequence number from the tdb cache first */
502 /* this will update the timestamp as well */
504 status = fetch_cache_seqnum( domain, t );
505 if (NT_STATUS_IS_OK(status) &&
506 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
507 NT_STATUS_IS_OK(domain->last_status)) {
511 /* important! make sure that we know if this is a native
512 mode domain or not. And that we can contact it. */
514 if ( winbindd_can_contact_domain( domain ) ) {
515 status = domain->backend->sequence_number(domain,
516 &domain->sequence_number);
518 /* just use the current time */
519 status = NT_STATUS_OK;
520 domain->sequence_number = time(NULL);
524 /* the above call could have set our domain->backend to NULL when
525 * coming from offline to online mode, make sure to reinitialize the
526 * backend - Guenther */
529 if (!NT_STATUS_IS_OK(status)) {
530 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status)));
531 domain->sequence_number = DOM_SEQUENCE_NONE;
534 domain->last_status = status;
535 domain->last_seq_check = time(NULL);
537 /* save the new sequence number in the cache */
538 store_cache_seqnum( domain );
541 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
542 domain->name, domain->sequence_number));
548 decide if a cache entry has expired
550 static bool centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
552 /* If we've been told to be offline - stay in that state... */
553 if (lp_winbind_offline_logon() && global_winbindd_offline_state) {
554 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
555 keystr, domain->name ));
559 /* when the domain is offline return the cached entry.
560 * This deals with transient offline states... */
562 if (!domain->online) {
563 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
564 keystr, domain->name ));
568 /* if the server is OK and our cache entry came from when it was down then
569 the entry is invalid */
570 if ((domain->sequence_number != DOM_SEQUENCE_NONE) &&
571 (centry->sequence_number == DOM_SEQUENCE_NONE)) {
572 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
573 keystr, domain->name ));
577 /* if the server is down or the cache entry is not older than the
578 current sequence number then it is OK */
579 if (wcache_server_down(domain) ||
580 centry->sequence_number == domain->sequence_number) {
581 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
582 keystr, domain->name ));
586 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
587 keystr, domain->name ));
593 static struct cache_entry *wcache_fetch_raw(char *kstr)
596 struct cache_entry *centry;
599 key = string_tdb_data(kstr);
600 data = tdb_fetch(wcache->tdb, key);
606 centry = SMB_XMALLOC_P(struct cache_entry);
607 centry->data = (unsigned char *)data.dptr;
608 centry->len = data.dsize;
611 if (centry->len < 8) {
612 /* huh? corrupt cache? */
613 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr));
618 centry->status = centry_ntstatus(centry);
619 centry->sequence_number = centry_uint32(centry);
625 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
626 number and return status
628 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
629 struct winbindd_domain *domain,
630 const char *format, ...) PRINTF_ATTRIBUTE(3,4);
631 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
632 struct winbindd_domain *domain,
633 const char *format, ...)
637 struct cache_entry *centry;
639 if (!winbindd_use_cache()) {
643 refresh_sequence_number(domain, false);
645 va_start(ap, format);
646 smb_xvasprintf(&kstr, format, ap);
649 centry = wcache_fetch_raw(kstr);
650 if (centry == NULL) {
655 if (centry_expired(domain, kstr, centry)) {
657 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
658 kstr, domain->name ));
665 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
666 kstr, domain->name ));
672 static void wcache_delete(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
673 static void wcache_delete(const char *format, ...)
679 va_start(ap, format);
680 smb_xvasprintf(&kstr, format, ap);
683 key = string_tdb_data(kstr);
685 tdb_delete(wcache->tdb, key);
690 make sure we have at least len bytes available in a centry
692 static void centry_expand(struct cache_entry *centry, uint32 len)
694 if (centry->len - centry->ofs >= len)
697 centry->data = SMB_REALLOC_ARRAY(centry->data, unsigned char,
700 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
701 smb_panic_fn("out of memory in centry_expand");
706 push a uint32 into a centry
708 static void centry_put_uint32(struct cache_entry *centry, uint32 v)
710 centry_expand(centry, 4);
711 SIVAL(centry->data, centry->ofs, v);
716 push a uint16 into a centry
718 static void centry_put_uint16(struct cache_entry *centry, uint16 v)
720 centry_expand(centry, 2);
721 SIVAL(centry->data, centry->ofs, v);
726 push a uint8 into a centry
728 static void centry_put_uint8(struct cache_entry *centry, uint8 v)
730 centry_expand(centry, 1);
731 SCVAL(centry->data, centry->ofs, v);
736 push a string into a centry
738 static void centry_put_string(struct cache_entry *centry, const char *s)
743 /* null strings are marked as len 0xFFFF */
744 centry_put_uint8(centry, 0xFF);
749 /* can't handle more than 254 char strings. Truncating is probably best */
751 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len));
754 centry_put_uint8(centry, len);
755 centry_expand(centry, len);
756 memcpy(centry->data + centry->ofs, s, len);
761 push a 16 byte hash into a centry - treat as 16 byte string.
763 static void centry_put_hash16(struct cache_entry *centry, const uint8 val[16])
765 centry_put_uint8(centry, 16);
766 centry_expand(centry, 16);
767 memcpy(centry->data + centry->ofs, val, 16);
771 static void centry_put_sid(struct cache_entry *centry, const DOM_SID *sid)
774 centry_put_string(centry, sid_to_fstring(sid_string, sid));
779 put NTSTATUS into a centry
781 static void centry_put_ntstatus(struct cache_entry *centry, NTSTATUS status)
783 uint32 status_value = NT_STATUS_V(status);
784 centry_put_uint32(centry, status_value);
789 push a NTTIME into a centry
791 static void centry_put_nttime(struct cache_entry *centry, NTTIME nt)
793 centry_expand(centry, 8);
794 SIVAL(centry->data, centry->ofs, nt & 0xFFFFFFFF);
796 SIVAL(centry->data, centry->ofs, nt >> 32);
801 push a time_t into a centry - use a 64 bit size.
802 NTTIME here is being used as a convenient 64-bit size.
804 static void centry_put_time(struct cache_entry *centry, time_t t)
806 NTTIME nt = (NTTIME)t;
807 centry_put_nttime(centry, nt);
811 start a centry for output. When finished, call centry_end()
813 struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status)
815 struct cache_entry *centry;
820 centry = SMB_XMALLOC_P(struct cache_entry);
822 centry->len = 8192; /* reasonable default */
823 centry->data = SMB_XMALLOC_ARRAY(uint8, centry->len);
825 centry->sequence_number = domain->sequence_number;
826 centry_put_ntstatus(centry, status);
827 centry_put_uint32(centry, centry->sequence_number);
832 finish a centry and write it to the tdb
834 static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
835 static void centry_end(struct cache_entry *centry, const char *format, ...)
841 if (!winbindd_use_cache()) {
845 va_start(ap, format);
846 smb_xvasprintf(&kstr, format, ap);
849 key = string_tdb_data(kstr);
850 data.dptr = centry->data;
851 data.dsize = centry->ofs;
853 tdb_store(wcache->tdb, key, data, TDB_REPLACE);
857 static void wcache_save_name_to_sid(struct winbindd_domain *domain,
858 NTSTATUS status, const char *domain_name,
859 const char *name, const DOM_SID *sid,
860 enum lsa_SidType type)
862 struct cache_entry *centry;
865 centry = centry_start(domain, status);
868 centry_put_uint32(centry, type);
869 centry_put_sid(centry, sid);
870 fstrcpy(uname, name);
872 centry_end(centry, "NS/%s/%s", domain_name, uname);
873 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name,
874 uname, sid_string_dbg(sid), nt_errstr(status)));
878 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
879 const DOM_SID *sid, const char *domain_name, const char *name, enum lsa_SidType type)
881 struct cache_entry *centry;
884 centry = centry_start(domain, status);
888 if (NT_STATUS_IS_OK(status)) {
889 centry_put_uint32(centry, type);
890 centry_put_string(centry, domain_name);
891 centry_put_string(centry, name);
894 centry_end(centry, "SN/%s", sid_to_fstring(sid_string, sid));
895 DEBUG(10,("wcache_save_sid_to_name: %s -> %s (%s)\n", sid_string,
896 name, nt_errstr(status)));
901 static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status,
902 struct wbint_userinfo *info)
904 struct cache_entry *centry;
907 if (is_null_sid(&info->user_sid)) {
911 centry = centry_start(domain, status);
914 centry_put_string(centry, info->acct_name);
915 centry_put_string(centry, info->full_name);
916 centry_put_string(centry, info->homedir);
917 centry_put_string(centry, info->shell);
918 centry_put_uint32(centry, info->primary_gid);
919 centry_put_sid(centry, &info->user_sid);
920 centry_put_sid(centry, &info->group_sid);
921 centry_end(centry, "U/%s", sid_to_fstring(sid_string,
923 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
927 static void wcache_save_lockout_policy(struct winbindd_domain *domain,
929 struct samr_DomInfo12 *lockout_policy)
931 struct cache_entry *centry;
933 centry = centry_start(domain, status);
937 centry_put_nttime(centry, lockout_policy->lockout_duration);
938 centry_put_nttime(centry, lockout_policy->lockout_window);
939 centry_put_uint16(centry, lockout_policy->lockout_threshold);
941 centry_end(centry, "LOC_POL/%s", domain->name);
943 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
950 static void wcache_save_password_policy(struct winbindd_domain *domain,
952 struct samr_DomInfo1 *policy)
954 struct cache_entry *centry;
956 centry = centry_start(domain, status);
960 centry_put_uint16(centry, policy->min_password_length);
961 centry_put_uint16(centry, policy->password_history_length);
962 centry_put_uint32(centry, policy->password_properties);
963 centry_put_nttime(centry, policy->max_password_age);
964 centry_put_nttime(centry, policy->min_password_age);
966 centry_end(centry, "PWD_POL/%s", domain->name);
968 DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
973 /***************************************************************************
974 ***************************************************************************/
976 static void wcache_save_username_alias(struct winbindd_domain *domain,
978 const char *name, const char *alias)
980 struct cache_entry *centry;
983 if ( (centry = centry_start(domain, status)) == NULL )
986 centry_put_string( centry, alias );
988 fstrcpy(uname, name);
990 centry_end(centry, "NSS/NA/%s", uname);
992 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name, alias ));
997 static void wcache_save_alias_username(struct winbindd_domain *domain,
999 const char *alias, const char *name)
1001 struct cache_entry *centry;
1004 if ( (centry = centry_start(domain, status)) == NULL )
1007 centry_put_string( centry, name );
1009 fstrcpy(uname, alias);
1011 centry_end(centry, "NSS/AN/%s", uname);
1013 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias, name ));
1015 centry_free(centry);
1018 /***************************************************************************
1019 ***************************************************************************/
1021 NTSTATUS resolve_username_to_alias( TALLOC_CTX *mem_ctx,
1022 struct winbindd_domain *domain,
1023 const char *name, char **alias )
1025 struct winbind_cache *cache = get_cache(domain);
1026 struct cache_entry *centry = NULL;
1030 if ( domain->internal )
1031 return NT_STATUS_NOT_SUPPORTED;
1036 if ( (upper_name = SMB_STRDUP(name)) == NULL )
1037 return NT_STATUS_NO_MEMORY;
1038 strupper_m(upper_name);
1040 centry = wcache_fetch(cache, domain, "NSS/NA/%s", upper_name);
1042 SAFE_FREE( upper_name );
1047 status = centry->status;
1049 if (!NT_STATUS_IS_OK(status)) {
1050 centry_free(centry);
1054 *alias = centry_string( centry, mem_ctx );
1056 centry_free(centry);
1058 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1059 name, *alias ? *alias : "(none)"));
1061 return (*alias) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1065 /* If its not in cache and we are offline, then fail */
1067 if ( get_global_winbindd_state_offline() || !domain->online ) {
1068 DEBUG(8,("resolve_username_to_alias: rejecting query "
1069 "in offline mode\n"));
1070 return NT_STATUS_NOT_FOUND;
1073 status = nss_map_to_alias( mem_ctx, domain->name, name, alias );
1075 if ( NT_STATUS_IS_OK( status ) ) {
1076 wcache_save_username_alias(domain, status, name, *alias);
1079 if ( NT_STATUS_EQUAL( status, NT_STATUS_NONE_MAPPED ) ) {
1080 wcache_save_username_alias(domain, status, name, "(NULL)");
1083 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1084 nt_errstr(status)));
1086 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1087 set_domain_offline( domain );
1093 /***************************************************************************
1094 ***************************************************************************/
1096 NTSTATUS resolve_alias_to_username( TALLOC_CTX *mem_ctx,
1097 struct winbindd_domain *domain,
1098 const char *alias, char **name )
1100 struct winbind_cache *cache = get_cache(domain);
1101 struct cache_entry *centry = NULL;
1105 if ( domain->internal )
1106 return NT_STATUS_NOT_SUPPORTED;
1111 if ( (upper_name = SMB_STRDUP(alias)) == NULL )
1112 return NT_STATUS_NO_MEMORY;
1113 strupper_m(upper_name);
1115 centry = wcache_fetch(cache, domain, "NSS/AN/%s", upper_name);
1117 SAFE_FREE( upper_name );
1122 status = centry->status;
1124 if (!NT_STATUS_IS_OK(status)) {
1125 centry_free(centry);
1129 *name = centry_string( centry, mem_ctx );
1131 centry_free(centry);
1133 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1134 alias, *name ? *name : "(none)"));
1136 return (*name) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1140 /* If its not in cache and we are offline, then fail */
1142 if ( get_global_winbindd_state_offline() || !domain->online ) {
1143 DEBUG(8,("resolve_alias_to_username: rejecting query "
1144 "in offline mode\n"));
1145 return NT_STATUS_NOT_FOUND;
1148 /* an alias cannot contain a domain prefix or '@' */
1150 if (strchr(alias, '\\') || strchr(alias, '@')) {
1151 DEBUG(10,("resolve_alias_to_username: skipping fully "
1152 "qualified name %s\n", alias));
1153 return NT_STATUS_OBJECT_NAME_INVALID;
1156 status = nss_map_from_alias( mem_ctx, domain->name, alias, name );
1158 if ( NT_STATUS_IS_OK( status ) ) {
1159 wcache_save_alias_username( domain, status, alias, *name );
1162 if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1163 wcache_save_alias_username(domain, status, alias, "(NULL)");
1166 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1167 nt_errstr(status)));
1169 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1170 set_domain_offline( domain );
1176 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const DOM_SID *sid)
1178 struct winbind_cache *cache = get_cache(domain);
1180 fstring key_str, tmp;
1184 return NT_STATUS_INTERNAL_DB_ERROR;
1187 if (is_null_sid(sid)) {
1188 return NT_STATUS_INVALID_SID;
1191 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1192 return NT_STATUS_INVALID_SID;
1195 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
1197 data = tdb_fetch(cache->tdb, string_tdb_data(key_str));
1199 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1202 SAFE_FREE(data.dptr);
1203 return NT_STATUS_OK;
1206 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1207 as new salted ones. */
1209 NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
1210 TALLOC_CTX *mem_ctx,
1212 const uint8 **cached_nt_pass,
1213 const uint8 **cached_salt)
1215 struct winbind_cache *cache = get_cache(domain);
1216 struct cache_entry *centry = NULL;
1223 return NT_STATUS_INTERNAL_DB_ERROR;
1226 if (is_null_sid(sid)) {
1227 return NT_STATUS_INVALID_SID;
1230 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1231 return NT_STATUS_INVALID_SID;
1234 /* Try and get a salted cred first. If we can't
1235 fall back to an unsalted cred. */
1237 centry = wcache_fetch(cache, domain, "CRED/%s",
1238 sid_to_fstring(tmp, sid));
1240 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1241 sid_string_dbg(sid)));
1242 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1245 t = centry_time(centry);
1247 /* In the salted case this isn't actually the nt_hash itself,
1248 but the MD5 of the salt + nt_hash. Let the caller
1249 sort this out. It can tell as we only return the cached_salt
1250 if we are returning a salted cred. */
1252 *cached_nt_pass = (const uint8 *)centry_hash16(centry, mem_ctx);
1253 if (*cached_nt_pass == NULL) {
1256 sid_to_fstring(sidstr, sid);
1258 /* Bad (old) cred cache. Delete and pretend we
1260 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1262 wcache_delete("CRED/%s", sidstr);
1263 centry_free(centry);
1264 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1267 /* We only have 17 bytes more data in the salted cred case. */
1268 if (centry->len - centry->ofs == 17) {
1269 *cached_salt = (const uint8 *)centry_hash16(centry, mem_ctx);
1271 *cached_salt = NULL;
1274 dump_data_pw("cached_nt_pass", *cached_nt_pass, NT_HASH_LEN);
1276 dump_data_pw("cached_salt", *cached_salt, NT_HASH_LEN);
1279 status = centry->status;
1281 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1282 sid_string_dbg(sid), nt_errstr(status) ));
1284 centry_free(centry);
1288 /* Store creds for a SID - only writes out new salted ones. */
1290 NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
1291 TALLOC_CTX *mem_ctx,
1293 const uint8 nt_pass[NT_HASH_LEN])
1295 struct cache_entry *centry;
1298 uint8 cred_salt[NT_HASH_LEN];
1299 uint8 salted_hash[NT_HASH_LEN];
1301 if (is_null_sid(sid)) {
1302 return NT_STATUS_INVALID_SID;
1305 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1306 return NT_STATUS_INVALID_SID;
1309 centry = centry_start(domain, NT_STATUS_OK);
1311 return NT_STATUS_INTERNAL_DB_ERROR;
1314 dump_data_pw("nt_pass", nt_pass, NT_HASH_LEN);
1316 centry_put_time(centry, time(NULL));
1318 /* Create a salt and then salt the hash. */
1319 generate_random_buffer(cred_salt, NT_HASH_LEN);
1320 E_md5hash(cred_salt, nt_pass, salted_hash);
1322 centry_put_hash16(centry, salted_hash);
1323 centry_put_hash16(centry, cred_salt);
1324 centry_end(centry, "CRED/%s", sid_to_fstring(sid_string, sid));
1326 DEBUG(10,("wcache_save_creds: %s\n", sid_string));
1328 centry_free(centry);
1330 return NT_STATUS_OK;
1334 /* Query display info. This is the basic user list fn */
1335 static NTSTATUS query_user_list(struct winbindd_domain *domain,
1336 TALLOC_CTX *mem_ctx,
1337 uint32 *num_entries,
1338 struct wbint_userinfo **info)
1340 struct winbind_cache *cache = get_cache(domain);
1341 struct cache_entry *centry = NULL;
1343 unsigned int i, retry;
1348 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1352 *num_entries = centry_uint32(centry);
1354 if (*num_entries == 0)
1357 (*info) = TALLOC_ARRAY(mem_ctx, struct wbint_userinfo, *num_entries);
1359 smb_panic_fn("query_user_list out of memory");
1361 for (i=0; i<(*num_entries); i++) {
1362 (*info)[i].acct_name = centry_string(centry, mem_ctx);
1363 (*info)[i].full_name = centry_string(centry, mem_ctx);
1364 (*info)[i].homedir = centry_string(centry, mem_ctx);
1365 (*info)[i].shell = centry_string(centry, mem_ctx);
1366 centry_sid(centry, &(*info)[i].user_sid);
1367 centry_sid(centry, &(*info)[i].group_sid);
1371 status = centry->status;
1373 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1374 domain->name, nt_errstr(status) ));
1376 centry_free(centry);
1383 /* Return status value returned by seq number check */
1385 if (!NT_STATUS_IS_OK(domain->last_status))
1386 return domain->last_status;
1388 /* Put the query_user_list() in a retry loop. There appears to be
1389 * some bug either with Windows 2000 or Samba's handling of large
1390 * rpc replies. This manifests itself as sudden disconnection
1391 * at a random point in the enumeration of a large (60k) user list.
1392 * The retry loop simply tries the operation again. )-: It's not
1393 * pretty but an acceptable workaround until we work out what the
1394 * real problem is. */
1399 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1402 status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
1403 if (!NT_STATUS_IS_OK(status)) {
1404 DEBUG(3, ("query_user_list: returned 0x%08x, "
1405 "retrying\n", NT_STATUS_V(status)));
1407 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1408 DEBUG(3, ("query_user_list: flushing "
1409 "connection cache\n"));
1410 invalidate_cm_connection(&domain->conn);
1413 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
1417 refresh_sequence_number(domain, false);
1418 centry = centry_start(domain, status);
1421 centry_put_uint32(centry, *num_entries);
1422 for (i=0; i<(*num_entries); i++) {
1423 centry_put_string(centry, (*info)[i].acct_name);
1424 centry_put_string(centry, (*info)[i].full_name);
1425 centry_put_string(centry, (*info)[i].homedir);
1426 centry_put_string(centry, (*info)[i].shell);
1427 centry_put_sid(centry, &(*info)[i].user_sid);
1428 centry_put_sid(centry, &(*info)[i].group_sid);
1429 if (domain->backend && domain->backend->consistent) {
1430 /* when the backend is consistent we can pre-prime some mappings */
1431 wcache_save_name_to_sid(domain, NT_STATUS_OK,
1433 (*info)[i].acct_name,
1434 &(*info)[i].user_sid,
1436 wcache_save_sid_to_name(domain, NT_STATUS_OK,
1437 &(*info)[i].user_sid,
1439 (*info)[i].acct_name,
1441 wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
1444 centry_end(centry, "UL/%s", domain->name);
1445 centry_free(centry);
1451 /* list all domain groups */
1452 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
1453 TALLOC_CTX *mem_ctx,
1454 uint32 *num_entries,
1455 struct acct_info **info)
1457 struct winbind_cache *cache = get_cache(domain);
1458 struct cache_entry *centry = NULL;
1465 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1469 *num_entries = centry_uint32(centry);
1471 if (*num_entries == 0)
1474 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1476 smb_panic_fn("enum_dom_groups out of memory");
1478 for (i=0; i<(*num_entries); i++) {
1479 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1480 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1481 (*info)[i].rid = centry_uint32(centry);
1485 status = centry->status;
1487 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1488 domain->name, nt_errstr(status) ));
1490 centry_free(centry);
1497 /* Return status value returned by seq number check */
1499 if (!NT_STATUS_IS_OK(domain->last_status))
1500 return domain->last_status;
1502 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1505 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1508 refresh_sequence_number(domain, false);
1509 centry = centry_start(domain, status);
1512 centry_put_uint32(centry, *num_entries);
1513 for (i=0; i<(*num_entries); i++) {
1514 centry_put_string(centry, (*info)[i].acct_name);
1515 centry_put_string(centry, (*info)[i].acct_desc);
1516 centry_put_uint32(centry, (*info)[i].rid);
1518 centry_end(centry, "GL/%s/domain", domain->name);
1519 centry_free(centry);
1525 /* list all domain groups */
1526 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
1527 TALLOC_CTX *mem_ctx,
1528 uint32 *num_entries,
1529 struct acct_info **info)
1531 struct winbind_cache *cache = get_cache(domain);
1532 struct cache_entry *centry = NULL;
1539 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1543 *num_entries = centry_uint32(centry);
1545 if (*num_entries == 0)
1548 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1550 smb_panic_fn("enum_dom_groups out of memory");
1552 for (i=0; i<(*num_entries); i++) {
1553 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1554 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1555 (*info)[i].rid = centry_uint32(centry);
1560 /* If we are returning cached data and the domain controller
1561 is down then we don't know whether the data is up to date
1562 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1565 if (wcache_server_down(domain)) {
1566 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1567 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1569 status = centry->status;
1571 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1572 domain->name, nt_errstr(status) ));
1574 centry_free(centry);
1581 /* Return status value returned by seq number check */
1583 if (!NT_STATUS_IS_OK(domain->last_status))
1584 return domain->last_status;
1586 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1589 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1592 refresh_sequence_number(domain, false);
1593 centry = centry_start(domain, status);
1596 centry_put_uint32(centry, *num_entries);
1597 for (i=0; i<(*num_entries); i++) {
1598 centry_put_string(centry, (*info)[i].acct_name);
1599 centry_put_string(centry, (*info)[i].acct_desc);
1600 centry_put_uint32(centry, (*info)[i].rid);
1602 centry_end(centry, "GL/%s/local", domain->name);
1603 centry_free(centry);
1609 NTSTATUS wcache_name_to_sid(struct winbindd_domain *domain,
1610 const char *domain_name,
1612 struct dom_sid *sid,
1613 enum lsa_SidType *type)
1615 struct winbind_cache *cache = get_cache(domain);
1616 struct cache_entry *centry;
1620 if (cache->tdb == NULL) {
1621 return NT_STATUS_NOT_FOUND;
1624 uname = talloc_strdup_upper(talloc_tos(), name);
1625 if (uname == NULL) {
1626 return NT_STATUS_NO_MEMORY;
1629 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1631 if (centry == NULL) {
1632 return NT_STATUS_NOT_FOUND;
1635 status = centry->status;
1636 if (NT_STATUS_IS_OK(status)) {
1637 *type = (enum lsa_SidType)centry_uint32(centry);
1638 centry_sid(centry, sid);
1641 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1642 "%s\n", domain->name, nt_errstr(status) ));
1644 centry_free(centry);
1648 /* convert a single name to a sid in a domain */
1649 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
1650 TALLOC_CTX *mem_ctx,
1651 const char *domain_name,
1655 enum lsa_SidType *type)
1659 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1660 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1666 /* If the seq number check indicated that there is a problem
1667 * with this DC, then return that status... except for
1668 * access_denied. This is special because the dc may be in
1669 * "restrict anonymous = 1" mode, in which case it will deny
1670 * most unauthenticated operations, but *will* allow the LSA
1671 * name-to-sid that we try as a fallback. */
1673 if (!(NT_STATUS_IS_OK(domain->last_status)
1674 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1675 return domain->last_status;
1677 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1680 status = domain->backend->name_to_sid(domain, mem_ctx, domain_name,
1681 name, flags, sid, type);
1684 refresh_sequence_number(domain, false);
1686 if (domain->online &&
1687 (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
1688 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1690 /* Only save the reverse mapping if this was not a UPN */
1691 if (!strchr(name, '@')) {
1692 strupper_m(CONST_DISCARD(char *,domain_name));
1693 strlower_m(CONST_DISCARD(char *,name));
1694 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1701 NTSTATUS wcache_sid_to_name(struct winbindd_domain *domain,
1702 const struct dom_sid *sid,
1703 TALLOC_CTX *mem_ctx,
1706 enum lsa_SidType *type)
1708 struct winbind_cache *cache = get_cache(domain);
1709 struct cache_entry *centry;
1713 if (cache->tdb == NULL) {
1714 return NT_STATUS_NOT_FOUND;
1717 sid_string = sid_string_tos(sid);
1718 if (sid_string == NULL) {
1719 return NT_STATUS_NO_MEMORY;
1722 centry = wcache_fetch(cache, domain, "SN/%s", sid_string);
1723 TALLOC_FREE(sid_string);
1724 if (centry == NULL) {
1725 return NT_STATUS_NOT_FOUND;
1728 if (NT_STATUS_IS_OK(centry->status)) {
1729 *type = (enum lsa_SidType)centry_uint32(centry);
1730 *domain_name = centry_string(centry, mem_ctx);
1731 *name = centry_string(centry, mem_ctx);
1734 status = centry->status;
1735 centry_free(centry);
1737 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1738 "%s\n", domain->name, nt_errstr(status) ));
1743 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1745 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
1746 TALLOC_CTX *mem_ctx,
1750 enum lsa_SidType *type)
1754 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
1756 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1761 *domain_name = NULL;
1763 /* If the seq number check indicated that there is a problem
1764 * with this DC, then return that status... except for
1765 * access_denied. This is special because the dc may be in
1766 * "restrict anonymous = 1" mode, in which case it will deny
1767 * most unauthenticated operations, but *will* allow the LSA
1768 * sid-to-name that we try as a fallback. */
1770 if (!(NT_STATUS_IS_OK(domain->last_status)
1771 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1772 return domain->last_status;
1774 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1777 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1780 refresh_sequence_number(domain, false);
1781 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1783 /* We can't save the name to sid mapping here, as with sid history a
1784 * later name2sid would give the wrong sid. */
1789 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
1790 TALLOC_CTX *mem_ctx,
1791 const DOM_SID *domain_sid,
1796 enum lsa_SidType **types)
1798 struct winbind_cache *cache = get_cache(domain);
1800 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1804 *domain_name = NULL;
1812 if (num_rids == 0) {
1813 return NT_STATUS_OK;
1816 *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
1817 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
1819 if ((*names == NULL) || (*types == NULL)) {
1820 result = NT_STATUS_NO_MEMORY;
1824 have_mapped = have_unmapped = false;
1826 for (i=0; i<num_rids; i++) {
1828 struct cache_entry *centry;
1831 if (!sid_compose(&sid, domain_sid, rids[i])) {
1832 result = NT_STATUS_INTERNAL_ERROR;
1836 centry = wcache_fetch(cache, domain, "SN/%s",
1837 sid_to_fstring(tmp, &sid));
1842 (*types)[i] = SID_NAME_UNKNOWN;
1843 (*names)[i] = talloc_strdup(*names, "");
1845 if (NT_STATUS_IS_OK(centry->status)) {
1848 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
1850 dom = centry_string(centry, mem_ctx);
1851 if (*domain_name == NULL) {
1857 (*names)[i] = centry_string(centry, *names);
1859 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
1860 have_unmapped = true;
1863 /* something's definitely wrong */
1864 result = centry->status;
1868 centry_free(centry);
1872 return NT_STATUS_NONE_MAPPED;
1874 if (!have_unmapped) {
1875 return NT_STATUS_OK;
1877 return STATUS_SOME_UNMAPPED;
1881 TALLOC_FREE(*names);
1882 TALLOC_FREE(*types);
1884 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
1885 rids, num_rids, domain_name,
1889 None of the queried rids has been found so save all negative entries
1891 if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
1892 for (i = 0; i < num_rids; i++) {
1894 const char *name = "";
1895 const enum lsa_SidType type = SID_NAME_UNKNOWN;
1896 NTSTATUS status = NT_STATUS_NONE_MAPPED;
1898 if (!sid_compose(&sid, domain_sid, rids[i])) {
1899 return NT_STATUS_INTERNAL_ERROR;
1902 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
1910 Some or all of the queried rids have been found.
1912 if (!NT_STATUS_IS_OK(result) &&
1913 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
1917 refresh_sequence_number(domain, false);
1919 for (i=0; i<num_rids; i++) {
1923 if (!sid_compose(&sid, domain_sid, rids[i])) {
1924 result = NT_STATUS_INTERNAL_ERROR;
1928 status = (*types)[i] == SID_NAME_UNKNOWN ?
1929 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
1931 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
1932 (*names)[i], (*types)[i]);
1938 TALLOC_FREE(*names);
1939 TALLOC_FREE(*types);
1943 NTSTATUS wcache_query_user(struct winbindd_domain *domain,
1944 TALLOC_CTX *mem_ctx,
1945 const struct dom_sid *user_sid,
1946 struct wbint_userinfo *info)
1948 struct winbind_cache *cache = get_cache(domain);
1949 struct cache_entry *centry = NULL;
1953 if (cache->tdb == NULL) {
1954 return NT_STATUS_NOT_FOUND;
1957 sid_string = sid_string_tos(user_sid);
1958 if (sid_string == NULL) {
1959 return NT_STATUS_NO_MEMORY;
1962 centry = wcache_fetch(cache, domain, "U/%s", sid_string);
1963 TALLOC_FREE(sid_string);
1964 if (centry == NULL) {
1965 return NT_STATUS_NOT_FOUND;
1969 * If we have an access denied cache entry and a cached info3
1970 * in the samlogon cache then do a query. This will force the
1971 * rpc back end to return the info3 data.
1974 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED) &&
1975 netsamlogon_cache_have(user_sid)) {
1976 DEBUG(10, ("query_user: cached access denied and have cached "
1978 domain->last_status = NT_STATUS_OK;
1979 centry_free(centry);
1980 return NT_STATUS_NOT_FOUND;
1983 /* if status is not ok then this is a negative hit
1984 and the rest of the data doesn't matter */
1985 status = centry->status;
1986 if (NT_STATUS_IS_OK(status)) {
1987 info->acct_name = centry_string(centry, mem_ctx);
1988 info->full_name = centry_string(centry, mem_ctx);
1989 info->homedir = centry_string(centry, mem_ctx);
1990 info->shell = centry_string(centry, mem_ctx);
1991 info->primary_gid = centry_uint32(centry);
1992 centry_sid(centry, &info->user_sid);
1993 centry_sid(centry, &info->group_sid);
1996 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
1997 "%s\n", domain->name, nt_errstr(status) ));
1999 centry_free(centry);
2003 /* Lookup user information from a rid */
2004 static NTSTATUS query_user(struct winbindd_domain *domain,
2005 TALLOC_CTX *mem_ctx,
2006 const DOM_SID *user_sid,
2007 struct wbint_userinfo *info)
2011 status = wcache_query_user(domain, mem_ctx, user_sid, info);
2012 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2018 /* Return status value returned by seq number check */
2020 if (!NT_STATUS_IS_OK(domain->last_status))
2021 return domain->last_status;
2023 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2026 status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
2029 refresh_sequence_number(domain, false);
2030 wcache_save_user(domain, status, info);
2035 NTSTATUS wcache_lookup_usergroups(struct winbindd_domain *domain,
2036 TALLOC_CTX *mem_ctx,
2037 const struct dom_sid *user_sid,
2038 uint32_t *pnum_sids,
2039 struct dom_sid **psids)
2041 struct winbind_cache *cache = get_cache(domain);
2042 struct cache_entry *centry = NULL;
2044 uint32_t i, num_sids;
2045 struct dom_sid *sids;
2048 if (cache->tdb == NULL) {
2049 return NT_STATUS_NOT_FOUND;
2052 centry = wcache_fetch(cache, domain, "UG/%s",
2053 sid_to_fstring(sid_string, user_sid));
2054 if (centry == NULL) {
2055 return NT_STATUS_NOT_FOUND;
2058 /* If we have an access denied cache entry and a cached info3 in the
2059 samlogon cache then do a query. This will force the rpc back end
2060 to return the info3 data. */
2062 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)
2063 && netsamlogon_cache_have(user_sid)) {
2064 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2066 domain->last_status = NT_STATUS_OK;
2067 centry_free(centry);
2068 return NT_STATUS_NOT_FOUND;
2071 num_sids = centry_uint32(centry);
2072 sids = talloc_array(mem_ctx, struct dom_sid, num_sids);
2074 return NT_STATUS_NO_MEMORY;
2077 for (i=0; i<num_sids; i++) {
2078 centry_sid(centry, &sids[i]);
2081 status = centry->status;
2083 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2084 "status: %s\n", domain->name, nt_errstr(status)));
2086 centry_free(centry);
2088 *pnum_sids = num_sids;
2093 /* Lookup groups a user is a member of. */
2094 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
2095 TALLOC_CTX *mem_ctx,
2096 const DOM_SID *user_sid,
2097 uint32 *num_groups, DOM_SID **user_gids)
2099 struct cache_entry *centry = NULL;
2104 status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2105 num_groups, user_gids);
2106 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2111 (*user_gids) = NULL;
2113 /* Return status value returned by seq number check */
2115 if (!NT_STATUS_IS_OK(domain->last_status))
2116 return domain->last_status;
2118 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2121 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
2123 if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
2127 refresh_sequence_number(domain, false);
2128 centry = centry_start(domain, status);
2132 centry_put_uint32(centry, *num_groups);
2133 for (i=0; i<(*num_groups); i++) {
2134 centry_put_sid(centry, &(*user_gids)[i]);
2137 centry_end(centry, "UG/%s", sid_to_fstring(sid_string, user_sid));
2138 centry_free(centry);
2144 static char *wcache_make_sidlist(TALLOC_CTX *mem_ctx, uint32_t num_sids,
2145 const struct dom_sid *sids)
2150 sidlist = talloc_strdup(mem_ctx, "");
2151 if (sidlist == NULL) {
2154 for (i=0; i<num_sids; i++) {
2156 sidlist = talloc_asprintf_append_buffer(
2157 sidlist, "/%s", sid_to_fstring(tmp, &sids[i]));
2158 if (sidlist == NULL) {
2165 NTSTATUS wcache_lookup_useraliases(struct winbindd_domain *domain,
2166 TALLOC_CTX *mem_ctx, uint32_t num_sids,
2167 const struct dom_sid *sids,
2168 uint32_t *pnum_aliases, uint32_t **paliases)
2170 struct winbind_cache *cache = get_cache(domain);
2171 struct cache_entry *centry = NULL;
2172 uint32_t num_aliases;
2178 if (cache->tdb == NULL) {
2179 return NT_STATUS_NOT_FOUND;
2182 if (num_sids == 0) {
2185 return NT_STATUS_OK;
2188 /* We need to cache indexed by the whole list of SIDs, the aliases
2189 * resulting might come from any of the SIDs. */
2191 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2192 if (sidlist == NULL) {
2193 return NT_STATUS_NO_MEMORY;
2196 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
2197 TALLOC_FREE(sidlist);
2198 if (centry == NULL) {
2199 return NT_STATUS_NOT_FOUND;
2202 num_aliases = centry_uint32(centry);
2203 aliases = talloc_array(mem_ctx, uint32_t, num_aliases);
2204 if (aliases == NULL) {
2205 centry_free(centry);
2206 return NT_STATUS_NO_MEMORY;
2209 for (i=0; i<num_aliases; i++) {
2210 aliases[i] = centry_uint32(centry);
2213 status = centry->status;
2215 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2216 "status %s\n", domain->name, nt_errstr(status)));
2218 centry_free(centry);
2220 *pnum_aliases = num_aliases;
2221 *paliases = aliases;
2226 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
2227 TALLOC_CTX *mem_ctx,
2228 uint32 num_sids, const DOM_SID *sids,
2229 uint32 *num_aliases, uint32 **alias_rids)
2231 struct cache_entry *centry = NULL;
2236 status = wcache_lookup_useraliases(domain, mem_ctx, num_sids, sids,
2237 num_aliases, alias_rids);
2238 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2243 (*alias_rids) = NULL;
2245 if (!NT_STATUS_IS_OK(domain->last_status))
2246 return domain->last_status;
2248 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2249 "for domain %s\n", domain->name ));
2251 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2252 if (sidlist == NULL) {
2253 return NT_STATUS_NO_MEMORY;
2256 status = domain->backend->lookup_useraliases(domain, mem_ctx,
2258 num_aliases, alias_rids);
2261 refresh_sequence_number(domain, false);
2262 centry = centry_start(domain, status);
2265 centry_put_uint32(centry, *num_aliases);
2266 for (i=0; i<(*num_aliases); i++)
2267 centry_put_uint32(centry, (*alias_rids)[i]);
2268 centry_end(centry, "UA%s", sidlist);
2269 centry_free(centry);
2275 NTSTATUS wcache_lookup_groupmem(struct winbindd_domain *domain,
2276 TALLOC_CTX *mem_ctx,
2277 const struct dom_sid *group_sid,
2278 uint32_t *num_names,
2279 struct dom_sid **sid_mem, char ***names,
2280 uint32_t **name_types)
2282 struct winbind_cache *cache = get_cache(domain);
2283 struct cache_entry *centry = NULL;
2288 if (cache->tdb == NULL) {
2289 return NT_STATUS_NOT_FOUND;
2292 sid_string = sid_string_tos(group_sid);
2293 if (sid_string == NULL) {
2294 return NT_STATUS_NO_MEMORY;
2297 centry = wcache_fetch(cache, domain, "GM/%s", sid_string);
2298 TALLOC_FREE(sid_string);
2299 if (centry == NULL) {
2300 return NT_STATUS_NOT_FOUND;
2307 *num_names = centry_uint32(centry);
2308 if (*num_names == 0) {
2309 return NT_STATUS_OK;
2312 *sid_mem = talloc_array(mem_ctx, DOM_SID, *num_names);
2313 *names = talloc_array(mem_ctx, char *, *num_names);
2314 *name_types = talloc_array(mem_ctx, uint32, *num_names);
2316 if ((*sid_mem == NULL) || (*names == NULL) || (*name_types == NULL)) {
2317 TALLOC_FREE(*sid_mem);
2318 TALLOC_FREE(*names);
2319 TALLOC_FREE(*name_types);
2320 return NT_STATUS_NO_MEMORY;
2323 for (i=0; i<(*num_names); i++) {
2324 centry_sid(centry, &(*sid_mem)[i]);
2325 (*names)[i] = centry_string(centry, mem_ctx);
2326 (*name_types)[i] = centry_uint32(centry);
2329 status = centry->status;
2331 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2332 "status: %s\n", domain->name, nt_errstr(status)));
2334 centry_free(centry);
2338 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
2339 TALLOC_CTX *mem_ctx,
2340 const DOM_SID *group_sid, uint32 *num_names,
2341 DOM_SID **sid_mem, char ***names,
2342 uint32 **name_types)
2344 struct cache_entry *centry = NULL;
2349 status = wcache_lookup_groupmem(domain, mem_ctx, group_sid, num_names,
2350 sid_mem, names, name_types);
2351 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2358 (*name_types) = NULL;
2360 /* Return status value returned by seq number check */
2362 if (!NT_STATUS_IS_OK(domain->last_status))
2363 return domain->last_status;
2365 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2368 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid, num_names,
2369 sid_mem, names, name_types);
2372 refresh_sequence_number(domain, false);
2373 centry = centry_start(domain, status);
2376 centry_put_uint32(centry, *num_names);
2377 for (i=0; i<(*num_names); i++) {
2378 centry_put_sid(centry, &(*sid_mem)[i]);
2379 centry_put_string(centry, (*names)[i]);
2380 centry_put_uint32(centry, (*name_types)[i]);
2382 centry_end(centry, "GM/%s", sid_to_fstring(sid_string, group_sid));
2383 centry_free(centry);
2389 /* find the sequence number for a domain */
2390 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
2392 refresh_sequence_number(domain, false);
2394 *seq = domain->sequence_number;
2396 return NT_STATUS_OK;
2399 /* enumerate trusted domains
2400 * (we need to have the list of trustdoms in the cache when we go offline) -
2402 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
2403 TALLOC_CTX *mem_ctx,
2404 uint32 *num_domains,
2409 struct winbind_cache *cache = get_cache(domain);
2410 struct cache_entry *centry = NULL;
2417 centry = wcache_fetch(cache, domain, "TRUSTDOMS/%s", domain->name);
2423 *num_domains = centry_uint32(centry);
2426 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
2427 (*alt_names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
2428 (*dom_sids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
2430 if (! (*dom_sids) || ! (*names) || ! (*alt_names)) {
2431 smb_panic_fn("trusted_domains out of memory");
2435 (*alt_names) = NULL;
2439 for (i=0; i<(*num_domains); i++) {
2440 (*names)[i] = centry_string(centry, mem_ctx);
2441 (*alt_names)[i] = centry_string(centry, mem_ctx);
2442 if (!centry_sid(centry, &(*dom_sids)[i])) {
2443 sid_copy(&(*dom_sids)[i], &global_sid_NULL);
2447 status = centry->status;
2449 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
2450 domain->name, *num_domains, nt_errstr(status) ));
2452 centry_free(centry);
2459 (*alt_names) = NULL;
2461 /* Return status value returned by seq number check */
2463 if (!NT_STATUS_IS_OK(domain->last_status))
2464 return domain->last_status;
2466 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2469 status = domain->backend->trusted_domains(domain, mem_ctx, num_domains,
2470 names, alt_names, dom_sids);
2472 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2473 * so that the generic centry handling still applies correctly -
2476 if (!NT_STATUS_IS_ERR(status)) {
2477 status = NT_STATUS_OK;
2481 #if 0 /* Disabled as we want the trust dom list to be managed by
2482 the main parent and always to make the query. --jerry */
2485 refresh_sequence_number(domain, false);
2487 centry = centry_start(domain, status);
2491 centry_put_uint32(centry, *num_domains);
2493 for (i=0; i<(*num_domains); i++) {
2494 centry_put_string(centry, (*names)[i]);
2495 centry_put_string(centry, (*alt_names)[i]);
2496 centry_put_sid(centry, &(*dom_sids)[i]);
2499 centry_end(centry, "TRUSTDOMS/%s", domain->name);
2501 centry_free(centry);
2509 /* get lockout policy */
2510 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
2511 TALLOC_CTX *mem_ctx,
2512 struct samr_DomInfo12 *policy)
2514 struct winbind_cache *cache = get_cache(domain);
2515 struct cache_entry *centry = NULL;
2521 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2526 policy->lockout_duration = centry_nttime(centry);
2527 policy->lockout_window = centry_nttime(centry);
2528 policy->lockout_threshold = centry_uint16(centry);
2530 status = centry->status;
2532 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2533 domain->name, nt_errstr(status) ));
2535 centry_free(centry);
2539 ZERO_STRUCTP(policy);
2541 /* Return status value returned by seq number check */
2543 if (!NT_STATUS_IS_OK(domain->last_status))
2544 return domain->last_status;
2546 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2549 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2552 refresh_sequence_number(domain, false);
2553 wcache_save_lockout_policy(domain, status, policy);
2558 /* get password policy */
2559 static NTSTATUS password_policy(struct winbindd_domain *domain,
2560 TALLOC_CTX *mem_ctx,
2561 struct samr_DomInfo1 *policy)
2563 struct winbind_cache *cache = get_cache(domain);
2564 struct cache_entry *centry = NULL;
2570 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2575 policy->min_password_length = centry_uint16(centry);
2576 policy->password_history_length = centry_uint16(centry);
2577 policy->password_properties = centry_uint32(centry);
2578 policy->max_password_age = centry_nttime(centry);
2579 policy->min_password_age = centry_nttime(centry);
2581 status = centry->status;
2583 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2584 domain->name, nt_errstr(status) ));
2586 centry_free(centry);
2590 ZERO_STRUCTP(policy);
2592 /* Return status value returned by seq number check */
2594 if (!NT_STATUS_IS_OK(domain->last_status))
2595 return domain->last_status;
2597 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2600 status = domain->backend->password_policy(domain, mem_ctx, policy);
2603 refresh_sequence_number(domain, false);
2604 if (NT_STATUS_IS_OK(status)) {
2605 wcache_save_password_policy(domain, status, policy);
2612 /* Invalidate cached user and group lists coherently */
2614 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2617 if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
2618 strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
2619 tdb_delete(the_tdb, kbuf);
2624 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2626 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
2627 struct netr_SamInfo3 *info3)
2630 fstring key_str, sid_string;
2631 struct winbind_cache *cache;
2633 /* dont clear cached U/SID and UG/SID entries when we want to logon
2636 if (lp_winbind_offline_logon()) {
2643 cache = get_cache(domain);
2649 sid_copy(&sid, info3->base.domain_sid);
2650 sid_append_rid(&sid, info3->base.rid);
2652 /* Clear U/SID cache entry */
2653 fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, &sid));
2654 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
2655 tdb_delete(cache->tdb, string_tdb_data(key_str));
2657 /* Clear UG/SID cache entry */
2658 fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, &sid));
2659 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
2660 tdb_delete(cache->tdb, string_tdb_data(key_str));
2662 /* Samba/winbindd never needs this. */
2663 netsamlogon_clear_cached_user(info3);
2666 bool wcache_invalidate_cache(void)
2668 struct winbindd_domain *domain;
2670 for (domain = domain_list(); domain; domain = domain->next) {
2671 struct winbind_cache *cache = get_cache(domain);
2673 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2674 "entries for %s\n", domain->name));
2677 tdb_traverse(cache->tdb, traverse_fn, NULL);
2686 bool init_wcache(void)
2688 if (wcache == NULL) {
2689 wcache = SMB_XMALLOC_P(struct winbind_cache);
2690 ZERO_STRUCTP(wcache);
2693 if (wcache->tdb != NULL)
2696 /* when working offline we must not clear the cache on restart */
2697 wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
2698 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2699 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
2700 O_RDWR|O_CREAT, 0600);
2702 if (wcache->tdb == NULL) {
2703 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2710 /************************************************************************
2711 This is called by the parent to initialize the cache file.
2712 We don't need sophisticated locking here as we know we're the
2714 ************************************************************************/
2716 bool initialize_winbindd_cache(void)
2718 bool cache_bad = true;
2721 if (!init_wcache()) {
2722 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
2726 /* Check version number. */
2727 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
2728 vers == WINBINDD_CACHE_VERSION) {
2733 DEBUG(0,("initialize_winbindd_cache: clearing cache "
2734 "and re-creating with version number %d\n",
2735 WINBINDD_CACHE_VERSION ));
2737 tdb_close(wcache->tdb);
2740 if (unlink(cache_path("winbindd_cache.tdb")) == -1) {
2741 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
2742 cache_path("winbindd_cache.tdb"),
2746 if (!init_wcache()) {
2747 DEBUG(0,("initialize_winbindd_cache: re-initialization "
2748 "init_wcache failed.\n"));
2752 /* Write the version. */
2753 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
2754 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
2755 tdb_errorstr(wcache->tdb) ));
2760 tdb_close(wcache->tdb);
2765 void close_winbindd_cache(void)
2771 tdb_close(wcache->tdb);
2776 bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
2777 char **domain_name, char **name,
2778 enum lsa_SidType *type)
2780 struct winbindd_domain *domain;
2783 domain = find_lookup_domain_from_sid(sid);
2784 if (domain == NULL) {
2787 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
2789 return NT_STATUS_IS_OK(status);
2792 bool lookup_cached_name(TALLOC_CTX *mem_ctx,
2793 const char *domain_name,
2796 enum lsa_SidType *type)
2798 struct winbindd_domain *domain;
2800 bool original_online_state;
2802 domain = find_lookup_domain_from_name(domain_name);
2803 if (domain == NULL) {
2807 /* If we are doing a cached logon, temporarily set the domain
2808 offline so the cache won't expire the entry */
2810 original_online_state = domain->online;
2811 domain->online = false;
2812 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
2813 domain->online = original_online_state;
2815 return NT_STATUS_IS_OK(status);
2818 void cache_name2sid(struct winbindd_domain *domain,
2819 const char *domain_name, const char *name,
2820 enum lsa_SidType type, const DOM_SID *sid)
2822 refresh_sequence_number(domain, false);
2823 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
2828 * The original idea that this cache only contains centries has
2829 * been blurred - now other stuff gets put in here. Ensure we
2830 * ignore these things on cleanup.
2833 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
2834 TDB_DATA dbuf, void *state)
2836 struct cache_entry *centry;
2838 if (is_non_centry_key(kbuf)) {
2842 centry = wcache_fetch_raw((char *)kbuf.dptr);
2847 if (!NT_STATUS_IS_OK(centry->status)) {
2848 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
2849 tdb_delete(the_tdb, kbuf);
2852 centry_free(centry);
2856 /* flush the cache */
2857 void wcache_flush_cache(void)
2862 tdb_close(wcache->tdb);
2865 if (!winbindd_use_cache()) {
2869 /* when working offline we must not clear the cache on restart */
2870 wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
2871 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2872 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
2873 O_RDWR|O_CREAT, 0600);
2876 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2880 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
2882 DEBUG(10,("wcache_flush_cache success\n"));
2885 /* Count cached creds */
2887 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2890 int *cred_count = (int*)state;
2892 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
2898 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
2900 struct winbind_cache *cache = get_cache(domain);
2905 return NT_STATUS_INTERNAL_DB_ERROR;
2908 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
2910 return NT_STATUS_OK;
2914 struct cred_list *prev, *next;
2919 static struct cred_list *wcache_cred_list;
2921 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2924 struct cred_list *cred;
2926 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
2928 cred = SMB_MALLOC_P(struct cred_list);
2930 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2936 /* save a copy of the key */
2938 fstrcpy(cred->name, (const char *)kbuf.dptr);
2939 DLIST_ADD(wcache_cred_list, cred);
2945 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const DOM_SID *sid)
2947 struct winbind_cache *cache = get_cache(domain);
2950 struct cred_list *cred, *oldest = NULL;
2953 return NT_STATUS_INTERNAL_DB_ERROR;
2956 /* we possibly already have an entry */
2957 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
2959 fstring key_str, tmp;
2961 DEBUG(11,("we already have an entry, deleting that\n"));
2963 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
2965 tdb_delete(cache->tdb, string_tdb_data(key_str));
2967 return NT_STATUS_OK;
2970 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
2972 return NT_STATUS_OK;
2973 } else if ((ret == -1) || (wcache_cred_list == NULL)) {
2974 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2977 ZERO_STRUCTP(oldest);
2979 for (cred = wcache_cred_list; cred; cred = cred->next) {
2984 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
2986 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
2988 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
2992 t = IVAL(data.dptr, 0);
2993 SAFE_FREE(data.dptr);
2996 oldest = SMB_MALLOC_P(struct cred_list);
2997 if (oldest == NULL) {
2998 status = NT_STATUS_NO_MEMORY;
3002 fstrcpy(oldest->name, cred->name);
3003 oldest->created = t;
3007 if (t < oldest->created) {
3008 fstrcpy(oldest->name, cred->name);
3009 oldest->created = t;
3013 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
3014 status = NT_STATUS_OK;
3016 status = NT_STATUS_UNSUCCESSFUL;
3019 SAFE_FREE(wcache_cred_list);
3025 /* Change the global online/offline state. */
3026 bool set_global_winbindd_state_offline(void)
3030 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3032 /* Only go offline if someone has created
3033 the key "WINBINDD_OFFLINE" in the cache tdb. */
3035 if (wcache == NULL || wcache->tdb == NULL) {
3036 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3040 if (!lp_winbind_offline_logon()) {
3041 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3045 if (global_winbindd_offline_state) {
3046 /* Already offline. */
3050 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
3052 if (!data.dptr || data.dsize != 4) {
3053 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3054 SAFE_FREE(data.dptr);
3057 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3058 global_winbindd_offline_state = true;
3059 SAFE_FREE(data.dptr);
3064 void set_global_winbindd_state_online(void)
3066 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3068 if (!lp_winbind_offline_logon()) {
3069 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3073 if (!global_winbindd_offline_state) {
3074 /* Already online. */
3077 global_winbindd_offline_state = false;
3083 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3084 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
3087 bool get_global_winbindd_state_offline(void)
3089 return global_winbindd_offline_state;
3092 /***********************************************************************
3093 Validate functions for all possible cache tdb keys.
3094 ***********************************************************************/
3096 static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
3097 struct tdb_validation_status *state)
3099 struct cache_entry *centry;
3101 centry = SMB_XMALLOC_P(struct cache_entry);
3102 centry->data = (unsigned char *)memdup(data.dptr, data.dsize);
3103 if (!centry->data) {
3107 centry->len = data.dsize;
3110 if (centry->len < 8) {
3111 /* huh? corrupt cache? */
3112 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr));
3113 centry_free(centry);
3114 state->bad_entry = true;
3115 state->success = false;
3119 centry->status = NT_STATUS(centry_uint32(centry));
3120 centry->sequence_number = centry_uint32(centry);
3124 static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3125 struct tdb_validation_status *state)
3127 if (dbuf.dsize != 8) {
3128 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3129 keystr, (unsigned int)dbuf.dsize ));
3130 state->bad_entry = true;
3136 static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3137 struct tdb_validation_status *state)
3139 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3144 (void)centry_uint32(centry);
3145 if (NT_STATUS_IS_OK(centry->status)) {
3147 (void)centry_sid(centry, &sid);
3150 centry_free(centry);
3152 if (!(state->success)) {
3155 DEBUG(10,("validate_ns: %s ok\n", keystr));
3159 static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3160 struct tdb_validation_status *state)
3162 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3167 if (NT_STATUS_IS_OK(centry->status)) {
3168 (void)centry_uint32(centry);
3169 (void)centry_string(centry, mem_ctx);
3170 (void)centry_string(centry, mem_ctx);
3173 centry_free(centry);
3175 if (!(state->success)) {
3178 DEBUG(10,("validate_sn: %s ok\n", keystr));
3182 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3183 struct tdb_validation_status *state)
3185 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3192 (void)centry_string(centry, mem_ctx);
3193 (void)centry_string(centry, mem_ctx);
3194 (void)centry_string(centry, mem_ctx);
3195 (void)centry_string(centry, mem_ctx);
3196 (void)centry_uint32(centry);
3197 (void)centry_sid(centry, &sid);
3198 (void)centry_sid(centry, &sid);
3200 centry_free(centry);
3202 if (!(state->success)) {
3205 DEBUG(10,("validate_u: %s ok\n", keystr));
3209 static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3210 struct tdb_validation_status *state)
3212 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3218 (void)centry_nttime(centry);
3219 (void)centry_nttime(centry);
3220 (void)centry_uint16(centry);
3222 centry_free(centry);
3224 if (!(state->success)) {
3227 DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
3231 static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3232 struct tdb_validation_status *state)
3234 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3240 (void)centry_uint16(centry);
3241 (void)centry_uint16(centry);
3242 (void)centry_uint32(centry);
3243 (void)centry_nttime(centry);
3244 (void)centry_nttime(centry);
3246 centry_free(centry);
3248 if (!(state->success)) {
3251 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
3255 static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3256 struct tdb_validation_status *state)
3258 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3264 (void)centry_time(centry);
3265 (void)centry_hash16(centry, mem_ctx);
3267 /* We only have 17 bytes more data in the salted cred case. */
3268 if (centry->len - centry->ofs == 17) {
3269 (void)centry_hash16(centry, mem_ctx);
3272 centry_free(centry);
3274 if (!(state->success)) {
3277 DEBUG(10,("validate_cred: %s ok\n", keystr));
3281 static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3282 struct tdb_validation_status *state)
3284 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3285 int32 num_entries, i;
3291 num_entries = (int32)centry_uint32(centry);
3293 for (i=0; i< num_entries; i++) {
3295 (void)centry_string(centry, mem_ctx);
3296 (void)centry_string(centry, mem_ctx);
3297 (void)centry_string(centry, mem_ctx);
3298 (void)centry_string(centry, mem_ctx);
3299 (void)centry_sid(centry, &sid);
3300 (void)centry_sid(centry, &sid);
3303 centry_free(centry);
3305 if (!(state->success)) {
3308 DEBUG(10,("validate_ul: %s ok\n", keystr));
3312 static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3313 struct tdb_validation_status *state)
3315 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3316 int32 num_entries, i;
3322 num_entries = centry_uint32(centry);
3324 for (i=0; i< num_entries; i++) {
3325 (void)centry_string(centry, mem_ctx);
3326 (void)centry_string(centry, mem_ctx);
3327 (void)centry_uint32(centry);
3330 centry_free(centry);
3332 if (!(state->success)) {
3335 DEBUG(10,("validate_gl: %s ok\n", keystr));
3339 static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3340 struct tdb_validation_status *state)
3342 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3343 int32 num_groups, i;
3349 num_groups = centry_uint32(centry);
3351 for (i=0; i< num_groups; i++) {
3353 centry_sid(centry, &sid);
3356 centry_free(centry);
3358 if (!(state->success)) {
3361 DEBUG(10,("validate_ug: %s ok\n", keystr));
3365 static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3366 struct tdb_validation_status *state)
3368 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3369 int32 num_aliases, i;
3375 num_aliases = centry_uint32(centry);
3377 for (i=0; i < num_aliases; i++) {
3378 (void)centry_uint32(centry);
3381 centry_free(centry);
3383 if (!(state->success)) {
3386 DEBUG(10,("validate_ua: %s ok\n", keystr));
3390 static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3391 struct tdb_validation_status *state)
3393 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3400 num_names = centry_uint32(centry);
3402 for (i=0; i< num_names; i++) {
3404 centry_sid(centry, &sid);
3405 (void)centry_string(centry, mem_ctx);
3406 (void)centry_uint32(centry);
3409 centry_free(centry);
3411 if (!(state->success)) {
3414 DEBUG(10,("validate_gm: %s ok\n", keystr));
3418 static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3419 struct tdb_validation_status *state)
3421 /* Can't say anything about this other than must be nonzero. */
3422 if (dbuf.dsize == 0) {
3423 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3425 state->bad_entry = true;
3426 state->success = false;
3430 DEBUG(10,("validate_dr: %s ok\n", keystr));
3434 static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3435 struct tdb_validation_status *state)
3437 /* Can't say anything about this other than must be nonzero. */
3438 if (dbuf.dsize == 0) {
3439 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3441 state->bad_entry = true;
3442 state->success = false;
3446 DEBUG(10,("validate_de: %s ok\n", keystr));
3450 static int validate_pwinfo(TALLOC_CTX *mem_ctx, const char *keystr,
3451 TDB_DATA dbuf, struct tdb_validation_status *state)
3453 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3459 (void)centry_string(centry, mem_ctx);
3460 (void)centry_string(centry, mem_ctx);
3461 (void)centry_string(centry, mem_ctx);
3462 (void)centry_uint32(centry);
3464 centry_free(centry);
3466 if (!(state->success)) {
3469 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3473 static int validate_nss_an(TALLOC_CTX *mem_ctx, const char *keystr,
3475 struct tdb_validation_status *state)
3477 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3483 (void)centry_string( centry, mem_ctx );
3485 centry_free(centry);
3487 if (!(state->success)) {
3490 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3494 static int validate_nss_na(TALLOC_CTX *mem_ctx, const char *keystr,
3496 struct tdb_validation_status *state)
3498 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3504 (void)centry_string( centry, mem_ctx );
3506 centry_free(centry);
3508 if (!(state->success)) {
3511 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3515 static int validate_trustdoms(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3516 struct tdb_validation_status *state)
3518 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3519 int32 num_domains, i;
3525 num_domains = centry_uint32(centry);
3527 for (i=0; i< num_domains; i++) {
3529 (void)centry_string(centry, mem_ctx);
3530 (void)centry_string(centry, mem_ctx);
3531 (void)centry_sid(centry, &sid);
3534 centry_free(centry);
3536 if (!(state->success)) {
3539 DEBUG(10,("validate_trustdoms: %s ok\n", keystr));
3543 static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
3545 struct tdb_validation_status *state)
3547 if (dbuf.dsize == 0) {
3548 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3549 "key %s (len ==0) ?\n", keystr));
3550 state->bad_entry = true;
3551 state->success = false;
3555 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
3556 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3560 static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3561 struct tdb_validation_status *state)
3563 if (dbuf.dsize != 4) {
3564 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3565 keystr, (unsigned int)dbuf.dsize ));
3566 state->bad_entry = true;
3567 state->success = false;
3570 DEBUG(10,("validate_offline: %s ok\n", keystr));
3574 static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3575 struct tdb_validation_status *state)
3577 if (dbuf.dsize != 4) {
3578 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3579 "key %s (len %u != 4) ?\n",
3580 keystr, (unsigned int)dbuf.dsize));
3581 state->bad_entry = true;
3582 state->success = false;
3586 DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
3590 /***********************************************************************
3591 A list of all possible cache tdb keys with associated validation
3593 ***********************************************************************/
3595 struct key_val_struct {
3596 const char *keyname;
3597 int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
3599 {"SEQNUM/", validate_seqnum},
3600 {"NS/", validate_ns},
3601 {"SN/", validate_sn},
3603 {"LOC_POL/", validate_loc_pol},
3604 {"PWD_POL/", validate_pwd_pol},
3605 {"CRED/", validate_cred},
3606 {"UL/", validate_ul},
3607 {"GL/", validate_gl},
3608 {"UG/", validate_ug},
3609 {"UA", validate_ua},
3610 {"GM/", validate_gm},
3611 {"DR/", validate_dr},
3612 {"DE/", validate_de},
3613 {"NSS/PWINFO/", validate_pwinfo},
3614 {"TRUSTDOMS/", validate_trustdoms},
3615 {"TRUSTDOMCACHE/", validate_trustdomcache},
3616 {"NSS/NA/", validate_nss_na},
3617 {"NSS/AN/", validate_nss_an},
3618 {"WINBINDD_OFFLINE", validate_offline},
3619 {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
3623 /***********************************************************************
3624 Function to look at every entry in the tdb and validate it as far as
3626 ***********************************************************************/
3628 static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
3631 unsigned int max_key_len = 1024;
3632 struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
3634 /* Paranoia check. */
3635 if (strncmp("UA/", (const char *)kbuf.dptr, 3) == 0) {
3636 max_key_len = 1024 * 1024;
3638 if (kbuf.dsize > max_key_len) {
3639 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
3641 (unsigned int)kbuf.dsize, (unsigned int)max_key_len));
3645 for (i = 0; key_val[i].keyname; i++) {
3646 size_t namelen = strlen(key_val[i].keyname);
3647 if (kbuf.dsize >= namelen && (
3648 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
3649 TALLOC_CTX *mem_ctx;
3653 keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
3657 memcpy(keystr, kbuf.dptr, kbuf.dsize);
3658 keystr[kbuf.dsize] = '\0';
3660 mem_ctx = talloc_init("validate_ctx");
3666 ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
3670 talloc_destroy(mem_ctx);
3675 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
3676 dump_data(0, (uint8 *)kbuf.dptr, kbuf.dsize);
3677 DEBUG(0,("data :\n"));
3678 dump_data(0, (uint8 *)dbuf.dptr, dbuf.dsize);
3679 v_state->unknown_key = true;
3680 v_state->success = false;
3681 return 1; /* terminate. */
3684 static void validate_panic(const char *const why)
3686 DEBUG(0,("validating cache: would panic %s\n", why ));
3687 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
3691 /***********************************************************************
3692 Try and validate every entry in the winbindd cache. If we fail here,
3693 delete the cache tdb and return non-zero.
3694 ***********************************************************************/
3696 int winbindd_validate_cache(void)
3699 const char *tdb_path = cache_path("winbindd_cache.tdb");
3700 TDB_CONTEXT *tdb = NULL;
3702 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3703 smb_panic_fn = validate_panic;
3706 tdb = tdb_open_log(tdb_path,
3707 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3708 ( lp_winbind_offline_logon()
3710 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
3714 DEBUG(0, ("winbindd_validate_cache: "
3715 "error opening/initializing tdb\n"));
3720 ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
3723 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
3724 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
3729 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
3730 smb_panic_fn = smb_panic;
3734 /***********************************************************************
3735 Try and validate every entry in the winbindd cache.
3736 ***********************************************************************/
3738 int winbindd_validate_cache_nobackup(void)
3741 const char *tdb_path = cache_path("winbindd_cache.tdb");
3743 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3744 smb_panic_fn = validate_panic;
3747 if (wcache == NULL || wcache->tdb == NULL) {
3748 ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
3750 ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
3754 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
3758 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
3760 smb_panic_fn = smb_panic;
3764 bool winbindd_cache_validate_and_initialize(void)
3766 close_winbindd_cache();
3768 if (lp_winbind_offline_logon()) {
3769 if (winbindd_validate_cache() < 0) {
3770 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
3771 "could be restored.\n"));
3775 return initialize_winbindd_cache();
3778 /*********************************************************************
3779 ********************************************************************/
3781 static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
3782 struct winbindd_tdc_domain **domains,
3783 size_t *num_domains )
3785 struct winbindd_tdc_domain *list = NULL;
3788 bool set_only = false;
3790 /* don't allow duplicates */
3795 for ( i=0; i< (*num_domains); i++ ) {
3796 if ( strequal( new_dom->name, list[i].domain_name ) ) {
3797 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
3808 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, 1 );
3811 list = TALLOC_REALLOC_ARRAY( *domains, *domains,
3812 struct winbindd_tdc_domain,
3817 ZERO_STRUCT( list[idx] );
3823 list[idx].domain_name = talloc_strdup( list, new_dom->name );
3824 list[idx].dns_name = talloc_strdup( list, new_dom->alt_name );
3826 if ( !is_null_sid( &new_dom->sid ) ) {
3827 sid_copy( &list[idx].sid, &new_dom->sid );
3829 sid_copy(&list[idx].sid, &global_sid_NULL);
3832 if ( new_dom->domain_flags != 0x0 )
3833 list[idx].trust_flags = new_dom->domain_flags;
3835 if ( new_dom->domain_type != 0x0 )
3836 list[idx].trust_type = new_dom->domain_type;
3838 if ( new_dom->domain_trust_attribs != 0x0 )
3839 list[idx].trust_attribs = new_dom->domain_trust_attribs;
3843 *num_domains = idx + 1;
3849 /*********************************************************************
3850 ********************************************************************/
3852 static TDB_DATA make_tdc_key( const char *domain_name )
3854 char *keystr = NULL;
3855 TDB_DATA key = { NULL, 0 };
3857 if ( !domain_name ) {
3858 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
3862 if (asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name ) == -1) {
3865 key = string_term_tdb_data(keystr);
3870 /*********************************************************************
3871 ********************************************************************/
3873 static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
3875 unsigned char **buf )
3877 unsigned char *buffer = NULL;
3882 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
3890 /* Store the number of array items first */
3891 len += tdb_pack( buffer+len, buflen-len, "d",
3894 /* now pack each domain trust record */
3895 for ( i=0; i<num_domains; i++ ) {
3900 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
3901 domains[i].domain_name,
3902 domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
3905 len += tdb_pack( buffer+len, buflen-len, "fffddd",
3906 domains[i].domain_name,
3907 domains[i].dns_name,
3908 sid_to_fstring(tmp, &domains[i].sid),
3909 domains[i].trust_flags,
3910 domains[i].trust_attribs,
3911 domains[i].trust_type );
3914 if ( buflen < len ) {
3916 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
3917 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
3931 /*********************************************************************
3932 ********************************************************************/
3934 static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
3935 struct winbindd_tdc_domain **domains )
3937 fstring domain_name, dns_name, sid_string;
3938 uint32 type, attribs, flags;
3942 struct winbindd_tdc_domain *list = NULL;
3944 /* get the number of domains */
3945 len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
3947 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3951 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, num_domains );
3953 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
3957 for ( i=0; i<num_domains; i++ ) {
3958 len += tdb_unpack( buf+len, buflen-len, "fffddd",
3967 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3968 TALLOC_FREE( list );
3972 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
3973 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
3974 domain_name, dns_name, sid_string,
3975 flags, attribs, type));
3977 list[i].domain_name = talloc_strdup( list, domain_name );
3978 list[i].dns_name = talloc_strdup( list, dns_name );
3979 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
3980 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
3983 list[i].trust_flags = flags;
3984 list[i].trust_attribs = attribs;
3985 list[i].trust_type = type;
3993 /*********************************************************************
3994 ********************************************************************/
3996 static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
3998 TDB_DATA key = make_tdc_key( lp_workgroup() );
3999 TDB_DATA data = { NULL, 0 };
4005 /* See if we were asked to delete the cache entry */
4008 ret = tdb_delete( wcache->tdb, key );
4012 data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
4019 ret = tdb_store( wcache->tdb, key, data, 0 );
4022 SAFE_FREE( data.dptr );
4023 SAFE_FREE( key.dptr );
4025 return ( ret != -1 );
4028 /*********************************************************************
4029 ********************************************************************/
4031 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
4033 TDB_DATA key = make_tdc_key( lp_workgroup() );
4034 TDB_DATA data = { NULL, 0 };
4042 data = tdb_fetch( wcache->tdb, key );
4044 SAFE_FREE( key.dptr );
4049 *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
4051 SAFE_FREE( data.dptr );
4059 /*********************************************************************
4060 ********************************************************************/
4062 bool wcache_tdc_add_domain( struct winbindd_domain *domain )
4064 struct winbindd_tdc_domain *dom_list = NULL;
4065 size_t num_domains = 0;
4068 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4069 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4070 domain->name, domain->alt_name,
4071 sid_string_dbg(&domain->sid),
4072 domain->domain_flags,
4073 domain->domain_trust_attribs,
4074 domain->domain_type));
4076 if ( !init_wcache() ) {
4080 /* fetch the list */
4082 wcache_tdc_fetch_list( &dom_list, &num_domains );
4084 /* add the new domain */
4086 if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
4090 /* pack the domain */
4092 if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
4100 TALLOC_FREE( dom_list );
4105 /*********************************************************************
4106 ********************************************************************/
4108 struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
4110 struct winbindd_tdc_domain *dom_list = NULL;
4111 size_t num_domains = 0;
4113 struct winbindd_tdc_domain *d = NULL;
4115 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
4117 if ( !init_wcache() ) {
4121 /* fetch the list */
4123 wcache_tdc_fetch_list( &dom_list, &num_domains );
4125 for ( i=0; i<num_domains; i++ ) {
4126 if ( strequal(name, dom_list[i].domain_name) ||
4127 strequal(name, dom_list[i].dns_name) )
4129 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4132 d = TALLOC_P( ctx, struct winbindd_tdc_domain );
4136 d->domain_name = talloc_strdup( d, dom_list[i].domain_name );
4137 d->dns_name = talloc_strdup( d, dom_list[i].dns_name );
4138 sid_copy( &d->sid, &dom_list[i].sid );
4139 d->trust_flags = dom_list[i].trust_flags;
4140 d->trust_type = dom_list[i].trust_type;
4141 d->trust_attribs = dom_list[i].trust_attribs;
4147 TALLOC_FREE( dom_list );
4153 /*********************************************************************
4154 ********************************************************************/
4156 void wcache_tdc_clear( void )
4158 if ( !init_wcache() )
4161 wcache_tdc_store_list( NULL, 0 );
4167 /*********************************************************************
4168 ********************************************************************/
4170 static void wcache_save_user_pwinfo(struct winbindd_domain *domain,
4172 const DOM_SID *user_sid,
4173 const char *homedir,
4178 struct cache_entry *centry;
4181 if ( (centry = centry_start(domain, status)) == NULL )
4184 centry_put_string( centry, homedir );
4185 centry_put_string( centry, shell );
4186 centry_put_string( centry, gecos );
4187 centry_put_uint32( centry, gid );
4189 centry_end(centry, "NSS/PWINFO/%s", sid_to_fstring(tmp, user_sid) );
4191 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid) ));
4193 centry_free(centry);
4196 NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
4197 const DOM_SID *user_sid,
4199 ADS_STRUCT *ads, LDAPMessage *msg,
4200 const char **homedir, const char **shell,
4201 const char **gecos, gid_t *p_gid)
4203 struct winbind_cache *cache = get_cache(domain);
4204 struct cache_entry *centry = NULL;
4211 centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s",
4212 sid_to_fstring(tmp, user_sid));
4217 *homedir = centry_string( centry, ctx );
4218 *shell = centry_string( centry, ctx );
4219 *gecos = centry_string( centry, ctx );
4220 *p_gid = centry_uint32( centry );
4222 centry_free(centry);
4224 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4225 sid_string_dbg(user_sid)));
4227 return NT_STATUS_OK;
4231 nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg,
4232 homedir, shell, gecos, p_gid );
4234 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status)));
4236 if ( NT_STATUS_IS_OK(nt_status) ) {
4237 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir));
4238 DEBUGADD(10, ("\tshell = '%s'\n", *shell));
4239 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos));
4240 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid));
4242 wcache_save_user_pwinfo( domain, nt_status, user_sid,
4243 *homedir, *shell, *gecos, *p_gid );
4246 if ( NT_STATUS_EQUAL( nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
4247 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4249 set_domain_offline( domain );
4256 /* the cache backend methods are exposed via this structure */
4257 struct winbindd_methods cache_methods = {