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);
2276 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
2277 TALLOC_CTX *mem_ctx,
2278 const DOM_SID *group_sid, uint32 *num_names,
2279 DOM_SID **sid_mem, char ***names,
2280 uint32 **name_types)
2282 struct winbind_cache *cache = get_cache(domain);
2283 struct cache_entry *centry = NULL;
2291 centry = wcache_fetch(cache, domain, "GM/%s",
2292 sid_to_fstring(sid_string, group_sid));
2296 *num_names = centry_uint32(centry);
2298 if (*num_names == 0)
2301 (*sid_mem) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_names);
2302 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_names);
2303 (*name_types) = TALLOC_ARRAY(mem_ctx, uint32, *num_names);
2305 if (! (*sid_mem) || ! (*names) || ! (*name_types)) {
2306 smb_panic_fn("lookup_groupmem out of memory");
2309 for (i=0; i<(*num_names); i++) {
2310 centry_sid(centry, &(*sid_mem)[i]);
2311 (*names)[i] = centry_string(centry, mem_ctx);
2312 (*name_types)[i] = centry_uint32(centry);
2316 status = centry->status;
2318 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status: %s\n",
2319 domain->name, nt_errstr(status)));
2321 centry_free(centry);
2328 (*name_types) = NULL;
2330 /* Return status value returned by seq number check */
2332 if (!NT_STATUS_IS_OK(domain->last_status))
2333 return domain->last_status;
2335 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2338 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid, num_names,
2339 sid_mem, names, name_types);
2342 refresh_sequence_number(domain, false);
2343 centry = centry_start(domain, status);
2346 centry_put_uint32(centry, *num_names);
2347 for (i=0; i<(*num_names); i++) {
2348 centry_put_sid(centry, &(*sid_mem)[i]);
2349 centry_put_string(centry, (*names)[i]);
2350 centry_put_uint32(centry, (*name_types)[i]);
2352 centry_end(centry, "GM/%s", sid_to_fstring(sid_string, group_sid));
2353 centry_free(centry);
2359 /* find the sequence number for a domain */
2360 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
2362 refresh_sequence_number(domain, false);
2364 *seq = domain->sequence_number;
2366 return NT_STATUS_OK;
2369 /* enumerate trusted domains
2370 * (we need to have the list of trustdoms in the cache when we go offline) -
2372 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
2373 TALLOC_CTX *mem_ctx,
2374 uint32 *num_domains,
2379 struct winbind_cache *cache = get_cache(domain);
2380 struct cache_entry *centry = NULL;
2387 centry = wcache_fetch(cache, domain, "TRUSTDOMS/%s", domain->name);
2393 *num_domains = centry_uint32(centry);
2396 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
2397 (*alt_names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
2398 (*dom_sids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
2400 if (! (*dom_sids) || ! (*names) || ! (*alt_names)) {
2401 smb_panic_fn("trusted_domains out of memory");
2405 (*alt_names) = NULL;
2409 for (i=0; i<(*num_domains); i++) {
2410 (*names)[i] = centry_string(centry, mem_ctx);
2411 (*alt_names)[i] = centry_string(centry, mem_ctx);
2412 if (!centry_sid(centry, &(*dom_sids)[i])) {
2413 sid_copy(&(*dom_sids)[i], &global_sid_NULL);
2417 status = centry->status;
2419 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
2420 domain->name, *num_domains, nt_errstr(status) ));
2422 centry_free(centry);
2429 (*alt_names) = NULL;
2431 /* Return status value returned by seq number check */
2433 if (!NT_STATUS_IS_OK(domain->last_status))
2434 return domain->last_status;
2436 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2439 status = domain->backend->trusted_domains(domain, mem_ctx, num_domains,
2440 names, alt_names, dom_sids);
2442 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2443 * so that the generic centry handling still applies correctly -
2446 if (!NT_STATUS_IS_ERR(status)) {
2447 status = NT_STATUS_OK;
2451 #if 0 /* Disabled as we want the trust dom list to be managed by
2452 the main parent and always to make the query. --jerry */
2455 refresh_sequence_number(domain, false);
2457 centry = centry_start(domain, status);
2461 centry_put_uint32(centry, *num_domains);
2463 for (i=0; i<(*num_domains); i++) {
2464 centry_put_string(centry, (*names)[i]);
2465 centry_put_string(centry, (*alt_names)[i]);
2466 centry_put_sid(centry, &(*dom_sids)[i]);
2469 centry_end(centry, "TRUSTDOMS/%s", domain->name);
2471 centry_free(centry);
2479 /* get lockout policy */
2480 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
2481 TALLOC_CTX *mem_ctx,
2482 struct samr_DomInfo12 *policy)
2484 struct winbind_cache *cache = get_cache(domain);
2485 struct cache_entry *centry = NULL;
2491 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2496 policy->lockout_duration = centry_nttime(centry);
2497 policy->lockout_window = centry_nttime(centry);
2498 policy->lockout_threshold = centry_uint16(centry);
2500 status = centry->status;
2502 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2503 domain->name, nt_errstr(status) ));
2505 centry_free(centry);
2509 ZERO_STRUCTP(policy);
2511 /* Return status value returned by seq number check */
2513 if (!NT_STATUS_IS_OK(domain->last_status))
2514 return domain->last_status;
2516 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2519 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2522 refresh_sequence_number(domain, false);
2523 wcache_save_lockout_policy(domain, status, policy);
2528 /* get password policy */
2529 static NTSTATUS password_policy(struct winbindd_domain *domain,
2530 TALLOC_CTX *mem_ctx,
2531 struct samr_DomInfo1 *policy)
2533 struct winbind_cache *cache = get_cache(domain);
2534 struct cache_entry *centry = NULL;
2540 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2545 policy->min_password_length = centry_uint16(centry);
2546 policy->password_history_length = centry_uint16(centry);
2547 policy->password_properties = centry_uint32(centry);
2548 policy->max_password_age = centry_nttime(centry);
2549 policy->min_password_age = centry_nttime(centry);
2551 status = centry->status;
2553 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2554 domain->name, nt_errstr(status) ));
2556 centry_free(centry);
2560 ZERO_STRUCTP(policy);
2562 /* Return status value returned by seq number check */
2564 if (!NT_STATUS_IS_OK(domain->last_status))
2565 return domain->last_status;
2567 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2570 status = domain->backend->password_policy(domain, mem_ctx, policy);
2573 refresh_sequence_number(domain, false);
2574 if (NT_STATUS_IS_OK(status)) {
2575 wcache_save_password_policy(domain, status, policy);
2582 /* Invalidate cached user and group lists coherently */
2584 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2587 if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
2588 strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
2589 tdb_delete(the_tdb, kbuf);
2594 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2596 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
2597 struct netr_SamInfo3 *info3)
2600 fstring key_str, sid_string;
2601 struct winbind_cache *cache;
2603 /* dont clear cached U/SID and UG/SID entries when we want to logon
2606 if (lp_winbind_offline_logon()) {
2613 cache = get_cache(domain);
2619 sid_copy(&sid, info3->base.domain_sid);
2620 sid_append_rid(&sid, info3->base.rid);
2622 /* Clear U/SID cache entry */
2623 fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, &sid));
2624 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
2625 tdb_delete(cache->tdb, string_tdb_data(key_str));
2627 /* Clear UG/SID cache entry */
2628 fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, &sid));
2629 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
2630 tdb_delete(cache->tdb, string_tdb_data(key_str));
2632 /* Samba/winbindd never needs this. */
2633 netsamlogon_clear_cached_user(info3);
2636 bool wcache_invalidate_cache(void)
2638 struct winbindd_domain *domain;
2640 for (domain = domain_list(); domain; domain = domain->next) {
2641 struct winbind_cache *cache = get_cache(domain);
2643 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2644 "entries for %s\n", domain->name));
2647 tdb_traverse(cache->tdb, traverse_fn, NULL);
2656 bool init_wcache(void)
2658 if (wcache == NULL) {
2659 wcache = SMB_XMALLOC_P(struct winbind_cache);
2660 ZERO_STRUCTP(wcache);
2663 if (wcache->tdb != NULL)
2666 /* when working offline we must not clear the cache on restart */
2667 wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
2668 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2669 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
2670 O_RDWR|O_CREAT, 0600);
2672 if (wcache->tdb == NULL) {
2673 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2680 /************************************************************************
2681 This is called by the parent to initialize the cache file.
2682 We don't need sophisticated locking here as we know we're the
2684 ************************************************************************/
2686 bool initialize_winbindd_cache(void)
2688 bool cache_bad = true;
2691 if (!init_wcache()) {
2692 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
2696 /* Check version number. */
2697 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
2698 vers == WINBINDD_CACHE_VERSION) {
2703 DEBUG(0,("initialize_winbindd_cache: clearing cache "
2704 "and re-creating with version number %d\n",
2705 WINBINDD_CACHE_VERSION ));
2707 tdb_close(wcache->tdb);
2710 if (unlink(cache_path("winbindd_cache.tdb")) == -1) {
2711 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
2712 cache_path("winbindd_cache.tdb"),
2716 if (!init_wcache()) {
2717 DEBUG(0,("initialize_winbindd_cache: re-initialization "
2718 "init_wcache failed.\n"));
2722 /* Write the version. */
2723 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
2724 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
2725 tdb_errorstr(wcache->tdb) ));
2730 tdb_close(wcache->tdb);
2735 void close_winbindd_cache(void)
2741 tdb_close(wcache->tdb);
2746 bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
2747 char **domain_name, char **name,
2748 enum lsa_SidType *type)
2750 struct winbindd_domain *domain;
2753 domain = find_lookup_domain_from_sid(sid);
2754 if (domain == NULL) {
2757 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
2759 return NT_STATUS_IS_OK(status);
2762 bool lookup_cached_name(TALLOC_CTX *mem_ctx,
2763 const char *domain_name,
2766 enum lsa_SidType *type)
2768 struct winbindd_domain *domain;
2770 bool original_online_state;
2772 domain = find_lookup_domain_from_name(domain_name);
2773 if (domain == NULL) {
2777 /* If we are doing a cached logon, temporarily set the domain
2778 offline so the cache won't expire the entry */
2780 original_online_state = domain->online;
2781 domain->online = false;
2782 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
2783 domain->online = original_online_state;
2785 return NT_STATUS_IS_OK(status);
2788 void cache_name2sid(struct winbindd_domain *domain,
2789 const char *domain_name, const char *name,
2790 enum lsa_SidType type, const DOM_SID *sid)
2792 refresh_sequence_number(domain, false);
2793 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
2798 * The original idea that this cache only contains centries has
2799 * been blurred - now other stuff gets put in here. Ensure we
2800 * ignore these things on cleanup.
2803 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
2804 TDB_DATA dbuf, void *state)
2806 struct cache_entry *centry;
2808 if (is_non_centry_key(kbuf)) {
2812 centry = wcache_fetch_raw((char *)kbuf.dptr);
2817 if (!NT_STATUS_IS_OK(centry->status)) {
2818 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
2819 tdb_delete(the_tdb, kbuf);
2822 centry_free(centry);
2826 /* flush the cache */
2827 void wcache_flush_cache(void)
2832 tdb_close(wcache->tdb);
2835 if (!winbindd_use_cache()) {
2839 /* when working offline we must not clear the cache on restart */
2840 wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
2841 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2842 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
2843 O_RDWR|O_CREAT, 0600);
2846 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2850 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
2852 DEBUG(10,("wcache_flush_cache success\n"));
2855 /* Count cached creds */
2857 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2860 int *cred_count = (int*)state;
2862 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
2868 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
2870 struct winbind_cache *cache = get_cache(domain);
2875 return NT_STATUS_INTERNAL_DB_ERROR;
2878 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
2880 return NT_STATUS_OK;
2884 struct cred_list *prev, *next;
2889 static struct cred_list *wcache_cred_list;
2891 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2894 struct cred_list *cred;
2896 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
2898 cred = SMB_MALLOC_P(struct cred_list);
2900 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2906 /* save a copy of the key */
2908 fstrcpy(cred->name, (const char *)kbuf.dptr);
2909 DLIST_ADD(wcache_cred_list, cred);
2915 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const DOM_SID *sid)
2917 struct winbind_cache *cache = get_cache(domain);
2920 struct cred_list *cred, *oldest = NULL;
2923 return NT_STATUS_INTERNAL_DB_ERROR;
2926 /* we possibly already have an entry */
2927 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
2929 fstring key_str, tmp;
2931 DEBUG(11,("we already have an entry, deleting that\n"));
2933 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
2935 tdb_delete(cache->tdb, string_tdb_data(key_str));
2937 return NT_STATUS_OK;
2940 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
2942 return NT_STATUS_OK;
2943 } else if ((ret == -1) || (wcache_cred_list == NULL)) {
2944 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2947 ZERO_STRUCTP(oldest);
2949 for (cred = wcache_cred_list; cred; cred = cred->next) {
2954 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
2956 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
2958 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
2962 t = IVAL(data.dptr, 0);
2963 SAFE_FREE(data.dptr);
2966 oldest = SMB_MALLOC_P(struct cred_list);
2967 if (oldest == NULL) {
2968 status = NT_STATUS_NO_MEMORY;
2972 fstrcpy(oldest->name, cred->name);
2973 oldest->created = t;
2977 if (t < oldest->created) {
2978 fstrcpy(oldest->name, cred->name);
2979 oldest->created = t;
2983 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
2984 status = NT_STATUS_OK;
2986 status = NT_STATUS_UNSUCCESSFUL;
2989 SAFE_FREE(wcache_cred_list);
2995 /* Change the global online/offline state. */
2996 bool set_global_winbindd_state_offline(void)
3000 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3002 /* Only go offline if someone has created
3003 the key "WINBINDD_OFFLINE" in the cache tdb. */
3005 if (wcache == NULL || wcache->tdb == NULL) {
3006 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3010 if (!lp_winbind_offline_logon()) {
3011 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3015 if (global_winbindd_offline_state) {
3016 /* Already offline. */
3020 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
3022 if (!data.dptr || data.dsize != 4) {
3023 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3024 SAFE_FREE(data.dptr);
3027 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3028 global_winbindd_offline_state = true;
3029 SAFE_FREE(data.dptr);
3034 void set_global_winbindd_state_online(void)
3036 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3038 if (!lp_winbind_offline_logon()) {
3039 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3043 if (!global_winbindd_offline_state) {
3044 /* Already online. */
3047 global_winbindd_offline_state = false;
3053 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3054 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
3057 bool get_global_winbindd_state_offline(void)
3059 return global_winbindd_offline_state;
3062 /***********************************************************************
3063 Validate functions for all possible cache tdb keys.
3064 ***********************************************************************/
3066 static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
3067 struct tdb_validation_status *state)
3069 struct cache_entry *centry;
3071 centry = SMB_XMALLOC_P(struct cache_entry);
3072 centry->data = (unsigned char *)memdup(data.dptr, data.dsize);
3073 if (!centry->data) {
3077 centry->len = data.dsize;
3080 if (centry->len < 8) {
3081 /* huh? corrupt cache? */
3082 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr));
3083 centry_free(centry);
3084 state->bad_entry = true;
3085 state->success = false;
3089 centry->status = NT_STATUS(centry_uint32(centry));
3090 centry->sequence_number = centry_uint32(centry);
3094 static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3095 struct tdb_validation_status *state)
3097 if (dbuf.dsize != 8) {
3098 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3099 keystr, (unsigned int)dbuf.dsize ));
3100 state->bad_entry = true;
3106 static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3107 struct tdb_validation_status *state)
3109 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3114 (void)centry_uint32(centry);
3115 if (NT_STATUS_IS_OK(centry->status)) {
3117 (void)centry_sid(centry, &sid);
3120 centry_free(centry);
3122 if (!(state->success)) {
3125 DEBUG(10,("validate_ns: %s ok\n", keystr));
3129 static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3130 struct tdb_validation_status *state)
3132 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3137 if (NT_STATUS_IS_OK(centry->status)) {
3138 (void)centry_uint32(centry);
3139 (void)centry_string(centry, mem_ctx);
3140 (void)centry_string(centry, mem_ctx);
3143 centry_free(centry);
3145 if (!(state->success)) {
3148 DEBUG(10,("validate_sn: %s ok\n", keystr));
3152 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3153 struct tdb_validation_status *state)
3155 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3162 (void)centry_string(centry, mem_ctx);
3163 (void)centry_string(centry, mem_ctx);
3164 (void)centry_string(centry, mem_ctx);
3165 (void)centry_string(centry, mem_ctx);
3166 (void)centry_uint32(centry);
3167 (void)centry_sid(centry, &sid);
3168 (void)centry_sid(centry, &sid);
3170 centry_free(centry);
3172 if (!(state->success)) {
3175 DEBUG(10,("validate_u: %s ok\n", keystr));
3179 static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3180 struct tdb_validation_status *state)
3182 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3188 (void)centry_nttime(centry);
3189 (void)centry_nttime(centry);
3190 (void)centry_uint16(centry);
3192 centry_free(centry);
3194 if (!(state->success)) {
3197 DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
3201 static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3202 struct tdb_validation_status *state)
3204 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3210 (void)centry_uint16(centry);
3211 (void)centry_uint16(centry);
3212 (void)centry_uint32(centry);
3213 (void)centry_nttime(centry);
3214 (void)centry_nttime(centry);
3216 centry_free(centry);
3218 if (!(state->success)) {
3221 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
3225 static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3226 struct tdb_validation_status *state)
3228 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3234 (void)centry_time(centry);
3235 (void)centry_hash16(centry, mem_ctx);
3237 /* We only have 17 bytes more data in the salted cred case. */
3238 if (centry->len - centry->ofs == 17) {
3239 (void)centry_hash16(centry, mem_ctx);
3242 centry_free(centry);
3244 if (!(state->success)) {
3247 DEBUG(10,("validate_cred: %s ok\n", keystr));
3251 static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3252 struct tdb_validation_status *state)
3254 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3255 int32 num_entries, i;
3261 num_entries = (int32)centry_uint32(centry);
3263 for (i=0; i< num_entries; i++) {
3265 (void)centry_string(centry, mem_ctx);
3266 (void)centry_string(centry, mem_ctx);
3267 (void)centry_string(centry, mem_ctx);
3268 (void)centry_string(centry, mem_ctx);
3269 (void)centry_sid(centry, &sid);
3270 (void)centry_sid(centry, &sid);
3273 centry_free(centry);
3275 if (!(state->success)) {
3278 DEBUG(10,("validate_ul: %s ok\n", keystr));
3282 static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3283 struct tdb_validation_status *state)
3285 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3286 int32 num_entries, i;
3292 num_entries = centry_uint32(centry);
3294 for (i=0; i< num_entries; i++) {
3295 (void)centry_string(centry, mem_ctx);
3296 (void)centry_string(centry, mem_ctx);
3297 (void)centry_uint32(centry);
3300 centry_free(centry);
3302 if (!(state->success)) {
3305 DEBUG(10,("validate_gl: %s ok\n", keystr));
3309 static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3310 struct tdb_validation_status *state)
3312 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3313 int32 num_groups, i;
3319 num_groups = centry_uint32(centry);
3321 for (i=0; i< num_groups; i++) {
3323 centry_sid(centry, &sid);
3326 centry_free(centry);
3328 if (!(state->success)) {
3331 DEBUG(10,("validate_ug: %s ok\n", keystr));
3335 static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3336 struct tdb_validation_status *state)
3338 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3339 int32 num_aliases, i;
3345 num_aliases = centry_uint32(centry);
3347 for (i=0; i < num_aliases; i++) {
3348 (void)centry_uint32(centry);
3351 centry_free(centry);
3353 if (!(state->success)) {
3356 DEBUG(10,("validate_ua: %s ok\n", keystr));
3360 static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3361 struct tdb_validation_status *state)
3363 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3370 num_names = centry_uint32(centry);
3372 for (i=0; i< num_names; i++) {
3374 centry_sid(centry, &sid);
3375 (void)centry_string(centry, mem_ctx);
3376 (void)centry_uint32(centry);
3379 centry_free(centry);
3381 if (!(state->success)) {
3384 DEBUG(10,("validate_gm: %s ok\n", keystr));
3388 static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3389 struct tdb_validation_status *state)
3391 /* Can't say anything about this other than must be nonzero. */
3392 if (dbuf.dsize == 0) {
3393 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3395 state->bad_entry = true;
3396 state->success = false;
3400 DEBUG(10,("validate_dr: %s ok\n", keystr));
3404 static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3405 struct tdb_validation_status *state)
3407 /* Can't say anything about this other than must be nonzero. */
3408 if (dbuf.dsize == 0) {
3409 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3411 state->bad_entry = true;
3412 state->success = false;
3416 DEBUG(10,("validate_de: %s ok\n", keystr));
3420 static int validate_pwinfo(TALLOC_CTX *mem_ctx, const char *keystr,
3421 TDB_DATA dbuf, struct tdb_validation_status *state)
3423 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3429 (void)centry_string(centry, mem_ctx);
3430 (void)centry_string(centry, mem_ctx);
3431 (void)centry_string(centry, mem_ctx);
3432 (void)centry_uint32(centry);
3434 centry_free(centry);
3436 if (!(state->success)) {
3439 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3443 static int validate_nss_an(TALLOC_CTX *mem_ctx, const char *keystr,
3445 struct tdb_validation_status *state)
3447 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3453 (void)centry_string( centry, mem_ctx );
3455 centry_free(centry);
3457 if (!(state->success)) {
3460 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3464 static int validate_nss_na(TALLOC_CTX *mem_ctx, const char *keystr,
3466 struct tdb_validation_status *state)
3468 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3474 (void)centry_string( centry, mem_ctx );
3476 centry_free(centry);
3478 if (!(state->success)) {
3481 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3485 static int validate_trustdoms(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3486 struct tdb_validation_status *state)
3488 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3489 int32 num_domains, i;
3495 num_domains = centry_uint32(centry);
3497 for (i=0; i< num_domains; i++) {
3499 (void)centry_string(centry, mem_ctx);
3500 (void)centry_string(centry, mem_ctx);
3501 (void)centry_sid(centry, &sid);
3504 centry_free(centry);
3506 if (!(state->success)) {
3509 DEBUG(10,("validate_trustdoms: %s ok\n", keystr));
3513 static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
3515 struct tdb_validation_status *state)
3517 if (dbuf.dsize == 0) {
3518 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3519 "key %s (len ==0) ?\n", keystr));
3520 state->bad_entry = true;
3521 state->success = false;
3525 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
3526 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3530 static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3531 struct tdb_validation_status *state)
3533 if (dbuf.dsize != 4) {
3534 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3535 keystr, (unsigned int)dbuf.dsize ));
3536 state->bad_entry = true;
3537 state->success = false;
3540 DEBUG(10,("validate_offline: %s ok\n", keystr));
3544 static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3545 struct tdb_validation_status *state)
3547 if (dbuf.dsize != 4) {
3548 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3549 "key %s (len %u != 4) ?\n",
3550 keystr, (unsigned int)dbuf.dsize));
3551 state->bad_entry = true;
3552 state->success = false;
3556 DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
3560 /***********************************************************************
3561 A list of all possible cache tdb keys with associated validation
3563 ***********************************************************************/
3565 struct key_val_struct {
3566 const char *keyname;
3567 int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
3569 {"SEQNUM/", validate_seqnum},
3570 {"NS/", validate_ns},
3571 {"SN/", validate_sn},
3573 {"LOC_POL/", validate_loc_pol},
3574 {"PWD_POL/", validate_pwd_pol},
3575 {"CRED/", validate_cred},
3576 {"UL/", validate_ul},
3577 {"GL/", validate_gl},
3578 {"UG/", validate_ug},
3579 {"UA", validate_ua},
3580 {"GM/", validate_gm},
3581 {"DR/", validate_dr},
3582 {"DE/", validate_de},
3583 {"NSS/PWINFO/", validate_pwinfo},
3584 {"TRUSTDOMS/", validate_trustdoms},
3585 {"TRUSTDOMCACHE/", validate_trustdomcache},
3586 {"NSS/NA/", validate_nss_na},
3587 {"NSS/AN/", validate_nss_an},
3588 {"WINBINDD_OFFLINE", validate_offline},
3589 {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
3593 /***********************************************************************
3594 Function to look at every entry in the tdb and validate it as far as
3596 ***********************************************************************/
3598 static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
3601 unsigned int max_key_len = 1024;
3602 struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
3604 /* Paranoia check. */
3605 if (strncmp("UA/", (const char *)kbuf.dptr, 3) == 0) {
3606 max_key_len = 1024 * 1024;
3608 if (kbuf.dsize > max_key_len) {
3609 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
3611 (unsigned int)kbuf.dsize, (unsigned int)max_key_len));
3615 for (i = 0; key_val[i].keyname; i++) {
3616 size_t namelen = strlen(key_val[i].keyname);
3617 if (kbuf.dsize >= namelen && (
3618 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
3619 TALLOC_CTX *mem_ctx;
3623 keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
3627 memcpy(keystr, kbuf.dptr, kbuf.dsize);
3628 keystr[kbuf.dsize] = '\0';
3630 mem_ctx = talloc_init("validate_ctx");
3636 ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
3640 talloc_destroy(mem_ctx);
3645 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
3646 dump_data(0, (uint8 *)kbuf.dptr, kbuf.dsize);
3647 DEBUG(0,("data :\n"));
3648 dump_data(0, (uint8 *)dbuf.dptr, dbuf.dsize);
3649 v_state->unknown_key = true;
3650 v_state->success = false;
3651 return 1; /* terminate. */
3654 static void validate_panic(const char *const why)
3656 DEBUG(0,("validating cache: would panic %s\n", why ));
3657 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
3661 /***********************************************************************
3662 Try and validate every entry in the winbindd cache. If we fail here,
3663 delete the cache tdb and return non-zero.
3664 ***********************************************************************/
3666 int winbindd_validate_cache(void)
3669 const char *tdb_path = cache_path("winbindd_cache.tdb");
3670 TDB_CONTEXT *tdb = NULL;
3672 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3673 smb_panic_fn = validate_panic;
3676 tdb = tdb_open_log(tdb_path,
3677 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3678 ( lp_winbind_offline_logon()
3680 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
3684 DEBUG(0, ("winbindd_validate_cache: "
3685 "error opening/initializing tdb\n"));
3690 ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
3693 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
3694 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
3699 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
3700 smb_panic_fn = smb_panic;
3704 /***********************************************************************
3705 Try and validate every entry in the winbindd cache.
3706 ***********************************************************************/
3708 int winbindd_validate_cache_nobackup(void)
3711 const char *tdb_path = cache_path("winbindd_cache.tdb");
3713 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3714 smb_panic_fn = validate_panic;
3717 if (wcache == NULL || wcache->tdb == NULL) {
3718 ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
3720 ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
3724 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
3728 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
3730 smb_panic_fn = smb_panic;
3734 bool winbindd_cache_validate_and_initialize(void)
3736 close_winbindd_cache();
3738 if (lp_winbind_offline_logon()) {
3739 if (winbindd_validate_cache() < 0) {
3740 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
3741 "could be restored.\n"));
3745 return initialize_winbindd_cache();
3748 /*********************************************************************
3749 ********************************************************************/
3751 static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
3752 struct winbindd_tdc_domain **domains,
3753 size_t *num_domains )
3755 struct winbindd_tdc_domain *list = NULL;
3758 bool set_only = false;
3760 /* don't allow duplicates */
3765 for ( i=0; i< (*num_domains); i++ ) {
3766 if ( strequal( new_dom->name, list[i].domain_name ) ) {
3767 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
3778 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, 1 );
3781 list = TALLOC_REALLOC_ARRAY( *domains, *domains,
3782 struct winbindd_tdc_domain,
3787 ZERO_STRUCT( list[idx] );
3793 list[idx].domain_name = talloc_strdup( list, new_dom->name );
3794 list[idx].dns_name = talloc_strdup( list, new_dom->alt_name );
3796 if ( !is_null_sid( &new_dom->sid ) ) {
3797 sid_copy( &list[idx].sid, &new_dom->sid );
3799 sid_copy(&list[idx].sid, &global_sid_NULL);
3802 if ( new_dom->domain_flags != 0x0 )
3803 list[idx].trust_flags = new_dom->domain_flags;
3805 if ( new_dom->domain_type != 0x0 )
3806 list[idx].trust_type = new_dom->domain_type;
3808 if ( new_dom->domain_trust_attribs != 0x0 )
3809 list[idx].trust_attribs = new_dom->domain_trust_attribs;
3813 *num_domains = idx + 1;
3819 /*********************************************************************
3820 ********************************************************************/
3822 static TDB_DATA make_tdc_key( const char *domain_name )
3824 char *keystr = NULL;
3825 TDB_DATA key = { NULL, 0 };
3827 if ( !domain_name ) {
3828 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
3832 if (asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name ) == -1) {
3835 key = string_term_tdb_data(keystr);
3840 /*********************************************************************
3841 ********************************************************************/
3843 static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
3845 unsigned char **buf )
3847 unsigned char *buffer = NULL;
3852 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
3860 /* Store the number of array items first */
3861 len += tdb_pack( buffer+len, buflen-len, "d",
3864 /* now pack each domain trust record */
3865 for ( i=0; i<num_domains; i++ ) {
3870 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
3871 domains[i].domain_name,
3872 domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
3875 len += tdb_pack( buffer+len, buflen-len, "fffddd",
3876 domains[i].domain_name,
3877 domains[i].dns_name,
3878 sid_to_fstring(tmp, &domains[i].sid),
3879 domains[i].trust_flags,
3880 domains[i].trust_attribs,
3881 domains[i].trust_type );
3884 if ( buflen < len ) {
3886 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
3887 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
3901 /*********************************************************************
3902 ********************************************************************/
3904 static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
3905 struct winbindd_tdc_domain **domains )
3907 fstring domain_name, dns_name, sid_string;
3908 uint32 type, attribs, flags;
3912 struct winbindd_tdc_domain *list = NULL;
3914 /* get the number of domains */
3915 len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
3917 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3921 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, num_domains );
3923 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
3927 for ( i=0; i<num_domains; i++ ) {
3928 len += tdb_unpack( buf+len, buflen-len, "fffddd",
3937 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3938 TALLOC_FREE( list );
3942 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
3943 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
3944 domain_name, dns_name, sid_string,
3945 flags, attribs, type));
3947 list[i].domain_name = talloc_strdup( list, domain_name );
3948 list[i].dns_name = talloc_strdup( list, dns_name );
3949 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
3950 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
3953 list[i].trust_flags = flags;
3954 list[i].trust_attribs = attribs;
3955 list[i].trust_type = type;
3963 /*********************************************************************
3964 ********************************************************************/
3966 static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
3968 TDB_DATA key = make_tdc_key( lp_workgroup() );
3969 TDB_DATA data = { NULL, 0 };
3975 /* See if we were asked to delete the cache entry */
3978 ret = tdb_delete( wcache->tdb, key );
3982 data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
3989 ret = tdb_store( wcache->tdb, key, data, 0 );
3992 SAFE_FREE( data.dptr );
3993 SAFE_FREE( key.dptr );
3995 return ( ret != -1 );
3998 /*********************************************************************
3999 ********************************************************************/
4001 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
4003 TDB_DATA key = make_tdc_key( lp_workgroup() );
4004 TDB_DATA data = { NULL, 0 };
4012 data = tdb_fetch( wcache->tdb, key );
4014 SAFE_FREE( key.dptr );
4019 *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
4021 SAFE_FREE( data.dptr );
4029 /*********************************************************************
4030 ********************************************************************/
4032 bool wcache_tdc_add_domain( struct winbindd_domain *domain )
4034 struct winbindd_tdc_domain *dom_list = NULL;
4035 size_t num_domains = 0;
4038 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4039 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4040 domain->name, domain->alt_name,
4041 sid_string_dbg(&domain->sid),
4042 domain->domain_flags,
4043 domain->domain_trust_attribs,
4044 domain->domain_type));
4046 if ( !init_wcache() ) {
4050 /* fetch the list */
4052 wcache_tdc_fetch_list( &dom_list, &num_domains );
4054 /* add the new domain */
4056 if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
4060 /* pack the domain */
4062 if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
4070 TALLOC_FREE( dom_list );
4075 /*********************************************************************
4076 ********************************************************************/
4078 struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
4080 struct winbindd_tdc_domain *dom_list = NULL;
4081 size_t num_domains = 0;
4083 struct winbindd_tdc_domain *d = NULL;
4085 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
4087 if ( !init_wcache() ) {
4091 /* fetch the list */
4093 wcache_tdc_fetch_list( &dom_list, &num_domains );
4095 for ( i=0; i<num_domains; i++ ) {
4096 if ( strequal(name, dom_list[i].domain_name) ||
4097 strequal(name, dom_list[i].dns_name) )
4099 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4102 d = TALLOC_P( ctx, struct winbindd_tdc_domain );
4106 d->domain_name = talloc_strdup( d, dom_list[i].domain_name );
4107 d->dns_name = talloc_strdup( d, dom_list[i].dns_name );
4108 sid_copy( &d->sid, &dom_list[i].sid );
4109 d->trust_flags = dom_list[i].trust_flags;
4110 d->trust_type = dom_list[i].trust_type;
4111 d->trust_attribs = dom_list[i].trust_attribs;
4117 TALLOC_FREE( dom_list );
4123 /*********************************************************************
4124 ********************************************************************/
4126 void wcache_tdc_clear( void )
4128 if ( !init_wcache() )
4131 wcache_tdc_store_list( NULL, 0 );
4137 /*********************************************************************
4138 ********************************************************************/
4140 static void wcache_save_user_pwinfo(struct winbindd_domain *domain,
4142 const DOM_SID *user_sid,
4143 const char *homedir,
4148 struct cache_entry *centry;
4151 if ( (centry = centry_start(domain, status)) == NULL )
4154 centry_put_string( centry, homedir );
4155 centry_put_string( centry, shell );
4156 centry_put_string( centry, gecos );
4157 centry_put_uint32( centry, gid );
4159 centry_end(centry, "NSS/PWINFO/%s", sid_to_fstring(tmp, user_sid) );
4161 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid) ));
4163 centry_free(centry);
4166 NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
4167 const DOM_SID *user_sid,
4169 ADS_STRUCT *ads, LDAPMessage *msg,
4170 const char **homedir, const char **shell,
4171 const char **gecos, gid_t *p_gid)
4173 struct winbind_cache *cache = get_cache(domain);
4174 struct cache_entry *centry = NULL;
4181 centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s",
4182 sid_to_fstring(tmp, user_sid));
4187 *homedir = centry_string( centry, ctx );
4188 *shell = centry_string( centry, ctx );
4189 *gecos = centry_string( centry, ctx );
4190 *p_gid = centry_uint32( centry );
4192 centry_free(centry);
4194 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4195 sid_string_dbg(user_sid)));
4197 return NT_STATUS_OK;
4201 nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg,
4202 homedir, shell, gecos, p_gid );
4204 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status)));
4206 if ( NT_STATUS_IS_OK(nt_status) ) {
4207 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir));
4208 DEBUGADD(10, ("\tshell = '%s'\n", *shell));
4209 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos));
4210 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid));
4212 wcache_save_user_pwinfo( domain, nt_status, user_sid,
4213 *homedir, *shell, *gecos, *p_gid );
4216 if ( NT_STATUS_EQUAL( nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
4217 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4219 set_domain_offline( domain );
4226 /* the cache backend methods are exposed via this structure */
4227 struct winbindd_methods cache_methods = {