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, WINBIND_USERINFO *info)
903 struct cache_entry *centry;
906 if (is_null_sid(&info->user_sid)) {
910 centry = centry_start(domain, status);
913 centry_put_string(centry, info->acct_name);
914 centry_put_string(centry, info->full_name);
915 centry_put_string(centry, info->homedir);
916 centry_put_string(centry, info->shell);
917 centry_put_uint32(centry, info->primary_gid);
918 centry_put_sid(centry, &info->user_sid);
919 centry_put_sid(centry, &info->group_sid);
920 centry_end(centry, "U/%s", sid_to_fstring(sid_string,
922 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
926 static void wcache_save_lockout_policy(struct winbindd_domain *domain,
928 struct samr_DomInfo12 *lockout_policy)
930 struct cache_entry *centry;
932 centry = centry_start(domain, status);
936 centry_put_nttime(centry, lockout_policy->lockout_duration);
937 centry_put_nttime(centry, lockout_policy->lockout_window);
938 centry_put_uint16(centry, lockout_policy->lockout_threshold);
940 centry_end(centry, "LOC_POL/%s", domain->name);
942 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
949 static void wcache_save_password_policy(struct winbindd_domain *domain,
951 struct samr_DomInfo1 *policy)
953 struct cache_entry *centry;
955 centry = centry_start(domain, status);
959 centry_put_uint16(centry, policy->min_password_length);
960 centry_put_uint16(centry, policy->password_history_length);
961 centry_put_uint32(centry, policy->password_properties);
962 centry_put_nttime(centry, policy->max_password_age);
963 centry_put_nttime(centry, policy->min_password_age);
965 centry_end(centry, "PWD_POL/%s", domain->name);
967 DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
972 /***************************************************************************
973 ***************************************************************************/
975 static void wcache_save_username_alias(struct winbindd_domain *domain,
977 const char *name, const char *alias)
979 struct cache_entry *centry;
982 if ( (centry = centry_start(domain, status)) == NULL )
985 centry_put_string( centry, alias );
987 fstrcpy(uname, name);
989 centry_end(centry, "NSS/NA/%s", uname);
991 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name, alias ));
996 static void wcache_save_alias_username(struct winbindd_domain *domain,
998 const char *alias, const char *name)
1000 struct cache_entry *centry;
1003 if ( (centry = centry_start(domain, status)) == NULL )
1006 centry_put_string( centry, name );
1008 fstrcpy(uname, alias);
1010 centry_end(centry, "NSS/AN/%s", uname);
1012 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias, name ));
1014 centry_free(centry);
1017 /***************************************************************************
1018 ***************************************************************************/
1020 NTSTATUS resolve_username_to_alias( TALLOC_CTX *mem_ctx,
1021 struct winbindd_domain *domain,
1022 const char *name, char **alias )
1024 struct winbind_cache *cache = get_cache(domain);
1025 struct cache_entry *centry = NULL;
1029 if ( domain->internal )
1030 return NT_STATUS_NOT_SUPPORTED;
1035 if ( (upper_name = SMB_STRDUP(name)) == NULL )
1036 return NT_STATUS_NO_MEMORY;
1037 strupper_m(upper_name);
1039 centry = wcache_fetch(cache, domain, "NSS/NA/%s", upper_name);
1041 SAFE_FREE( upper_name );
1046 status = centry->status;
1048 if (!NT_STATUS_IS_OK(status)) {
1049 centry_free(centry);
1053 *alias = centry_string( centry, mem_ctx );
1055 centry_free(centry);
1057 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1058 name, *alias ? *alias : "(none)"));
1060 return (*alias) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1064 /* If its not in cache and we are offline, then fail */
1066 if ( get_global_winbindd_state_offline() || !domain->online ) {
1067 DEBUG(8,("resolve_username_to_alias: rejecting query "
1068 "in offline mode\n"));
1069 return NT_STATUS_NOT_FOUND;
1072 status = nss_map_to_alias( mem_ctx, domain->name, name, alias );
1074 if ( NT_STATUS_IS_OK( status ) ) {
1075 wcache_save_username_alias(domain, status, name, *alias);
1078 if ( NT_STATUS_EQUAL( status, NT_STATUS_NONE_MAPPED ) ) {
1079 wcache_save_username_alias(domain, status, name, "(NULL)");
1082 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1083 nt_errstr(status)));
1085 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1086 set_domain_offline( domain );
1092 /***************************************************************************
1093 ***************************************************************************/
1095 NTSTATUS resolve_alias_to_username( TALLOC_CTX *mem_ctx,
1096 struct winbindd_domain *domain,
1097 const char *alias, char **name )
1099 struct winbind_cache *cache = get_cache(domain);
1100 struct cache_entry *centry = NULL;
1104 if ( domain->internal )
1105 return NT_STATUS_NOT_SUPPORTED;
1110 if ( (upper_name = SMB_STRDUP(alias)) == NULL )
1111 return NT_STATUS_NO_MEMORY;
1112 strupper_m(upper_name);
1114 centry = wcache_fetch(cache, domain, "NSS/AN/%s", upper_name);
1116 SAFE_FREE( upper_name );
1121 status = centry->status;
1123 if (!NT_STATUS_IS_OK(status)) {
1124 centry_free(centry);
1128 *name = centry_string( centry, mem_ctx );
1130 centry_free(centry);
1132 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1133 alias, *name ? *name : "(none)"));
1135 return (*name) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1139 /* If its not in cache and we are offline, then fail */
1141 if ( get_global_winbindd_state_offline() || !domain->online ) {
1142 DEBUG(8,("resolve_alias_to_username: rejecting query "
1143 "in offline mode\n"));
1144 return NT_STATUS_NOT_FOUND;
1147 /* an alias cannot contain a domain prefix or '@' */
1149 if (strchr(alias, '\\') || strchr(alias, '@')) {
1150 DEBUG(10,("resolve_alias_to_username: skipping fully "
1151 "qualified name %s\n", alias));
1152 return NT_STATUS_OBJECT_NAME_INVALID;
1155 status = nss_map_from_alias( mem_ctx, domain->name, alias, name );
1157 if ( NT_STATUS_IS_OK( status ) ) {
1158 wcache_save_alias_username( domain, status, alias, *name );
1161 if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1162 wcache_save_alias_username(domain, status, alias, "(NULL)");
1165 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1166 nt_errstr(status)));
1168 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1169 set_domain_offline( domain );
1175 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const DOM_SID *sid)
1177 struct winbind_cache *cache = get_cache(domain);
1179 fstring key_str, tmp;
1183 return NT_STATUS_INTERNAL_DB_ERROR;
1186 if (is_null_sid(sid)) {
1187 return NT_STATUS_INVALID_SID;
1190 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1191 return NT_STATUS_INVALID_SID;
1194 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
1196 data = tdb_fetch(cache->tdb, string_tdb_data(key_str));
1198 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1201 SAFE_FREE(data.dptr);
1202 return NT_STATUS_OK;
1205 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1206 as new salted ones. */
1208 NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
1209 TALLOC_CTX *mem_ctx,
1211 const uint8 **cached_nt_pass,
1212 const uint8 **cached_salt)
1214 struct winbind_cache *cache = get_cache(domain);
1215 struct cache_entry *centry = NULL;
1222 return NT_STATUS_INTERNAL_DB_ERROR;
1225 if (is_null_sid(sid)) {
1226 return NT_STATUS_INVALID_SID;
1229 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1230 return NT_STATUS_INVALID_SID;
1233 /* Try and get a salted cred first. If we can't
1234 fall back to an unsalted cred. */
1236 centry = wcache_fetch(cache, domain, "CRED/%s",
1237 sid_to_fstring(tmp, sid));
1239 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1240 sid_string_dbg(sid)));
1241 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1244 t = centry_time(centry);
1246 /* In the salted case this isn't actually the nt_hash itself,
1247 but the MD5 of the salt + nt_hash. Let the caller
1248 sort this out. It can tell as we only return the cached_salt
1249 if we are returning a salted cred. */
1251 *cached_nt_pass = (const uint8 *)centry_hash16(centry, mem_ctx);
1252 if (*cached_nt_pass == NULL) {
1255 sid_to_fstring(sidstr, sid);
1257 /* Bad (old) cred cache. Delete and pretend we
1259 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1261 wcache_delete("CRED/%s", sidstr);
1262 centry_free(centry);
1263 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1266 /* We only have 17 bytes more data in the salted cred case. */
1267 if (centry->len - centry->ofs == 17) {
1268 *cached_salt = (const uint8 *)centry_hash16(centry, mem_ctx);
1270 *cached_salt = NULL;
1273 dump_data_pw("cached_nt_pass", *cached_nt_pass, NT_HASH_LEN);
1275 dump_data_pw("cached_salt", *cached_salt, NT_HASH_LEN);
1278 status = centry->status;
1280 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1281 sid_string_dbg(sid), nt_errstr(status) ));
1283 centry_free(centry);
1287 /* Store creds for a SID - only writes out new salted ones. */
1289 NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
1290 TALLOC_CTX *mem_ctx,
1292 const uint8 nt_pass[NT_HASH_LEN])
1294 struct cache_entry *centry;
1297 uint8 cred_salt[NT_HASH_LEN];
1298 uint8 salted_hash[NT_HASH_LEN];
1300 if (is_null_sid(sid)) {
1301 return NT_STATUS_INVALID_SID;
1304 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1305 return NT_STATUS_INVALID_SID;
1308 centry = centry_start(domain, NT_STATUS_OK);
1310 return NT_STATUS_INTERNAL_DB_ERROR;
1313 dump_data_pw("nt_pass", nt_pass, NT_HASH_LEN);
1315 centry_put_time(centry, time(NULL));
1317 /* Create a salt and then salt the hash. */
1318 generate_random_buffer(cred_salt, NT_HASH_LEN);
1319 E_md5hash(cred_salt, nt_pass, salted_hash);
1321 centry_put_hash16(centry, salted_hash);
1322 centry_put_hash16(centry, cred_salt);
1323 centry_end(centry, "CRED/%s", sid_to_fstring(sid_string, sid));
1325 DEBUG(10,("wcache_save_creds: %s\n", sid_string));
1327 centry_free(centry);
1329 return NT_STATUS_OK;
1333 /* Query display info. This is the basic user list fn */
1334 static NTSTATUS query_user_list(struct winbindd_domain *domain,
1335 TALLOC_CTX *mem_ctx,
1336 uint32 *num_entries,
1337 WINBIND_USERINFO **info)
1339 struct winbind_cache *cache = get_cache(domain);
1340 struct cache_entry *centry = NULL;
1342 unsigned int i, retry;
1347 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1351 *num_entries = centry_uint32(centry);
1353 if (*num_entries == 0)
1356 (*info) = TALLOC_ARRAY(mem_ctx, WINBIND_USERINFO, *num_entries);
1358 smb_panic_fn("query_user_list out of memory");
1360 for (i=0; i<(*num_entries); i++) {
1361 (*info)[i].acct_name = centry_string(centry, mem_ctx);
1362 (*info)[i].full_name = centry_string(centry, mem_ctx);
1363 (*info)[i].homedir = centry_string(centry, mem_ctx);
1364 (*info)[i].shell = centry_string(centry, mem_ctx);
1365 centry_sid(centry, &(*info)[i].user_sid);
1366 centry_sid(centry, &(*info)[i].group_sid);
1370 status = centry->status;
1372 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1373 domain->name, nt_errstr(status) ));
1375 centry_free(centry);
1382 /* Return status value returned by seq number check */
1384 if (!NT_STATUS_IS_OK(domain->last_status))
1385 return domain->last_status;
1387 /* Put the query_user_list() in a retry loop. There appears to be
1388 * some bug either with Windows 2000 or Samba's handling of large
1389 * rpc replies. This manifests itself as sudden disconnection
1390 * at a random point in the enumeration of a large (60k) user list.
1391 * The retry loop simply tries the operation again. )-: It's not
1392 * pretty but an acceptable workaround until we work out what the
1393 * real problem is. */
1398 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1401 status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
1402 if (!NT_STATUS_IS_OK(status)) {
1403 DEBUG(3, ("query_user_list: returned 0x%08x, "
1404 "retrying\n", NT_STATUS_V(status)));
1406 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1407 DEBUG(3, ("query_user_list: flushing "
1408 "connection cache\n"));
1409 invalidate_cm_connection(&domain->conn);
1412 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
1416 refresh_sequence_number(domain, false);
1417 centry = centry_start(domain, status);
1420 centry_put_uint32(centry, *num_entries);
1421 for (i=0; i<(*num_entries); i++) {
1422 centry_put_string(centry, (*info)[i].acct_name);
1423 centry_put_string(centry, (*info)[i].full_name);
1424 centry_put_string(centry, (*info)[i].homedir);
1425 centry_put_string(centry, (*info)[i].shell);
1426 centry_put_sid(centry, &(*info)[i].user_sid);
1427 centry_put_sid(centry, &(*info)[i].group_sid);
1428 if (domain->backend && domain->backend->consistent) {
1429 /* when the backend is consistent we can pre-prime some mappings */
1430 wcache_save_name_to_sid(domain, NT_STATUS_OK,
1432 (*info)[i].acct_name,
1433 &(*info)[i].user_sid,
1435 wcache_save_sid_to_name(domain, NT_STATUS_OK,
1436 &(*info)[i].user_sid,
1438 (*info)[i].acct_name,
1440 wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
1443 centry_end(centry, "UL/%s", domain->name);
1444 centry_free(centry);
1450 /* list all domain groups */
1451 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
1452 TALLOC_CTX *mem_ctx,
1453 uint32 *num_entries,
1454 struct acct_info **info)
1456 struct winbind_cache *cache = get_cache(domain);
1457 struct cache_entry *centry = NULL;
1464 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1468 *num_entries = centry_uint32(centry);
1470 if (*num_entries == 0)
1473 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1475 smb_panic_fn("enum_dom_groups out of memory");
1477 for (i=0; i<(*num_entries); i++) {
1478 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1479 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1480 (*info)[i].rid = centry_uint32(centry);
1484 status = centry->status;
1486 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1487 domain->name, nt_errstr(status) ));
1489 centry_free(centry);
1496 /* Return status value returned by seq number check */
1498 if (!NT_STATUS_IS_OK(domain->last_status))
1499 return domain->last_status;
1501 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1504 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1507 refresh_sequence_number(domain, false);
1508 centry = centry_start(domain, status);
1511 centry_put_uint32(centry, *num_entries);
1512 for (i=0; i<(*num_entries); i++) {
1513 centry_put_string(centry, (*info)[i].acct_name);
1514 centry_put_string(centry, (*info)[i].acct_desc);
1515 centry_put_uint32(centry, (*info)[i].rid);
1517 centry_end(centry, "GL/%s/domain", domain->name);
1518 centry_free(centry);
1524 /* list all domain groups */
1525 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
1526 TALLOC_CTX *mem_ctx,
1527 uint32 *num_entries,
1528 struct acct_info **info)
1530 struct winbind_cache *cache = get_cache(domain);
1531 struct cache_entry *centry = NULL;
1538 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1542 *num_entries = centry_uint32(centry);
1544 if (*num_entries == 0)
1547 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1549 smb_panic_fn("enum_dom_groups out of memory");
1551 for (i=0; i<(*num_entries); i++) {
1552 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1553 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1554 (*info)[i].rid = centry_uint32(centry);
1559 /* If we are returning cached data and the domain controller
1560 is down then we don't know whether the data is up to date
1561 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1564 if (wcache_server_down(domain)) {
1565 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1566 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1568 status = centry->status;
1570 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1571 domain->name, nt_errstr(status) ));
1573 centry_free(centry);
1580 /* Return status value returned by seq number check */
1582 if (!NT_STATUS_IS_OK(domain->last_status))
1583 return domain->last_status;
1585 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1588 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1591 refresh_sequence_number(domain, false);
1592 centry = centry_start(domain, status);
1595 centry_put_uint32(centry, *num_entries);
1596 for (i=0; i<(*num_entries); i++) {
1597 centry_put_string(centry, (*info)[i].acct_name);
1598 centry_put_string(centry, (*info)[i].acct_desc);
1599 centry_put_uint32(centry, (*info)[i].rid);
1601 centry_end(centry, "GL/%s/local", domain->name);
1602 centry_free(centry);
1608 NTSTATUS wcache_name_to_sid(struct winbindd_domain *domain,
1609 const char *domain_name,
1611 struct dom_sid *sid,
1612 enum lsa_SidType *type)
1614 struct winbind_cache *cache = get_cache(domain);
1615 struct cache_entry *centry;
1619 if (cache->tdb == NULL) {
1620 return NT_STATUS_NOT_FOUND;
1623 uname = talloc_strdup_upper(talloc_tos(), name);
1624 if (uname == NULL) {
1625 return NT_STATUS_NO_MEMORY;
1628 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1630 if (centry == NULL) {
1631 return NT_STATUS_NOT_FOUND;
1634 status = centry->status;
1635 if (NT_STATUS_IS_OK(status)) {
1636 *type = (enum lsa_SidType)centry_uint32(centry);
1637 centry_sid(centry, sid);
1640 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1641 "%s\n", domain->name, nt_errstr(status) ));
1643 centry_free(centry);
1647 /* convert a single name to a sid in a domain */
1648 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
1649 TALLOC_CTX *mem_ctx,
1650 const char *domain_name,
1654 enum lsa_SidType *type)
1658 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1659 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1665 /* If the seq number check indicated that there is a problem
1666 * with this DC, then return that status... except for
1667 * access_denied. This is special because the dc may be in
1668 * "restrict anonymous = 1" mode, in which case it will deny
1669 * most unauthenticated operations, but *will* allow the LSA
1670 * name-to-sid that we try as a fallback. */
1672 if (!(NT_STATUS_IS_OK(domain->last_status)
1673 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1674 return domain->last_status;
1676 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1679 status = domain->backend->name_to_sid(domain, mem_ctx, domain_name,
1680 name, flags, sid, type);
1683 refresh_sequence_number(domain, false);
1685 if (domain->online &&
1686 (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
1687 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1689 /* Only save the reverse mapping if this was not a UPN */
1690 if (!strchr(name, '@')) {
1691 strupper_m(CONST_DISCARD(char *,domain_name));
1692 strlower_m(CONST_DISCARD(char *,name));
1693 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1700 NTSTATUS wcache_sid_to_name(struct winbindd_domain *domain,
1701 const struct dom_sid *sid,
1702 TALLOC_CTX *mem_ctx,
1705 enum lsa_SidType *type)
1707 struct winbind_cache *cache = get_cache(domain);
1708 struct cache_entry *centry;
1712 if (cache->tdb == NULL) {
1713 return NT_STATUS_NOT_FOUND;
1716 sid_string = sid_string_tos(sid);
1717 if (sid_string == NULL) {
1718 return NT_STATUS_NO_MEMORY;
1721 centry = wcache_fetch(cache, domain, "SN/%s", sid_string);
1722 TALLOC_FREE(sid_string);
1723 if (centry == NULL) {
1724 return NT_STATUS_NOT_FOUND;
1727 if (NT_STATUS_IS_OK(centry->status)) {
1728 *type = (enum lsa_SidType)centry_uint32(centry);
1729 *domain_name = centry_string(centry, mem_ctx);
1730 *name = centry_string(centry, mem_ctx);
1733 status = centry->status;
1734 centry_free(centry);
1736 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1737 "%s\n", domain->name, nt_errstr(status) ));
1742 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1744 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
1745 TALLOC_CTX *mem_ctx,
1749 enum lsa_SidType *type)
1753 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
1755 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1760 *domain_name = NULL;
1762 /* If the seq number check indicated that there is a problem
1763 * with this DC, then return that status... except for
1764 * access_denied. This is special because the dc may be in
1765 * "restrict anonymous = 1" mode, in which case it will deny
1766 * most unauthenticated operations, but *will* allow the LSA
1767 * sid-to-name that we try as a fallback. */
1769 if (!(NT_STATUS_IS_OK(domain->last_status)
1770 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1771 return domain->last_status;
1773 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1776 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1779 refresh_sequence_number(domain, false);
1780 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1782 /* We can't save the name to sid mapping here, as with sid history a
1783 * later name2sid would give the wrong sid. */
1788 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
1789 TALLOC_CTX *mem_ctx,
1790 const DOM_SID *domain_sid,
1795 enum lsa_SidType **types)
1797 struct winbind_cache *cache = get_cache(domain);
1799 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1803 *domain_name = NULL;
1811 if (num_rids == 0) {
1812 return NT_STATUS_OK;
1815 *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
1816 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
1818 if ((*names == NULL) || (*types == NULL)) {
1819 result = NT_STATUS_NO_MEMORY;
1823 have_mapped = have_unmapped = false;
1825 for (i=0; i<num_rids; i++) {
1827 struct cache_entry *centry;
1830 if (!sid_compose(&sid, domain_sid, rids[i])) {
1831 result = NT_STATUS_INTERNAL_ERROR;
1835 centry = wcache_fetch(cache, domain, "SN/%s",
1836 sid_to_fstring(tmp, &sid));
1841 (*types)[i] = SID_NAME_UNKNOWN;
1842 (*names)[i] = talloc_strdup(*names, "");
1844 if (NT_STATUS_IS_OK(centry->status)) {
1847 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
1849 dom = centry_string(centry, mem_ctx);
1850 if (*domain_name == NULL) {
1856 (*names)[i] = centry_string(centry, *names);
1858 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
1859 have_unmapped = true;
1862 /* something's definitely wrong */
1863 result = centry->status;
1867 centry_free(centry);
1871 return NT_STATUS_NONE_MAPPED;
1873 if (!have_unmapped) {
1874 return NT_STATUS_OK;
1876 return STATUS_SOME_UNMAPPED;
1880 TALLOC_FREE(*names);
1881 TALLOC_FREE(*types);
1883 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
1884 rids, num_rids, domain_name,
1888 None of the queried rids has been found so save all negative entries
1890 if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
1891 for (i = 0; i < num_rids; i++) {
1893 const char *name = "";
1894 const enum lsa_SidType type = SID_NAME_UNKNOWN;
1895 NTSTATUS status = NT_STATUS_NONE_MAPPED;
1897 if (!sid_compose(&sid, domain_sid, rids[i])) {
1898 return NT_STATUS_INTERNAL_ERROR;
1901 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
1909 Some or all of the queried rids have been found.
1911 if (!NT_STATUS_IS_OK(result) &&
1912 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
1916 refresh_sequence_number(domain, false);
1918 for (i=0; i<num_rids; i++) {
1922 if (!sid_compose(&sid, domain_sid, rids[i])) {
1923 result = NT_STATUS_INTERNAL_ERROR;
1927 status = (*types)[i] == SID_NAME_UNKNOWN ?
1928 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
1930 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
1931 (*names)[i], (*types)[i]);
1937 TALLOC_FREE(*names);
1938 TALLOC_FREE(*types);
1942 NTSTATUS wcache_query_user(struct winbindd_domain *domain,
1943 TALLOC_CTX *mem_ctx,
1944 const struct dom_sid *user_sid,
1945 struct winbind_userinfo *info)
1947 struct winbind_cache *cache = get_cache(domain);
1948 struct cache_entry *centry = NULL;
1952 if (cache->tdb == NULL) {
1953 return NT_STATUS_NOT_FOUND;
1956 sid_string = sid_string_tos(user_sid);
1957 if (sid_string == NULL) {
1958 return NT_STATUS_NO_MEMORY;
1961 centry = wcache_fetch(cache, domain, "U/%s", sid_string);
1962 TALLOC_FREE(sid_string);
1963 if (centry == NULL) {
1964 return NT_STATUS_NOT_FOUND;
1968 * If we have an access denied cache entry and a cached info3
1969 * in the samlogon cache then do a query. This will force the
1970 * rpc back end to return the info3 data.
1973 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED) &&
1974 netsamlogon_cache_have(user_sid)) {
1975 DEBUG(10, ("query_user: cached access denied and have cached "
1977 domain->last_status = NT_STATUS_OK;
1978 centry_free(centry);
1979 return NT_STATUS_NOT_FOUND;
1982 /* if status is not ok then this is a negative hit
1983 and the rest of the data doesn't matter */
1984 status = centry->status;
1985 if (NT_STATUS_IS_OK(status)) {
1986 info->acct_name = centry_string(centry, mem_ctx);
1987 info->full_name = centry_string(centry, mem_ctx);
1988 info->homedir = centry_string(centry, mem_ctx);
1989 info->shell = centry_string(centry, mem_ctx);
1990 info->primary_gid = centry_uint32(centry);
1991 centry_sid(centry, &info->user_sid);
1992 centry_sid(centry, &info->group_sid);
1995 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
1996 "%s\n", domain->name, nt_errstr(status) ));
1998 centry_free(centry);
2002 /* Lookup user information from a rid */
2003 static NTSTATUS query_user(struct winbindd_domain *domain,
2004 TALLOC_CTX *mem_ctx,
2005 const DOM_SID *user_sid,
2006 WINBIND_USERINFO *info)
2010 status = wcache_query_user(domain, mem_ctx, user_sid, info);
2011 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2017 /* Return status value returned by seq number check */
2019 if (!NT_STATUS_IS_OK(domain->last_status))
2020 return domain->last_status;
2022 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2025 status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
2028 refresh_sequence_number(domain, false);
2029 wcache_save_user(domain, status, info);
2034 NTSTATUS wcache_lookup_usergroups(struct winbindd_domain *domain,
2035 TALLOC_CTX *mem_ctx,
2036 const struct dom_sid *user_sid,
2037 uint32_t *pnum_sids,
2038 struct dom_sid **psids)
2040 struct winbind_cache *cache = get_cache(domain);
2041 struct cache_entry *centry = NULL;
2043 uint32_t i, num_sids;
2044 struct dom_sid *sids;
2047 if (cache->tdb == NULL) {
2048 return NT_STATUS_NOT_FOUND;
2051 centry = wcache_fetch(cache, domain, "UG/%s",
2052 sid_to_fstring(sid_string, user_sid));
2053 if (centry == NULL) {
2054 return NT_STATUS_NOT_FOUND;
2057 /* If we have an access denied cache entry and a cached info3 in the
2058 samlogon cache then do a query. This will force the rpc back end
2059 to return the info3 data. */
2061 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)
2062 && netsamlogon_cache_have(user_sid)) {
2063 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2065 domain->last_status = NT_STATUS_OK;
2066 centry_free(centry);
2067 return NT_STATUS_NOT_FOUND;
2070 num_sids = centry_uint32(centry);
2071 sids = talloc_array(mem_ctx, struct dom_sid, num_sids);
2073 return NT_STATUS_NO_MEMORY;
2076 for (i=0; i<num_sids; i++) {
2077 centry_sid(centry, &sids[i]);
2080 status = centry->status;
2082 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2083 "status: %s\n", domain->name, nt_errstr(status)));
2085 centry_free(centry);
2087 *pnum_sids = num_sids;
2092 /* Lookup groups a user is a member of. */
2093 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
2094 TALLOC_CTX *mem_ctx,
2095 const DOM_SID *user_sid,
2096 uint32 *num_groups, DOM_SID **user_gids)
2098 struct cache_entry *centry = NULL;
2103 status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2104 num_groups, user_gids);
2105 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2110 (*user_gids) = NULL;
2112 /* Return status value returned by seq number check */
2114 if (!NT_STATUS_IS_OK(domain->last_status))
2115 return domain->last_status;
2117 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2120 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
2122 if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
2126 refresh_sequence_number(domain, false);
2127 centry = centry_start(domain, status);
2131 centry_put_uint32(centry, *num_groups);
2132 for (i=0; i<(*num_groups); i++) {
2133 centry_put_sid(centry, &(*user_gids)[i]);
2136 centry_end(centry, "UG/%s", sid_to_fstring(sid_string, user_sid));
2137 centry_free(centry);
2143 static char *wcache_make_sidlist(TALLOC_CTX *mem_ctx, uint32_t num_sids,
2144 const struct dom_sid *sids)
2149 sidlist = talloc_strdup(mem_ctx, "");
2150 if (sidlist == NULL) {
2153 for (i=0; i<num_sids; i++) {
2155 sidlist = talloc_asprintf_append_buffer(
2156 sidlist, "/%s", sid_to_fstring(tmp, &sids[i]));
2157 if (sidlist == NULL) {
2164 NTSTATUS wcache_lookup_useraliases(struct winbindd_domain *domain,
2165 TALLOC_CTX *mem_ctx, uint32_t num_sids,
2166 const struct dom_sid *sids,
2167 uint32_t *pnum_aliases, uint32_t **paliases)
2169 struct winbind_cache *cache = get_cache(domain);
2170 struct cache_entry *centry = NULL;
2171 uint32_t num_aliases;
2177 if (cache->tdb == NULL) {
2178 return NT_STATUS_NOT_FOUND;
2181 if (num_sids == 0) {
2184 return NT_STATUS_OK;
2187 /* We need to cache indexed by the whole list of SIDs, the aliases
2188 * resulting might come from any of the SIDs. */
2190 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2191 if (sidlist == NULL) {
2192 return NT_STATUS_NO_MEMORY;
2195 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
2196 TALLOC_FREE(sidlist);
2197 if (centry == NULL) {
2198 return NT_STATUS_NOT_FOUND;
2201 num_aliases = centry_uint32(centry);
2202 aliases = talloc_array(mem_ctx, uint32_t, num_aliases);
2203 if (aliases == NULL) {
2204 centry_free(centry);
2205 return NT_STATUS_NO_MEMORY;
2208 for (i=0; i<num_aliases; i++) {
2209 aliases[i] = centry_uint32(centry);
2212 status = centry->status;
2214 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2215 "status %s\n", domain->name, nt_errstr(status)));
2217 centry_free(centry);
2219 *pnum_aliases = num_aliases;
2220 *paliases = aliases;
2225 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
2226 TALLOC_CTX *mem_ctx,
2227 uint32 num_sids, const DOM_SID *sids,
2228 uint32 *num_aliases, uint32 **alias_rids)
2230 struct cache_entry *centry = NULL;
2235 status = wcache_lookup_useraliases(domain, mem_ctx, num_sids, sids,
2236 num_aliases, alias_rids);
2237 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2242 (*alias_rids) = NULL;
2244 if (!NT_STATUS_IS_OK(domain->last_status))
2245 return domain->last_status;
2247 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2248 "for domain %s\n", domain->name ));
2250 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2251 if (sidlist == NULL) {
2252 return NT_STATUS_NO_MEMORY;
2255 status = domain->backend->lookup_useraliases(domain, mem_ctx,
2257 num_aliases, alias_rids);
2260 refresh_sequence_number(domain, false);
2261 centry = centry_start(domain, status);
2264 centry_put_uint32(centry, *num_aliases);
2265 for (i=0; i<(*num_aliases); i++)
2266 centry_put_uint32(centry, (*alias_rids)[i]);
2267 centry_end(centry, "UA%s", sidlist);
2268 centry_free(centry);
2275 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
2276 TALLOC_CTX *mem_ctx,
2277 const DOM_SID *group_sid, uint32 *num_names,
2278 DOM_SID **sid_mem, char ***names,
2279 uint32 **name_types)
2281 struct winbind_cache *cache = get_cache(domain);
2282 struct cache_entry *centry = NULL;
2290 centry = wcache_fetch(cache, domain, "GM/%s",
2291 sid_to_fstring(sid_string, group_sid));
2295 *num_names = centry_uint32(centry);
2297 if (*num_names == 0)
2300 (*sid_mem) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_names);
2301 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_names);
2302 (*name_types) = TALLOC_ARRAY(mem_ctx, uint32, *num_names);
2304 if (! (*sid_mem) || ! (*names) || ! (*name_types)) {
2305 smb_panic_fn("lookup_groupmem out of memory");
2308 for (i=0; i<(*num_names); i++) {
2309 centry_sid(centry, &(*sid_mem)[i]);
2310 (*names)[i] = centry_string(centry, mem_ctx);
2311 (*name_types)[i] = centry_uint32(centry);
2315 status = centry->status;
2317 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status: %s\n",
2318 domain->name, nt_errstr(status)));
2320 centry_free(centry);
2327 (*name_types) = NULL;
2329 /* Return status value returned by seq number check */
2331 if (!NT_STATUS_IS_OK(domain->last_status))
2332 return domain->last_status;
2334 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2337 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid, num_names,
2338 sid_mem, names, name_types);
2341 refresh_sequence_number(domain, false);
2342 centry = centry_start(domain, status);
2345 centry_put_uint32(centry, *num_names);
2346 for (i=0; i<(*num_names); i++) {
2347 centry_put_sid(centry, &(*sid_mem)[i]);
2348 centry_put_string(centry, (*names)[i]);
2349 centry_put_uint32(centry, (*name_types)[i]);
2351 centry_end(centry, "GM/%s", sid_to_fstring(sid_string, group_sid));
2352 centry_free(centry);
2358 /* find the sequence number for a domain */
2359 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
2361 refresh_sequence_number(domain, false);
2363 *seq = domain->sequence_number;
2365 return NT_STATUS_OK;
2368 /* enumerate trusted domains
2369 * (we need to have the list of trustdoms in the cache when we go offline) -
2371 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
2372 TALLOC_CTX *mem_ctx,
2373 uint32 *num_domains,
2378 struct winbind_cache *cache = get_cache(domain);
2379 struct cache_entry *centry = NULL;
2386 centry = wcache_fetch(cache, domain, "TRUSTDOMS/%s", domain->name);
2392 *num_domains = centry_uint32(centry);
2395 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
2396 (*alt_names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
2397 (*dom_sids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
2399 if (! (*dom_sids) || ! (*names) || ! (*alt_names)) {
2400 smb_panic_fn("trusted_domains out of memory");
2404 (*alt_names) = NULL;
2408 for (i=0; i<(*num_domains); i++) {
2409 (*names)[i] = centry_string(centry, mem_ctx);
2410 (*alt_names)[i] = centry_string(centry, mem_ctx);
2411 if (!centry_sid(centry, &(*dom_sids)[i])) {
2412 sid_copy(&(*dom_sids)[i], &global_sid_NULL);
2416 status = centry->status;
2418 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
2419 domain->name, *num_domains, nt_errstr(status) ));
2421 centry_free(centry);
2428 (*alt_names) = NULL;
2430 /* Return status value returned by seq number check */
2432 if (!NT_STATUS_IS_OK(domain->last_status))
2433 return domain->last_status;
2435 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2438 status = domain->backend->trusted_domains(domain, mem_ctx, num_domains,
2439 names, alt_names, dom_sids);
2441 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2442 * so that the generic centry handling still applies correctly -
2445 if (!NT_STATUS_IS_ERR(status)) {
2446 status = NT_STATUS_OK;
2450 #if 0 /* Disabled as we want the trust dom list to be managed by
2451 the main parent and always to make the query. --jerry */
2454 refresh_sequence_number(domain, false);
2456 centry = centry_start(domain, status);
2460 centry_put_uint32(centry, *num_domains);
2462 for (i=0; i<(*num_domains); i++) {
2463 centry_put_string(centry, (*names)[i]);
2464 centry_put_string(centry, (*alt_names)[i]);
2465 centry_put_sid(centry, &(*dom_sids)[i]);
2468 centry_end(centry, "TRUSTDOMS/%s", domain->name);
2470 centry_free(centry);
2478 /* get lockout policy */
2479 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
2480 TALLOC_CTX *mem_ctx,
2481 struct samr_DomInfo12 *policy)
2483 struct winbind_cache *cache = get_cache(domain);
2484 struct cache_entry *centry = NULL;
2490 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2495 policy->lockout_duration = centry_nttime(centry);
2496 policy->lockout_window = centry_nttime(centry);
2497 policy->lockout_threshold = centry_uint16(centry);
2499 status = centry->status;
2501 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2502 domain->name, nt_errstr(status) ));
2504 centry_free(centry);
2508 ZERO_STRUCTP(policy);
2510 /* Return status value returned by seq number check */
2512 if (!NT_STATUS_IS_OK(domain->last_status))
2513 return domain->last_status;
2515 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2518 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2521 refresh_sequence_number(domain, false);
2522 wcache_save_lockout_policy(domain, status, policy);
2527 /* get password policy */
2528 static NTSTATUS password_policy(struct winbindd_domain *domain,
2529 TALLOC_CTX *mem_ctx,
2530 struct samr_DomInfo1 *policy)
2532 struct winbind_cache *cache = get_cache(domain);
2533 struct cache_entry *centry = NULL;
2539 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2544 policy->min_password_length = centry_uint16(centry);
2545 policy->password_history_length = centry_uint16(centry);
2546 policy->password_properties = centry_uint32(centry);
2547 policy->max_password_age = centry_nttime(centry);
2548 policy->min_password_age = centry_nttime(centry);
2550 status = centry->status;
2552 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2553 domain->name, nt_errstr(status) ));
2555 centry_free(centry);
2559 ZERO_STRUCTP(policy);
2561 /* Return status value returned by seq number check */
2563 if (!NT_STATUS_IS_OK(domain->last_status))
2564 return domain->last_status;
2566 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2569 status = domain->backend->password_policy(domain, mem_ctx, policy);
2572 refresh_sequence_number(domain, false);
2573 if (NT_STATUS_IS_OK(status)) {
2574 wcache_save_password_policy(domain, status, policy);
2581 /* Invalidate cached user and group lists coherently */
2583 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2586 if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
2587 strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
2588 tdb_delete(the_tdb, kbuf);
2593 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2595 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
2596 struct netr_SamInfo3 *info3)
2599 fstring key_str, sid_string;
2600 struct winbind_cache *cache;
2602 /* dont clear cached U/SID and UG/SID entries when we want to logon
2605 if (lp_winbind_offline_logon()) {
2612 cache = get_cache(domain);
2618 sid_copy(&sid, info3->base.domain_sid);
2619 sid_append_rid(&sid, info3->base.rid);
2621 /* Clear U/SID cache entry */
2622 fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, &sid));
2623 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
2624 tdb_delete(cache->tdb, string_tdb_data(key_str));
2626 /* Clear UG/SID cache entry */
2627 fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, &sid));
2628 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
2629 tdb_delete(cache->tdb, string_tdb_data(key_str));
2631 /* Samba/winbindd never needs this. */
2632 netsamlogon_clear_cached_user(info3);
2635 bool wcache_invalidate_cache(void)
2637 struct winbindd_domain *domain;
2639 for (domain = domain_list(); domain; domain = domain->next) {
2640 struct winbind_cache *cache = get_cache(domain);
2642 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2643 "entries for %s\n", domain->name));
2646 tdb_traverse(cache->tdb, traverse_fn, NULL);
2655 bool init_wcache(void)
2657 if (wcache == NULL) {
2658 wcache = SMB_XMALLOC_P(struct winbind_cache);
2659 ZERO_STRUCTP(wcache);
2662 if (wcache->tdb != NULL)
2665 /* when working offline we must not clear the cache on restart */
2666 wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
2667 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2668 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
2669 O_RDWR|O_CREAT, 0600);
2671 if (wcache->tdb == NULL) {
2672 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2679 /************************************************************************
2680 This is called by the parent to initialize the cache file.
2681 We don't need sophisticated locking here as we know we're the
2683 ************************************************************************/
2685 bool initialize_winbindd_cache(void)
2687 bool cache_bad = true;
2690 if (!init_wcache()) {
2691 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
2695 /* Check version number. */
2696 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
2697 vers == WINBINDD_CACHE_VERSION) {
2702 DEBUG(0,("initialize_winbindd_cache: clearing cache "
2703 "and re-creating with version number %d\n",
2704 WINBINDD_CACHE_VERSION ));
2706 tdb_close(wcache->tdb);
2709 if (unlink(cache_path("winbindd_cache.tdb")) == -1) {
2710 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
2711 cache_path("winbindd_cache.tdb"),
2715 if (!init_wcache()) {
2716 DEBUG(0,("initialize_winbindd_cache: re-initialization "
2717 "init_wcache failed.\n"));
2721 /* Write the version. */
2722 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
2723 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
2724 tdb_errorstr(wcache->tdb) ));
2729 tdb_close(wcache->tdb);
2734 void close_winbindd_cache(void)
2740 tdb_close(wcache->tdb);
2745 bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
2746 char **domain_name, char **name,
2747 enum lsa_SidType *type)
2749 struct winbindd_domain *domain;
2752 domain = find_lookup_domain_from_sid(sid);
2753 if (domain == NULL) {
2756 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
2758 return NT_STATUS_IS_OK(status);
2761 bool lookup_cached_name(TALLOC_CTX *mem_ctx,
2762 const char *domain_name,
2765 enum lsa_SidType *type)
2767 struct winbindd_domain *domain;
2769 bool original_online_state;
2771 domain = find_lookup_domain_from_name(domain_name);
2772 if (domain == NULL) {
2776 /* If we are doing a cached logon, temporarily set the domain
2777 offline so the cache won't expire the entry */
2779 original_online_state = domain->online;
2780 domain->online = false;
2781 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
2782 domain->online = original_online_state;
2784 return NT_STATUS_IS_OK(status);
2787 void cache_name2sid(struct winbindd_domain *domain,
2788 const char *domain_name, const char *name,
2789 enum lsa_SidType type, const DOM_SID *sid)
2791 refresh_sequence_number(domain, false);
2792 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
2797 * The original idea that this cache only contains centries has
2798 * been blurred - now other stuff gets put in here. Ensure we
2799 * ignore these things on cleanup.
2802 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
2803 TDB_DATA dbuf, void *state)
2805 struct cache_entry *centry;
2807 if (is_non_centry_key(kbuf)) {
2811 centry = wcache_fetch_raw((char *)kbuf.dptr);
2816 if (!NT_STATUS_IS_OK(centry->status)) {
2817 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
2818 tdb_delete(the_tdb, kbuf);
2821 centry_free(centry);
2825 /* flush the cache */
2826 void wcache_flush_cache(void)
2831 tdb_close(wcache->tdb);
2834 if (!winbindd_use_cache()) {
2838 /* when working offline we must not clear the cache on restart */
2839 wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
2840 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2841 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
2842 O_RDWR|O_CREAT, 0600);
2845 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2849 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
2851 DEBUG(10,("wcache_flush_cache success\n"));
2854 /* Count cached creds */
2856 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2859 int *cred_count = (int*)state;
2861 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
2867 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
2869 struct winbind_cache *cache = get_cache(domain);
2874 return NT_STATUS_INTERNAL_DB_ERROR;
2877 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
2879 return NT_STATUS_OK;
2883 struct cred_list *prev, *next;
2888 static struct cred_list *wcache_cred_list;
2890 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2893 struct cred_list *cred;
2895 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
2897 cred = SMB_MALLOC_P(struct cred_list);
2899 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2905 /* save a copy of the key */
2907 fstrcpy(cred->name, (const char *)kbuf.dptr);
2908 DLIST_ADD(wcache_cred_list, cred);
2914 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const DOM_SID *sid)
2916 struct winbind_cache *cache = get_cache(domain);
2919 struct cred_list *cred, *oldest = NULL;
2922 return NT_STATUS_INTERNAL_DB_ERROR;
2925 /* we possibly already have an entry */
2926 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
2928 fstring key_str, tmp;
2930 DEBUG(11,("we already have an entry, deleting that\n"));
2932 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
2934 tdb_delete(cache->tdb, string_tdb_data(key_str));
2936 return NT_STATUS_OK;
2939 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
2941 return NT_STATUS_OK;
2942 } else if ((ret == -1) || (wcache_cred_list == NULL)) {
2943 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2946 ZERO_STRUCTP(oldest);
2948 for (cred = wcache_cred_list; cred; cred = cred->next) {
2953 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
2955 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
2957 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
2961 t = IVAL(data.dptr, 0);
2962 SAFE_FREE(data.dptr);
2965 oldest = SMB_MALLOC_P(struct cred_list);
2966 if (oldest == NULL) {
2967 status = NT_STATUS_NO_MEMORY;
2971 fstrcpy(oldest->name, cred->name);
2972 oldest->created = t;
2976 if (t < oldest->created) {
2977 fstrcpy(oldest->name, cred->name);
2978 oldest->created = t;
2982 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
2983 status = NT_STATUS_OK;
2985 status = NT_STATUS_UNSUCCESSFUL;
2988 SAFE_FREE(wcache_cred_list);
2994 /* Change the global online/offline state. */
2995 bool set_global_winbindd_state_offline(void)
2999 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3001 /* Only go offline if someone has created
3002 the key "WINBINDD_OFFLINE" in the cache tdb. */
3004 if (wcache == NULL || wcache->tdb == NULL) {
3005 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3009 if (!lp_winbind_offline_logon()) {
3010 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3014 if (global_winbindd_offline_state) {
3015 /* Already offline. */
3019 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
3021 if (!data.dptr || data.dsize != 4) {
3022 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3023 SAFE_FREE(data.dptr);
3026 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3027 global_winbindd_offline_state = true;
3028 SAFE_FREE(data.dptr);
3033 void set_global_winbindd_state_online(void)
3035 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3037 if (!lp_winbind_offline_logon()) {
3038 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3042 if (!global_winbindd_offline_state) {
3043 /* Already online. */
3046 global_winbindd_offline_state = false;
3052 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3053 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
3056 bool get_global_winbindd_state_offline(void)
3058 return global_winbindd_offline_state;
3061 /***********************************************************************
3062 Validate functions for all possible cache tdb keys.
3063 ***********************************************************************/
3065 static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
3066 struct tdb_validation_status *state)
3068 struct cache_entry *centry;
3070 centry = SMB_XMALLOC_P(struct cache_entry);
3071 centry->data = (unsigned char *)memdup(data.dptr, data.dsize);
3072 if (!centry->data) {
3076 centry->len = data.dsize;
3079 if (centry->len < 8) {
3080 /* huh? corrupt cache? */
3081 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr));
3082 centry_free(centry);
3083 state->bad_entry = true;
3084 state->success = false;
3088 centry->status = NT_STATUS(centry_uint32(centry));
3089 centry->sequence_number = centry_uint32(centry);
3093 static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3094 struct tdb_validation_status *state)
3096 if (dbuf.dsize != 8) {
3097 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3098 keystr, (unsigned int)dbuf.dsize ));
3099 state->bad_entry = true;
3105 static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3106 struct tdb_validation_status *state)
3108 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3113 (void)centry_uint32(centry);
3114 if (NT_STATUS_IS_OK(centry->status)) {
3116 (void)centry_sid(centry, &sid);
3119 centry_free(centry);
3121 if (!(state->success)) {
3124 DEBUG(10,("validate_ns: %s ok\n", keystr));
3128 static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3129 struct tdb_validation_status *state)
3131 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3136 if (NT_STATUS_IS_OK(centry->status)) {
3137 (void)centry_uint32(centry);
3138 (void)centry_string(centry, mem_ctx);
3139 (void)centry_string(centry, mem_ctx);
3142 centry_free(centry);
3144 if (!(state->success)) {
3147 DEBUG(10,("validate_sn: %s ok\n", keystr));
3151 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3152 struct tdb_validation_status *state)
3154 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3161 (void)centry_string(centry, mem_ctx);
3162 (void)centry_string(centry, mem_ctx);
3163 (void)centry_string(centry, mem_ctx);
3164 (void)centry_string(centry, mem_ctx);
3165 (void)centry_uint32(centry);
3166 (void)centry_sid(centry, &sid);
3167 (void)centry_sid(centry, &sid);
3169 centry_free(centry);
3171 if (!(state->success)) {
3174 DEBUG(10,("validate_u: %s ok\n", keystr));
3178 static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3179 struct tdb_validation_status *state)
3181 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3187 (void)centry_nttime(centry);
3188 (void)centry_nttime(centry);
3189 (void)centry_uint16(centry);
3191 centry_free(centry);
3193 if (!(state->success)) {
3196 DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
3200 static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3201 struct tdb_validation_status *state)
3203 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3209 (void)centry_uint16(centry);
3210 (void)centry_uint16(centry);
3211 (void)centry_uint32(centry);
3212 (void)centry_nttime(centry);
3213 (void)centry_nttime(centry);
3215 centry_free(centry);
3217 if (!(state->success)) {
3220 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
3224 static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3225 struct tdb_validation_status *state)
3227 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3233 (void)centry_time(centry);
3234 (void)centry_hash16(centry, mem_ctx);
3236 /* We only have 17 bytes more data in the salted cred case. */
3237 if (centry->len - centry->ofs == 17) {
3238 (void)centry_hash16(centry, mem_ctx);
3241 centry_free(centry);
3243 if (!(state->success)) {
3246 DEBUG(10,("validate_cred: %s ok\n", keystr));
3250 static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3251 struct tdb_validation_status *state)
3253 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3254 int32 num_entries, i;
3260 num_entries = (int32)centry_uint32(centry);
3262 for (i=0; i< num_entries; i++) {
3264 (void)centry_string(centry, mem_ctx);
3265 (void)centry_string(centry, mem_ctx);
3266 (void)centry_string(centry, mem_ctx);
3267 (void)centry_string(centry, mem_ctx);
3268 (void)centry_sid(centry, &sid);
3269 (void)centry_sid(centry, &sid);
3272 centry_free(centry);
3274 if (!(state->success)) {
3277 DEBUG(10,("validate_ul: %s ok\n", keystr));
3281 static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3282 struct tdb_validation_status *state)
3284 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3285 int32 num_entries, i;
3291 num_entries = centry_uint32(centry);
3293 for (i=0; i< num_entries; i++) {
3294 (void)centry_string(centry, mem_ctx);
3295 (void)centry_string(centry, mem_ctx);
3296 (void)centry_uint32(centry);
3299 centry_free(centry);
3301 if (!(state->success)) {
3304 DEBUG(10,("validate_gl: %s ok\n", keystr));
3308 static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3309 struct tdb_validation_status *state)
3311 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3312 int32 num_groups, i;
3318 num_groups = centry_uint32(centry);
3320 for (i=0; i< num_groups; i++) {
3322 centry_sid(centry, &sid);
3325 centry_free(centry);
3327 if (!(state->success)) {
3330 DEBUG(10,("validate_ug: %s ok\n", keystr));
3334 static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3335 struct tdb_validation_status *state)
3337 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3338 int32 num_aliases, i;
3344 num_aliases = centry_uint32(centry);
3346 for (i=0; i < num_aliases; i++) {
3347 (void)centry_uint32(centry);
3350 centry_free(centry);
3352 if (!(state->success)) {
3355 DEBUG(10,("validate_ua: %s ok\n", keystr));
3359 static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3360 struct tdb_validation_status *state)
3362 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3369 num_names = centry_uint32(centry);
3371 for (i=0; i< num_names; i++) {
3373 centry_sid(centry, &sid);
3374 (void)centry_string(centry, mem_ctx);
3375 (void)centry_uint32(centry);
3378 centry_free(centry);
3380 if (!(state->success)) {
3383 DEBUG(10,("validate_gm: %s ok\n", keystr));
3387 static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3388 struct tdb_validation_status *state)
3390 /* Can't say anything about this other than must be nonzero. */
3391 if (dbuf.dsize == 0) {
3392 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3394 state->bad_entry = true;
3395 state->success = false;
3399 DEBUG(10,("validate_dr: %s ok\n", keystr));
3403 static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3404 struct tdb_validation_status *state)
3406 /* Can't say anything about this other than must be nonzero. */
3407 if (dbuf.dsize == 0) {
3408 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3410 state->bad_entry = true;
3411 state->success = false;
3415 DEBUG(10,("validate_de: %s ok\n", keystr));
3419 static int validate_pwinfo(TALLOC_CTX *mem_ctx, const char *keystr,
3420 TDB_DATA dbuf, struct tdb_validation_status *state)
3422 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3428 (void)centry_string(centry, mem_ctx);
3429 (void)centry_string(centry, mem_ctx);
3430 (void)centry_string(centry, mem_ctx);
3431 (void)centry_uint32(centry);
3433 centry_free(centry);
3435 if (!(state->success)) {
3438 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3442 static int validate_nss_an(TALLOC_CTX *mem_ctx, const char *keystr,
3444 struct tdb_validation_status *state)
3446 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3452 (void)centry_string( centry, mem_ctx );
3454 centry_free(centry);
3456 if (!(state->success)) {
3459 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3463 static int validate_nss_na(TALLOC_CTX *mem_ctx, const char *keystr,
3465 struct tdb_validation_status *state)
3467 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3473 (void)centry_string( centry, mem_ctx );
3475 centry_free(centry);
3477 if (!(state->success)) {
3480 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3484 static int validate_trustdoms(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3485 struct tdb_validation_status *state)
3487 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3488 int32 num_domains, i;
3494 num_domains = centry_uint32(centry);
3496 for (i=0; i< num_domains; i++) {
3498 (void)centry_string(centry, mem_ctx);
3499 (void)centry_string(centry, mem_ctx);
3500 (void)centry_sid(centry, &sid);
3503 centry_free(centry);
3505 if (!(state->success)) {
3508 DEBUG(10,("validate_trustdoms: %s ok\n", keystr));
3512 static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
3514 struct tdb_validation_status *state)
3516 if (dbuf.dsize == 0) {
3517 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3518 "key %s (len ==0) ?\n", keystr));
3519 state->bad_entry = true;
3520 state->success = false;
3524 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
3525 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3529 static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3530 struct tdb_validation_status *state)
3532 if (dbuf.dsize != 4) {
3533 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3534 keystr, (unsigned int)dbuf.dsize ));
3535 state->bad_entry = true;
3536 state->success = false;
3539 DEBUG(10,("validate_offline: %s ok\n", keystr));
3543 static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3544 struct tdb_validation_status *state)
3546 if (dbuf.dsize != 4) {
3547 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3548 "key %s (len %u != 4) ?\n",
3549 keystr, (unsigned int)dbuf.dsize));
3550 state->bad_entry = true;
3551 state->success = false;
3555 DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
3559 /***********************************************************************
3560 A list of all possible cache tdb keys with associated validation
3562 ***********************************************************************/
3564 struct key_val_struct {
3565 const char *keyname;
3566 int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
3568 {"SEQNUM/", validate_seqnum},
3569 {"NS/", validate_ns},
3570 {"SN/", validate_sn},
3572 {"LOC_POL/", validate_loc_pol},
3573 {"PWD_POL/", validate_pwd_pol},
3574 {"CRED/", validate_cred},
3575 {"UL/", validate_ul},
3576 {"GL/", validate_gl},
3577 {"UG/", validate_ug},
3578 {"UA", validate_ua},
3579 {"GM/", validate_gm},
3580 {"DR/", validate_dr},
3581 {"DE/", validate_de},
3582 {"NSS/PWINFO/", validate_pwinfo},
3583 {"TRUSTDOMS/", validate_trustdoms},
3584 {"TRUSTDOMCACHE/", validate_trustdomcache},
3585 {"NSS/NA/", validate_nss_na},
3586 {"NSS/AN/", validate_nss_an},
3587 {"WINBINDD_OFFLINE", validate_offline},
3588 {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
3592 /***********************************************************************
3593 Function to look at every entry in the tdb and validate it as far as
3595 ***********************************************************************/
3597 static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
3600 unsigned int max_key_len = 1024;
3601 struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
3603 /* Paranoia check. */
3604 if (strncmp("UA/", (const char *)kbuf.dptr, 3) == 0) {
3605 max_key_len = 1024 * 1024;
3607 if (kbuf.dsize > max_key_len) {
3608 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
3610 (unsigned int)kbuf.dsize, (unsigned int)max_key_len));
3614 for (i = 0; key_val[i].keyname; i++) {
3615 size_t namelen = strlen(key_val[i].keyname);
3616 if (kbuf.dsize >= namelen && (
3617 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
3618 TALLOC_CTX *mem_ctx;
3622 keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
3626 memcpy(keystr, kbuf.dptr, kbuf.dsize);
3627 keystr[kbuf.dsize] = '\0';
3629 mem_ctx = talloc_init("validate_ctx");
3635 ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
3639 talloc_destroy(mem_ctx);
3644 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
3645 dump_data(0, (uint8 *)kbuf.dptr, kbuf.dsize);
3646 DEBUG(0,("data :\n"));
3647 dump_data(0, (uint8 *)dbuf.dptr, dbuf.dsize);
3648 v_state->unknown_key = true;
3649 v_state->success = false;
3650 return 1; /* terminate. */
3653 static void validate_panic(const char *const why)
3655 DEBUG(0,("validating cache: would panic %s\n", why ));
3656 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
3660 /***********************************************************************
3661 Try and validate every entry in the winbindd cache. If we fail here,
3662 delete the cache tdb and return non-zero.
3663 ***********************************************************************/
3665 int winbindd_validate_cache(void)
3668 const char *tdb_path = cache_path("winbindd_cache.tdb");
3669 TDB_CONTEXT *tdb = NULL;
3671 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3672 smb_panic_fn = validate_panic;
3675 tdb = tdb_open_log(tdb_path,
3676 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3677 ( lp_winbind_offline_logon()
3679 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
3683 DEBUG(0, ("winbindd_validate_cache: "
3684 "error opening/initializing tdb\n"));
3689 ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
3692 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
3693 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
3698 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
3699 smb_panic_fn = smb_panic;
3703 /***********************************************************************
3704 Try and validate every entry in the winbindd cache.
3705 ***********************************************************************/
3707 int winbindd_validate_cache_nobackup(void)
3710 const char *tdb_path = cache_path("winbindd_cache.tdb");
3712 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3713 smb_panic_fn = validate_panic;
3716 if (wcache == NULL || wcache->tdb == NULL) {
3717 ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
3719 ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
3723 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
3727 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
3729 smb_panic_fn = smb_panic;
3733 bool winbindd_cache_validate_and_initialize(void)
3735 close_winbindd_cache();
3737 if (lp_winbind_offline_logon()) {
3738 if (winbindd_validate_cache() < 0) {
3739 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
3740 "could be restored.\n"));
3744 return initialize_winbindd_cache();
3747 /*********************************************************************
3748 ********************************************************************/
3750 static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
3751 struct winbindd_tdc_domain **domains,
3752 size_t *num_domains )
3754 struct winbindd_tdc_domain *list = NULL;
3757 bool set_only = false;
3759 /* don't allow duplicates */
3764 for ( i=0; i< (*num_domains); i++ ) {
3765 if ( strequal( new_dom->name, list[i].domain_name ) ) {
3766 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
3777 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, 1 );
3780 list = TALLOC_REALLOC_ARRAY( *domains, *domains,
3781 struct winbindd_tdc_domain,
3786 ZERO_STRUCT( list[idx] );
3792 list[idx].domain_name = talloc_strdup( list, new_dom->name );
3793 list[idx].dns_name = talloc_strdup( list, new_dom->alt_name );
3795 if ( !is_null_sid( &new_dom->sid ) ) {
3796 sid_copy( &list[idx].sid, &new_dom->sid );
3798 sid_copy(&list[idx].sid, &global_sid_NULL);
3801 if ( new_dom->domain_flags != 0x0 )
3802 list[idx].trust_flags = new_dom->domain_flags;
3804 if ( new_dom->domain_type != 0x0 )
3805 list[idx].trust_type = new_dom->domain_type;
3807 if ( new_dom->domain_trust_attribs != 0x0 )
3808 list[idx].trust_attribs = new_dom->domain_trust_attribs;
3812 *num_domains = idx + 1;
3818 /*********************************************************************
3819 ********************************************************************/
3821 static TDB_DATA make_tdc_key( const char *domain_name )
3823 char *keystr = NULL;
3824 TDB_DATA key = { NULL, 0 };
3826 if ( !domain_name ) {
3827 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
3831 if (asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name ) == -1) {
3834 key = string_term_tdb_data(keystr);
3839 /*********************************************************************
3840 ********************************************************************/
3842 static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
3844 unsigned char **buf )
3846 unsigned char *buffer = NULL;
3851 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
3859 /* Store the number of array items first */
3860 len += tdb_pack( buffer+len, buflen-len, "d",
3863 /* now pack each domain trust record */
3864 for ( i=0; i<num_domains; i++ ) {
3869 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
3870 domains[i].domain_name,
3871 domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
3874 len += tdb_pack( buffer+len, buflen-len, "fffddd",
3875 domains[i].domain_name,
3876 domains[i].dns_name,
3877 sid_to_fstring(tmp, &domains[i].sid),
3878 domains[i].trust_flags,
3879 domains[i].trust_attribs,
3880 domains[i].trust_type );
3883 if ( buflen < len ) {
3885 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
3886 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
3900 /*********************************************************************
3901 ********************************************************************/
3903 static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
3904 struct winbindd_tdc_domain **domains )
3906 fstring domain_name, dns_name, sid_string;
3907 uint32 type, attribs, flags;
3911 struct winbindd_tdc_domain *list = NULL;
3913 /* get the number of domains */
3914 len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
3916 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3920 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, num_domains );
3922 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
3926 for ( i=0; i<num_domains; i++ ) {
3927 len += tdb_unpack( buf+len, buflen-len, "fffddd",
3936 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3937 TALLOC_FREE( list );
3941 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
3942 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
3943 domain_name, dns_name, sid_string,
3944 flags, attribs, type));
3946 list[i].domain_name = talloc_strdup( list, domain_name );
3947 list[i].dns_name = talloc_strdup( list, dns_name );
3948 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
3949 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
3952 list[i].trust_flags = flags;
3953 list[i].trust_attribs = attribs;
3954 list[i].trust_type = type;
3962 /*********************************************************************
3963 ********************************************************************/
3965 static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
3967 TDB_DATA key = make_tdc_key( lp_workgroup() );
3968 TDB_DATA data = { NULL, 0 };
3974 /* See if we were asked to delete the cache entry */
3977 ret = tdb_delete( wcache->tdb, key );
3981 data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
3988 ret = tdb_store( wcache->tdb, key, data, 0 );
3991 SAFE_FREE( data.dptr );
3992 SAFE_FREE( key.dptr );
3994 return ( ret != -1 );
3997 /*********************************************************************
3998 ********************************************************************/
4000 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
4002 TDB_DATA key = make_tdc_key( lp_workgroup() );
4003 TDB_DATA data = { NULL, 0 };
4011 data = tdb_fetch( wcache->tdb, key );
4013 SAFE_FREE( key.dptr );
4018 *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
4020 SAFE_FREE( data.dptr );
4028 /*********************************************************************
4029 ********************************************************************/
4031 bool wcache_tdc_add_domain( struct winbindd_domain *domain )
4033 struct winbindd_tdc_domain *dom_list = NULL;
4034 size_t num_domains = 0;
4037 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4038 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4039 domain->name, domain->alt_name,
4040 sid_string_dbg(&domain->sid),
4041 domain->domain_flags,
4042 domain->domain_trust_attribs,
4043 domain->domain_type));
4045 if ( !init_wcache() ) {
4049 /* fetch the list */
4051 wcache_tdc_fetch_list( &dom_list, &num_domains );
4053 /* add the new domain */
4055 if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
4059 /* pack the domain */
4061 if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
4069 TALLOC_FREE( dom_list );
4074 /*********************************************************************
4075 ********************************************************************/
4077 struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
4079 struct winbindd_tdc_domain *dom_list = NULL;
4080 size_t num_domains = 0;
4082 struct winbindd_tdc_domain *d = NULL;
4084 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
4086 if ( !init_wcache() ) {
4090 /* fetch the list */
4092 wcache_tdc_fetch_list( &dom_list, &num_domains );
4094 for ( i=0; i<num_domains; i++ ) {
4095 if ( strequal(name, dom_list[i].domain_name) ||
4096 strequal(name, dom_list[i].dns_name) )
4098 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4101 d = TALLOC_P( ctx, struct winbindd_tdc_domain );
4105 d->domain_name = talloc_strdup( d, dom_list[i].domain_name );
4106 d->dns_name = talloc_strdup( d, dom_list[i].dns_name );
4107 sid_copy( &d->sid, &dom_list[i].sid );
4108 d->trust_flags = dom_list[i].trust_flags;
4109 d->trust_type = dom_list[i].trust_type;
4110 d->trust_attribs = dom_list[i].trust_attribs;
4116 TALLOC_FREE( dom_list );
4122 /*********************************************************************
4123 ********************************************************************/
4125 void wcache_tdc_clear( void )
4127 if ( !init_wcache() )
4130 wcache_tdc_store_list( NULL, 0 );
4136 /*********************************************************************
4137 ********************************************************************/
4139 static void wcache_save_user_pwinfo(struct winbindd_domain *domain,
4141 const DOM_SID *user_sid,
4142 const char *homedir,
4147 struct cache_entry *centry;
4150 if ( (centry = centry_start(domain, status)) == NULL )
4153 centry_put_string( centry, homedir );
4154 centry_put_string( centry, shell );
4155 centry_put_string( centry, gecos );
4156 centry_put_uint32( centry, gid );
4158 centry_end(centry, "NSS/PWINFO/%s", sid_to_fstring(tmp, user_sid) );
4160 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid) ));
4162 centry_free(centry);
4165 NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
4166 const DOM_SID *user_sid,
4168 ADS_STRUCT *ads, LDAPMessage *msg,
4169 const char **homedir, const char **shell,
4170 const char **gecos, gid_t *p_gid)
4172 struct winbind_cache *cache = get_cache(domain);
4173 struct cache_entry *centry = NULL;
4180 centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s",
4181 sid_to_fstring(tmp, user_sid));
4186 *homedir = centry_string( centry, ctx );
4187 *shell = centry_string( centry, ctx );
4188 *gecos = centry_string( centry, ctx );
4189 *p_gid = centry_uint32( centry );
4191 centry_free(centry);
4193 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4194 sid_string_dbg(user_sid)));
4196 return NT_STATUS_OK;
4200 nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg,
4201 homedir, shell, gecos, p_gid );
4203 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status)));
4205 if ( NT_STATUS_IS_OK(nt_status) ) {
4206 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir));
4207 DEBUGADD(10, ("\tshell = '%s'\n", *shell));
4208 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos));
4209 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid));
4211 wcache_save_user_pwinfo( domain, nt_status, user_sid,
4212 *homedir, *shell, *gecos, *p_gid );
4215 if ( NT_STATUS_EQUAL( nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
4216 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4218 set_domain_offline( domain );
4225 /* the cache backend methods are exposed via this structure */
4226 struct winbindd_methods cache_methods = {