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 /* convert a single name to a sid in a domain */
1609 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
1610 TALLOC_CTX *mem_ctx,
1611 const char *domain_name,
1615 enum lsa_SidType *type)
1617 struct winbind_cache *cache = get_cache(domain);
1618 struct cache_entry *centry = NULL;
1625 fstrcpy(uname, name);
1627 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1631 status = centry->status;
1632 if (NT_STATUS_IS_OK(status)) {
1633 *type = (enum lsa_SidType)centry_uint32(centry);
1634 centry_sid(centry, sid);
1637 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: %s\n",
1638 domain->name, nt_errstr(status) ));
1640 centry_free(centry);
1646 /* If the seq number check indicated that there is a problem
1647 * with this DC, then return that status... except for
1648 * access_denied. This is special because the dc may be in
1649 * "restrict anonymous = 1" mode, in which case it will deny
1650 * most unauthenticated operations, but *will* allow the LSA
1651 * name-to-sid that we try as a fallback. */
1653 if (!(NT_STATUS_IS_OK(domain->last_status)
1654 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1655 return domain->last_status;
1657 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1660 status = domain->backend->name_to_sid(domain, mem_ctx, domain_name,
1661 name, flags, sid, type);
1664 refresh_sequence_number(domain, false);
1666 if (domain->online &&
1667 (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
1668 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1670 /* Only save the reverse mapping if this was not a UPN */
1671 if (!strchr(name, '@')) {
1672 strupper_m(CONST_DISCARD(char *,domain_name));
1673 strlower_m(CONST_DISCARD(char *,name));
1674 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1681 NTSTATUS wcache_sid_to_name(struct winbindd_domain *domain,
1682 const struct dom_sid *sid,
1683 TALLOC_CTX *mem_ctx,
1686 enum lsa_SidType *type)
1688 struct winbind_cache *cache = get_cache(domain);
1689 struct cache_entry *centry;
1693 if (cache->tdb == NULL) {
1694 return NT_STATUS_NOT_FOUND;
1697 sid_string = sid_string_tos(sid);
1698 if (sid_string == NULL) {
1699 return NT_STATUS_NO_MEMORY;
1702 centry = wcache_fetch(cache, domain, "SN/%s", sid_string);
1703 TALLOC_FREE(sid_string);
1704 if (centry == NULL) {
1705 return NT_STATUS_NOT_FOUND;
1708 if (NT_STATUS_IS_OK(centry->status)) {
1709 *type = (enum lsa_SidType)centry_uint32(centry);
1710 *domain_name = centry_string(centry, mem_ctx);
1711 *name = centry_string(centry, mem_ctx);
1714 status = centry->status;
1715 centry_free(centry);
1717 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1718 "%s\n", domain->name, nt_errstr(status) ));
1723 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1725 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
1726 TALLOC_CTX *mem_ctx,
1730 enum lsa_SidType *type)
1734 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
1736 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1741 *domain_name = NULL;
1743 /* If the seq number check indicated that there is a problem
1744 * with this DC, then return that status... except for
1745 * access_denied. This is special because the dc may be in
1746 * "restrict anonymous = 1" mode, in which case it will deny
1747 * most unauthenticated operations, but *will* allow the LSA
1748 * sid-to-name that we try as a fallback. */
1750 if (!(NT_STATUS_IS_OK(domain->last_status)
1751 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1752 return domain->last_status;
1754 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1757 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1760 refresh_sequence_number(domain, false);
1761 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1763 /* We can't save the name to sid mapping here, as with sid history a
1764 * later name2sid would give the wrong sid. */
1769 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
1770 TALLOC_CTX *mem_ctx,
1771 const DOM_SID *domain_sid,
1776 enum lsa_SidType **types)
1778 struct winbind_cache *cache = get_cache(domain);
1780 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1784 *domain_name = NULL;
1792 if (num_rids == 0) {
1793 return NT_STATUS_OK;
1796 *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
1797 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
1799 if ((*names == NULL) || (*types == NULL)) {
1800 result = NT_STATUS_NO_MEMORY;
1804 have_mapped = have_unmapped = false;
1806 for (i=0; i<num_rids; i++) {
1808 struct cache_entry *centry;
1811 if (!sid_compose(&sid, domain_sid, rids[i])) {
1812 result = NT_STATUS_INTERNAL_ERROR;
1816 centry = wcache_fetch(cache, domain, "SN/%s",
1817 sid_to_fstring(tmp, &sid));
1822 (*types)[i] = SID_NAME_UNKNOWN;
1823 (*names)[i] = talloc_strdup(*names, "");
1825 if (NT_STATUS_IS_OK(centry->status)) {
1828 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
1830 dom = centry_string(centry, mem_ctx);
1831 if (*domain_name == NULL) {
1837 (*names)[i] = centry_string(centry, *names);
1839 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
1840 have_unmapped = true;
1843 /* something's definitely wrong */
1844 result = centry->status;
1848 centry_free(centry);
1852 return NT_STATUS_NONE_MAPPED;
1854 if (!have_unmapped) {
1855 return NT_STATUS_OK;
1857 return STATUS_SOME_UNMAPPED;
1861 TALLOC_FREE(*names);
1862 TALLOC_FREE(*types);
1864 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
1865 rids, num_rids, domain_name,
1869 None of the queried rids has been found so save all negative entries
1871 if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
1872 for (i = 0; i < num_rids; i++) {
1874 const char *name = "";
1875 const enum lsa_SidType type = SID_NAME_UNKNOWN;
1876 NTSTATUS status = NT_STATUS_NONE_MAPPED;
1878 if (!sid_compose(&sid, domain_sid, rids[i])) {
1879 return NT_STATUS_INTERNAL_ERROR;
1882 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
1890 Some or all of the queried rids have been found.
1892 if (!NT_STATUS_IS_OK(result) &&
1893 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
1897 refresh_sequence_number(domain, false);
1899 for (i=0; i<num_rids; i++) {
1903 if (!sid_compose(&sid, domain_sid, rids[i])) {
1904 result = NT_STATUS_INTERNAL_ERROR;
1908 status = (*types)[i] == SID_NAME_UNKNOWN ?
1909 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
1911 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
1912 (*names)[i], (*types)[i]);
1918 TALLOC_FREE(*names);
1919 TALLOC_FREE(*types);
1923 /* Lookup user information from a rid */
1924 static NTSTATUS query_user(struct winbindd_domain *domain,
1925 TALLOC_CTX *mem_ctx,
1926 const DOM_SID *user_sid,
1927 WINBIND_USERINFO *info)
1929 struct winbind_cache *cache = get_cache(domain);
1930 struct cache_entry *centry = NULL;
1937 centry = wcache_fetch(cache, domain, "U/%s",
1938 sid_to_fstring(tmp, user_sid));
1940 /* If we have an access denied cache entry and a cached info3 in the
1941 samlogon cache then do a query. This will force the rpc back end
1942 to return the info3 data. */
1944 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1945 netsamlogon_cache_have(user_sid)) {
1946 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1947 domain->last_status = NT_STATUS_OK;
1948 centry_free(centry);
1955 /* if status is not ok then this is a negative hit
1956 and the rest of the data doesn't matter */
1957 status = centry->status;
1958 if (NT_STATUS_IS_OK(status)) {
1959 info->acct_name = centry_string(centry, mem_ctx);
1960 info->full_name = centry_string(centry, mem_ctx);
1961 info->homedir = centry_string(centry, mem_ctx);
1962 info->shell = centry_string(centry, mem_ctx);
1963 info->primary_gid = centry_uint32(centry);
1964 centry_sid(centry, &info->user_sid);
1965 centry_sid(centry, &info->group_sid);
1968 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: %s\n",
1969 domain->name, nt_errstr(status) ));
1971 centry_free(centry);
1977 /* Return status value returned by seq number check */
1979 if (!NT_STATUS_IS_OK(domain->last_status))
1980 return domain->last_status;
1982 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
1985 status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
1988 refresh_sequence_number(domain, false);
1989 wcache_save_user(domain, status, info);
1995 /* Lookup groups a user is a member of. */
1996 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
1997 TALLOC_CTX *mem_ctx,
1998 const DOM_SID *user_sid,
1999 uint32 *num_groups, DOM_SID **user_gids)
2001 struct winbind_cache *cache = get_cache(domain);
2002 struct cache_entry *centry = NULL;
2010 centry = wcache_fetch(cache, domain, "UG/%s",
2011 sid_to_fstring(sid_string, user_sid));
2013 /* If we have an access denied cache entry and a cached info3 in the
2014 samlogon cache then do a query. This will force the rpc back end
2015 to return the info3 data. */
2017 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
2018 netsamlogon_cache_have(user_sid)) {
2019 DEBUG(10, ("lookup_usergroups: cached access denied and have cached info3\n"));
2020 domain->last_status = NT_STATUS_OK;
2021 centry_free(centry);
2028 *num_groups = centry_uint32(centry);
2030 if (*num_groups == 0)
2033 (*user_gids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
2034 if (! (*user_gids)) {
2035 smb_panic_fn("lookup_usergroups out of memory");
2037 for (i=0; i<(*num_groups); i++) {
2038 centry_sid(centry, &(*user_gids)[i]);
2042 status = centry->status;
2044 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status: %s\n",
2045 domain->name, nt_errstr(status) ));
2047 centry_free(centry);
2052 (*user_gids) = NULL;
2054 /* Return status value returned by seq number check */
2056 if (!NT_STATUS_IS_OK(domain->last_status))
2057 return domain->last_status;
2059 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2062 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
2064 if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
2068 refresh_sequence_number(domain, false);
2069 centry = centry_start(domain, status);
2073 centry_put_uint32(centry, *num_groups);
2074 for (i=0; i<(*num_groups); i++) {
2075 centry_put_sid(centry, &(*user_gids)[i]);
2078 centry_end(centry, "UG/%s", sid_to_fstring(sid_string, user_sid));
2079 centry_free(centry);
2085 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
2086 TALLOC_CTX *mem_ctx,
2087 uint32 num_sids, const DOM_SID *sids,
2088 uint32 *num_aliases, uint32 **alias_rids)
2090 struct winbind_cache *cache = get_cache(domain);
2091 struct cache_entry *centry = NULL;
2093 char *sidlist = talloc_strdup(mem_ctx, "");
2099 if (num_sids == 0) {
2102 return NT_STATUS_OK;
2105 /* We need to cache indexed by the whole list of SIDs, the aliases
2106 * resulting might come from any of the SIDs. */
2108 for (i=0; i<num_sids; i++) {
2110 sidlist = talloc_asprintf(mem_ctx, "%s/%s", sidlist,
2111 sid_to_fstring(tmp, &sids[i]));
2112 if (sidlist == NULL)
2113 return NT_STATUS_NO_MEMORY;
2116 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
2121 *num_aliases = centry_uint32(centry);
2125 (*alias_rids) = TALLOC_ARRAY(mem_ctx, uint32, *num_aliases);
2127 if ((*alias_rids) == NULL) {
2128 centry_free(centry);
2129 return NT_STATUS_NO_MEMORY;
2132 (*alias_rids) = NULL;
2135 for (i=0; i<(*num_aliases); i++)
2136 (*alias_rids)[i] = centry_uint32(centry);
2138 status = centry->status;
2140 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2141 "status %s\n", domain->name, nt_errstr(status)));
2143 centry_free(centry);
2148 (*alias_rids) = NULL;
2150 if (!NT_STATUS_IS_OK(domain->last_status))
2151 return domain->last_status;
2153 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2154 "for domain %s\n", domain->name ));
2156 status = domain->backend->lookup_useraliases(domain, mem_ctx,
2158 num_aliases, alias_rids);
2161 refresh_sequence_number(domain, false);
2162 centry = centry_start(domain, status);
2165 centry_put_uint32(centry, *num_aliases);
2166 for (i=0; i<(*num_aliases); i++)
2167 centry_put_uint32(centry, (*alias_rids)[i]);
2168 centry_end(centry, "UA%s", sidlist);
2169 centry_free(centry);
2176 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
2177 TALLOC_CTX *mem_ctx,
2178 const DOM_SID *group_sid, uint32 *num_names,
2179 DOM_SID **sid_mem, char ***names,
2180 uint32 **name_types)
2182 struct winbind_cache *cache = get_cache(domain);
2183 struct cache_entry *centry = NULL;
2191 centry = wcache_fetch(cache, domain, "GM/%s",
2192 sid_to_fstring(sid_string, group_sid));
2196 *num_names = centry_uint32(centry);
2198 if (*num_names == 0)
2201 (*sid_mem) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_names);
2202 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_names);
2203 (*name_types) = TALLOC_ARRAY(mem_ctx, uint32, *num_names);
2205 if (! (*sid_mem) || ! (*names) || ! (*name_types)) {
2206 smb_panic_fn("lookup_groupmem out of memory");
2209 for (i=0; i<(*num_names); i++) {
2210 centry_sid(centry, &(*sid_mem)[i]);
2211 (*names)[i] = centry_string(centry, mem_ctx);
2212 (*name_types)[i] = centry_uint32(centry);
2216 status = centry->status;
2218 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status: %s\n",
2219 domain->name, nt_errstr(status)));
2221 centry_free(centry);
2228 (*name_types) = NULL;
2230 /* Return status value returned by seq number check */
2232 if (!NT_STATUS_IS_OK(domain->last_status))
2233 return domain->last_status;
2235 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2238 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid, num_names,
2239 sid_mem, names, name_types);
2242 refresh_sequence_number(domain, false);
2243 centry = centry_start(domain, status);
2246 centry_put_uint32(centry, *num_names);
2247 for (i=0; i<(*num_names); i++) {
2248 centry_put_sid(centry, &(*sid_mem)[i]);
2249 centry_put_string(centry, (*names)[i]);
2250 centry_put_uint32(centry, (*name_types)[i]);
2252 centry_end(centry, "GM/%s", sid_to_fstring(sid_string, group_sid));
2253 centry_free(centry);
2259 /* find the sequence number for a domain */
2260 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
2262 refresh_sequence_number(domain, false);
2264 *seq = domain->sequence_number;
2266 return NT_STATUS_OK;
2269 /* enumerate trusted domains
2270 * (we need to have the list of trustdoms in the cache when we go offline) -
2272 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
2273 TALLOC_CTX *mem_ctx,
2274 uint32 *num_domains,
2279 struct winbind_cache *cache = get_cache(domain);
2280 struct cache_entry *centry = NULL;
2287 centry = wcache_fetch(cache, domain, "TRUSTDOMS/%s", domain->name);
2293 *num_domains = centry_uint32(centry);
2296 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
2297 (*alt_names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
2298 (*dom_sids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
2300 if (! (*dom_sids) || ! (*names) || ! (*alt_names)) {
2301 smb_panic_fn("trusted_domains out of memory");
2305 (*alt_names) = NULL;
2309 for (i=0; i<(*num_domains); i++) {
2310 (*names)[i] = centry_string(centry, mem_ctx);
2311 (*alt_names)[i] = centry_string(centry, mem_ctx);
2312 if (!centry_sid(centry, &(*dom_sids)[i])) {
2313 sid_copy(&(*dom_sids)[i], &global_sid_NULL);
2317 status = centry->status;
2319 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
2320 domain->name, *num_domains, nt_errstr(status) ));
2322 centry_free(centry);
2329 (*alt_names) = NULL;
2331 /* Return status value returned by seq number check */
2333 if (!NT_STATUS_IS_OK(domain->last_status))
2334 return domain->last_status;
2336 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2339 status = domain->backend->trusted_domains(domain, mem_ctx, num_domains,
2340 names, alt_names, dom_sids);
2342 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2343 * so that the generic centry handling still applies correctly -
2346 if (!NT_STATUS_IS_ERR(status)) {
2347 status = NT_STATUS_OK;
2351 #if 0 /* Disabled as we want the trust dom list to be managed by
2352 the main parent and always to make the query. --jerry */
2355 refresh_sequence_number(domain, false);
2357 centry = centry_start(domain, status);
2361 centry_put_uint32(centry, *num_domains);
2363 for (i=0; i<(*num_domains); i++) {
2364 centry_put_string(centry, (*names)[i]);
2365 centry_put_string(centry, (*alt_names)[i]);
2366 centry_put_sid(centry, &(*dom_sids)[i]);
2369 centry_end(centry, "TRUSTDOMS/%s", domain->name);
2371 centry_free(centry);
2379 /* get lockout policy */
2380 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
2381 TALLOC_CTX *mem_ctx,
2382 struct samr_DomInfo12 *policy)
2384 struct winbind_cache *cache = get_cache(domain);
2385 struct cache_entry *centry = NULL;
2391 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2396 policy->lockout_duration = centry_nttime(centry);
2397 policy->lockout_window = centry_nttime(centry);
2398 policy->lockout_threshold = centry_uint16(centry);
2400 status = centry->status;
2402 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2403 domain->name, nt_errstr(status) ));
2405 centry_free(centry);
2409 ZERO_STRUCTP(policy);
2411 /* Return status value returned by seq number check */
2413 if (!NT_STATUS_IS_OK(domain->last_status))
2414 return domain->last_status;
2416 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2419 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2422 refresh_sequence_number(domain, false);
2423 wcache_save_lockout_policy(domain, status, policy);
2428 /* get password policy */
2429 static NTSTATUS password_policy(struct winbindd_domain *domain,
2430 TALLOC_CTX *mem_ctx,
2431 struct samr_DomInfo1 *policy)
2433 struct winbind_cache *cache = get_cache(domain);
2434 struct cache_entry *centry = NULL;
2440 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2445 policy->min_password_length = centry_uint16(centry);
2446 policy->password_history_length = centry_uint16(centry);
2447 policy->password_properties = centry_uint32(centry);
2448 policy->max_password_age = centry_nttime(centry);
2449 policy->min_password_age = centry_nttime(centry);
2451 status = centry->status;
2453 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2454 domain->name, nt_errstr(status) ));
2456 centry_free(centry);
2460 ZERO_STRUCTP(policy);
2462 /* Return status value returned by seq number check */
2464 if (!NT_STATUS_IS_OK(domain->last_status))
2465 return domain->last_status;
2467 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2470 status = domain->backend->password_policy(domain, mem_ctx, policy);
2473 refresh_sequence_number(domain, false);
2474 if (NT_STATUS_IS_OK(status)) {
2475 wcache_save_password_policy(domain, status, policy);
2482 /* Invalidate cached user and group lists coherently */
2484 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2487 if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
2488 strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
2489 tdb_delete(the_tdb, kbuf);
2494 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2496 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
2497 struct netr_SamInfo3 *info3)
2500 fstring key_str, sid_string;
2501 struct winbind_cache *cache;
2503 /* dont clear cached U/SID and UG/SID entries when we want to logon
2506 if (lp_winbind_offline_logon()) {
2513 cache = get_cache(domain);
2519 sid_copy(&sid, info3->base.domain_sid);
2520 sid_append_rid(&sid, info3->base.rid);
2522 /* Clear U/SID cache entry */
2523 fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, &sid));
2524 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
2525 tdb_delete(cache->tdb, string_tdb_data(key_str));
2527 /* Clear UG/SID cache entry */
2528 fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, &sid));
2529 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
2530 tdb_delete(cache->tdb, string_tdb_data(key_str));
2532 /* Samba/winbindd never needs this. */
2533 netsamlogon_clear_cached_user(info3);
2536 bool wcache_invalidate_cache(void)
2538 struct winbindd_domain *domain;
2540 for (domain = domain_list(); domain; domain = domain->next) {
2541 struct winbind_cache *cache = get_cache(domain);
2543 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2544 "entries for %s\n", domain->name));
2547 tdb_traverse(cache->tdb, traverse_fn, NULL);
2556 bool init_wcache(void)
2558 if (wcache == NULL) {
2559 wcache = SMB_XMALLOC_P(struct winbind_cache);
2560 ZERO_STRUCTP(wcache);
2563 if (wcache->tdb != NULL)
2566 /* when working offline we must not clear the cache on restart */
2567 wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
2568 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2569 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
2570 O_RDWR|O_CREAT, 0600);
2572 if (wcache->tdb == NULL) {
2573 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2580 /************************************************************************
2581 This is called by the parent to initialize the cache file.
2582 We don't need sophisticated locking here as we know we're the
2584 ************************************************************************/
2586 bool initialize_winbindd_cache(void)
2588 bool cache_bad = true;
2591 if (!init_wcache()) {
2592 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
2596 /* Check version number. */
2597 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
2598 vers == WINBINDD_CACHE_VERSION) {
2603 DEBUG(0,("initialize_winbindd_cache: clearing cache "
2604 "and re-creating with version number %d\n",
2605 WINBINDD_CACHE_VERSION ));
2607 tdb_close(wcache->tdb);
2610 if (unlink(cache_path("winbindd_cache.tdb")) == -1) {
2611 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
2612 cache_path("winbindd_cache.tdb"),
2616 if (!init_wcache()) {
2617 DEBUG(0,("initialize_winbindd_cache: re-initialization "
2618 "init_wcache failed.\n"));
2622 /* Write the version. */
2623 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
2624 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
2625 tdb_errorstr(wcache->tdb) ));
2630 tdb_close(wcache->tdb);
2635 void close_winbindd_cache(void)
2641 tdb_close(wcache->tdb);
2646 bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
2647 char **domain_name, char **name,
2648 enum lsa_SidType *type)
2650 struct winbindd_domain *domain;
2653 domain = find_lookup_domain_from_sid(sid);
2654 if (domain == NULL) {
2657 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
2659 return NT_STATUS_IS_OK(status);
2662 bool lookup_cached_name(TALLOC_CTX *mem_ctx,
2663 const char *domain_name,
2666 enum lsa_SidType *type)
2668 struct winbindd_domain *domain;
2669 struct winbind_cache *cache;
2670 struct cache_entry *centry = NULL;
2673 bool original_online_state;
2675 domain = find_lookup_domain_from_name(domain_name);
2676 if (domain == NULL) {
2680 cache = get_cache(domain);
2682 if (cache->tdb == NULL) {
2686 fstrcpy(uname, name);
2689 /* If we are doing a cached logon, temporarily set the domain
2690 offline so the cache won't expire the entry */
2692 original_online_state = domain->online;
2693 domain->online = false;
2694 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
2695 domain->online = original_online_state;
2697 if (centry == NULL) {
2701 if (NT_STATUS_IS_OK(centry->status)) {
2702 *type = (enum lsa_SidType)centry_uint32(centry);
2703 centry_sid(centry, sid);
2706 status = centry->status;
2707 centry_free(centry);
2709 return NT_STATUS_IS_OK(status);
2712 void cache_name2sid(struct winbindd_domain *domain,
2713 const char *domain_name, const char *name,
2714 enum lsa_SidType type, const DOM_SID *sid)
2716 refresh_sequence_number(domain, false);
2717 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
2722 * The original idea that this cache only contains centries has
2723 * been blurred - now other stuff gets put in here. Ensure we
2724 * ignore these things on cleanup.
2727 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
2728 TDB_DATA dbuf, void *state)
2730 struct cache_entry *centry;
2732 if (is_non_centry_key(kbuf)) {
2736 centry = wcache_fetch_raw((char *)kbuf.dptr);
2741 if (!NT_STATUS_IS_OK(centry->status)) {
2742 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
2743 tdb_delete(the_tdb, kbuf);
2746 centry_free(centry);
2750 /* flush the cache */
2751 void wcache_flush_cache(void)
2756 tdb_close(wcache->tdb);
2759 if (!winbindd_use_cache()) {
2763 /* when working offline we must not clear the cache on restart */
2764 wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
2765 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2766 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
2767 O_RDWR|O_CREAT, 0600);
2770 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2774 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
2776 DEBUG(10,("wcache_flush_cache success\n"));
2779 /* Count cached creds */
2781 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2784 int *cred_count = (int*)state;
2786 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
2792 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
2794 struct winbind_cache *cache = get_cache(domain);
2799 return NT_STATUS_INTERNAL_DB_ERROR;
2802 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
2804 return NT_STATUS_OK;
2808 struct cred_list *prev, *next;
2813 static struct cred_list *wcache_cred_list;
2815 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2818 struct cred_list *cred;
2820 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
2822 cred = SMB_MALLOC_P(struct cred_list);
2824 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2830 /* save a copy of the key */
2832 fstrcpy(cred->name, (const char *)kbuf.dptr);
2833 DLIST_ADD(wcache_cred_list, cred);
2839 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const DOM_SID *sid)
2841 struct winbind_cache *cache = get_cache(domain);
2844 struct cred_list *cred, *oldest = NULL;
2847 return NT_STATUS_INTERNAL_DB_ERROR;
2850 /* we possibly already have an entry */
2851 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
2853 fstring key_str, tmp;
2855 DEBUG(11,("we already have an entry, deleting that\n"));
2857 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
2859 tdb_delete(cache->tdb, string_tdb_data(key_str));
2861 return NT_STATUS_OK;
2864 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
2866 return NT_STATUS_OK;
2867 } else if ((ret == -1) || (wcache_cred_list == NULL)) {
2868 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2871 ZERO_STRUCTP(oldest);
2873 for (cred = wcache_cred_list; cred; cred = cred->next) {
2878 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
2880 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
2882 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
2886 t = IVAL(data.dptr, 0);
2887 SAFE_FREE(data.dptr);
2890 oldest = SMB_MALLOC_P(struct cred_list);
2891 if (oldest == NULL) {
2892 status = NT_STATUS_NO_MEMORY;
2896 fstrcpy(oldest->name, cred->name);
2897 oldest->created = t;
2901 if (t < oldest->created) {
2902 fstrcpy(oldest->name, cred->name);
2903 oldest->created = t;
2907 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
2908 status = NT_STATUS_OK;
2910 status = NT_STATUS_UNSUCCESSFUL;
2913 SAFE_FREE(wcache_cred_list);
2919 /* Change the global online/offline state. */
2920 bool set_global_winbindd_state_offline(void)
2924 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
2926 /* Only go offline if someone has created
2927 the key "WINBINDD_OFFLINE" in the cache tdb. */
2929 if (wcache == NULL || wcache->tdb == NULL) {
2930 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
2934 if (!lp_winbind_offline_logon()) {
2935 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
2939 if (global_winbindd_offline_state) {
2940 /* Already offline. */
2944 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
2946 if (!data.dptr || data.dsize != 4) {
2947 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
2948 SAFE_FREE(data.dptr);
2951 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
2952 global_winbindd_offline_state = true;
2953 SAFE_FREE(data.dptr);
2958 void set_global_winbindd_state_online(void)
2960 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
2962 if (!lp_winbind_offline_logon()) {
2963 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
2967 if (!global_winbindd_offline_state) {
2968 /* Already online. */
2971 global_winbindd_offline_state = false;
2977 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
2978 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
2981 bool get_global_winbindd_state_offline(void)
2983 return global_winbindd_offline_state;
2986 /***********************************************************************
2987 Validate functions for all possible cache tdb keys.
2988 ***********************************************************************/
2990 static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
2991 struct tdb_validation_status *state)
2993 struct cache_entry *centry;
2995 centry = SMB_XMALLOC_P(struct cache_entry);
2996 centry->data = (unsigned char *)memdup(data.dptr, data.dsize);
2997 if (!centry->data) {
3001 centry->len = data.dsize;
3004 if (centry->len < 8) {
3005 /* huh? corrupt cache? */
3006 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr));
3007 centry_free(centry);
3008 state->bad_entry = true;
3009 state->success = false;
3013 centry->status = NT_STATUS(centry_uint32(centry));
3014 centry->sequence_number = centry_uint32(centry);
3018 static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3019 struct tdb_validation_status *state)
3021 if (dbuf.dsize != 8) {
3022 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3023 keystr, (unsigned int)dbuf.dsize ));
3024 state->bad_entry = true;
3030 static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3031 struct tdb_validation_status *state)
3033 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3038 (void)centry_uint32(centry);
3039 if (NT_STATUS_IS_OK(centry->status)) {
3041 (void)centry_sid(centry, &sid);
3044 centry_free(centry);
3046 if (!(state->success)) {
3049 DEBUG(10,("validate_ns: %s ok\n", keystr));
3053 static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3054 struct tdb_validation_status *state)
3056 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3061 if (NT_STATUS_IS_OK(centry->status)) {
3062 (void)centry_uint32(centry);
3063 (void)centry_string(centry, mem_ctx);
3064 (void)centry_string(centry, mem_ctx);
3067 centry_free(centry);
3069 if (!(state->success)) {
3072 DEBUG(10,("validate_sn: %s ok\n", keystr));
3076 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3077 struct tdb_validation_status *state)
3079 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3086 (void)centry_string(centry, mem_ctx);
3087 (void)centry_string(centry, mem_ctx);
3088 (void)centry_string(centry, mem_ctx);
3089 (void)centry_string(centry, mem_ctx);
3090 (void)centry_uint32(centry);
3091 (void)centry_sid(centry, &sid);
3092 (void)centry_sid(centry, &sid);
3094 centry_free(centry);
3096 if (!(state->success)) {
3099 DEBUG(10,("validate_u: %s ok\n", keystr));
3103 static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3104 struct tdb_validation_status *state)
3106 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3112 (void)centry_nttime(centry);
3113 (void)centry_nttime(centry);
3114 (void)centry_uint16(centry);
3116 centry_free(centry);
3118 if (!(state->success)) {
3121 DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
3125 static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3126 struct tdb_validation_status *state)
3128 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3134 (void)centry_uint16(centry);
3135 (void)centry_uint16(centry);
3136 (void)centry_uint32(centry);
3137 (void)centry_nttime(centry);
3138 (void)centry_nttime(centry);
3140 centry_free(centry);
3142 if (!(state->success)) {
3145 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
3149 static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3150 struct tdb_validation_status *state)
3152 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3158 (void)centry_time(centry);
3159 (void)centry_hash16(centry, mem_ctx);
3161 /* We only have 17 bytes more data in the salted cred case. */
3162 if (centry->len - centry->ofs == 17) {
3163 (void)centry_hash16(centry, mem_ctx);
3166 centry_free(centry);
3168 if (!(state->success)) {
3171 DEBUG(10,("validate_cred: %s ok\n", keystr));
3175 static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3176 struct tdb_validation_status *state)
3178 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3179 int32 num_entries, i;
3185 num_entries = (int32)centry_uint32(centry);
3187 for (i=0; i< num_entries; i++) {
3189 (void)centry_string(centry, mem_ctx);
3190 (void)centry_string(centry, mem_ctx);
3191 (void)centry_string(centry, mem_ctx);
3192 (void)centry_string(centry, mem_ctx);
3193 (void)centry_sid(centry, &sid);
3194 (void)centry_sid(centry, &sid);
3197 centry_free(centry);
3199 if (!(state->success)) {
3202 DEBUG(10,("validate_ul: %s ok\n", keystr));
3206 static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3207 struct tdb_validation_status *state)
3209 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3210 int32 num_entries, i;
3216 num_entries = centry_uint32(centry);
3218 for (i=0; i< num_entries; i++) {
3219 (void)centry_string(centry, mem_ctx);
3220 (void)centry_string(centry, mem_ctx);
3221 (void)centry_uint32(centry);
3224 centry_free(centry);
3226 if (!(state->success)) {
3229 DEBUG(10,("validate_gl: %s ok\n", keystr));
3233 static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3234 struct tdb_validation_status *state)
3236 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3237 int32 num_groups, i;
3243 num_groups = centry_uint32(centry);
3245 for (i=0; i< num_groups; i++) {
3247 centry_sid(centry, &sid);
3250 centry_free(centry);
3252 if (!(state->success)) {
3255 DEBUG(10,("validate_ug: %s ok\n", keystr));
3259 static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3260 struct tdb_validation_status *state)
3262 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3263 int32 num_aliases, i;
3269 num_aliases = centry_uint32(centry);
3271 for (i=0; i < num_aliases; i++) {
3272 (void)centry_uint32(centry);
3275 centry_free(centry);
3277 if (!(state->success)) {
3280 DEBUG(10,("validate_ua: %s ok\n", keystr));
3284 static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3285 struct tdb_validation_status *state)
3287 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3294 num_names = centry_uint32(centry);
3296 for (i=0; i< num_names; i++) {
3298 centry_sid(centry, &sid);
3299 (void)centry_string(centry, mem_ctx);
3300 (void)centry_uint32(centry);
3303 centry_free(centry);
3305 if (!(state->success)) {
3308 DEBUG(10,("validate_gm: %s ok\n", keystr));
3312 static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3313 struct tdb_validation_status *state)
3315 /* Can't say anything about this other than must be nonzero. */
3316 if (dbuf.dsize == 0) {
3317 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3319 state->bad_entry = true;
3320 state->success = false;
3324 DEBUG(10,("validate_dr: %s ok\n", keystr));
3328 static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3329 struct tdb_validation_status *state)
3331 /* Can't say anything about this other than must be nonzero. */
3332 if (dbuf.dsize == 0) {
3333 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3335 state->bad_entry = true;
3336 state->success = false;
3340 DEBUG(10,("validate_de: %s ok\n", keystr));
3344 static int validate_pwinfo(TALLOC_CTX *mem_ctx, const char *keystr,
3345 TDB_DATA dbuf, struct tdb_validation_status *state)
3347 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3353 (void)centry_string(centry, mem_ctx);
3354 (void)centry_string(centry, mem_ctx);
3355 (void)centry_string(centry, mem_ctx);
3356 (void)centry_uint32(centry);
3358 centry_free(centry);
3360 if (!(state->success)) {
3363 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3367 static int validate_nss_an(TALLOC_CTX *mem_ctx, const char *keystr,
3369 struct tdb_validation_status *state)
3371 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3377 (void)centry_string( centry, mem_ctx );
3379 centry_free(centry);
3381 if (!(state->success)) {
3384 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3388 static int validate_nss_na(TALLOC_CTX *mem_ctx, const char *keystr,
3390 struct tdb_validation_status *state)
3392 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3398 (void)centry_string( centry, mem_ctx );
3400 centry_free(centry);
3402 if (!(state->success)) {
3405 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3409 static int validate_trustdoms(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3410 struct tdb_validation_status *state)
3412 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3413 int32 num_domains, i;
3419 num_domains = centry_uint32(centry);
3421 for (i=0; i< num_domains; i++) {
3423 (void)centry_string(centry, mem_ctx);
3424 (void)centry_string(centry, mem_ctx);
3425 (void)centry_sid(centry, &sid);
3428 centry_free(centry);
3430 if (!(state->success)) {
3433 DEBUG(10,("validate_trustdoms: %s ok\n", keystr));
3437 static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
3439 struct tdb_validation_status *state)
3441 if (dbuf.dsize == 0) {
3442 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3443 "key %s (len ==0) ?\n", keystr));
3444 state->bad_entry = true;
3445 state->success = false;
3449 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
3450 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3454 static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3455 struct tdb_validation_status *state)
3457 if (dbuf.dsize != 4) {
3458 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3459 keystr, (unsigned int)dbuf.dsize ));
3460 state->bad_entry = true;
3461 state->success = false;
3464 DEBUG(10,("validate_offline: %s ok\n", keystr));
3468 static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3469 struct tdb_validation_status *state)
3471 if (dbuf.dsize != 4) {
3472 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3473 "key %s (len %u != 4) ?\n",
3474 keystr, (unsigned int)dbuf.dsize));
3475 state->bad_entry = true;
3476 state->success = false;
3480 DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
3484 /***********************************************************************
3485 A list of all possible cache tdb keys with associated validation
3487 ***********************************************************************/
3489 struct key_val_struct {
3490 const char *keyname;
3491 int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
3493 {"SEQNUM/", validate_seqnum},
3494 {"NS/", validate_ns},
3495 {"SN/", validate_sn},
3497 {"LOC_POL/", validate_loc_pol},
3498 {"PWD_POL/", validate_pwd_pol},
3499 {"CRED/", validate_cred},
3500 {"UL/", validate_ul},
3501 {"GL/", validate_gl},
3502 {"UG/", validate_ug},
3503 {"UA", validate_ua},
3504 {"GM/", validate_gm},
3505 {"DR/", validate_dr},
3506 {"DE/", validate_de},
3507 {"NSS/PWINFO/", validate_pwinfo},
3508 {"TRUSTDOMS/", validate_trustdoms},
3509 {"TRUSTDOMCACHE/", validate_trustdomcache},
3510 {"NSS/NA/", validate_nss_na},
3511 {"NSS/AN/", validate_nss_an},
3512 {"WINBINDD_OFFLINE", validate_offline},
3513 {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
3517 /***********************************************************************
3518 Function to look at every entry in the tdb and validate it as far as
3520 ***********************************************************************/
3522 static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
3525 unsigned int max_key_len = 1024;
3526 struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
3528 /* Paranoia check. */
3529 if (strncmp("UA/", (const char *)kbuf.dptr, 3) == 0) {
3530 max_key_len = 1024 * 1024;
3532 if (kbuf.dsize > max_key_len) {
3533 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
3535 (unsigned int)kbuf.dsize, (unsigned int)max_key_len));
3539 for (i = 0; key_val[i].keyname; i++) {
3540 size_t namelen = strlen(key_val[i].keyname);
3541 if (kbuf.dsize >= namelen && (
3542 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
3543 TALLOC_CTX *mem_ctx;
3547 keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
3551 memcpy(keystr, kbuf.dptr, kbuf.dsize);
3552 keystr[kbuf.dsize] = '\0';
3554 mem_ctx = talloc_init("validate_ctx");
3560 ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
3564 talloc_destroy(mem_ctx);
3569 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
3570 dump_data(0, (uint8 *)kbuf.dptr, kbuf.dsize);
3571 DEBUG(0,("data :\n"));
3572 dump_data(0, (uint8 *)dbuf.dptr, dbuf.dsize);
3573 v_state->unknown_key = true;
3574 v_state->success = false;
3575 return 1; /* terminate. */
3578 static void validate_panic(const char *const why)
3580 DEBUG(0,("validating cache: would panic %s\n", why ));
3581 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
3585 /***********************************************************************
3586 Try and validate every entry in the winbindd cache. If we fail here,
3587 delete the cache tdb and return non-zero.
3588 ***********************************************************************/
3590 int winbindd_validate_cache(void)
3593 const char *tdb_path = cache_path("winbindd_cache.tdb");
3594 TDB_CONTEXT *tdb = NULL;
3596 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3597 smb_panic_fn = validate_panic;
3600 tdb = tdb_open_log(tdb_path,
3601 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3602 ( lp_winbind_offline_logon()
3604 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
3608 DEBUG(0, ("winbindd_validate_cache: "
3609 "error opening/initializing tdb\n"));
3614 ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
3617 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
3618 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
3623 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
3624 smb_panic_fn = smb_panic;
3628 /***********************************************************************
3629 Try and validate every entry in the winbindd cache.
3630 ***********************************************************************/
3632 int winbindd_validate_cache_nobackup(void)
3635 const char *tdb_path = cache_path("winbindd_cache.tdb");
3637 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3638 smb_panic_fn = validate_panic;
3641 if (wcache == NULL || wcache->tdb == NULL) {
3642 ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
3644 ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
3648 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
3652 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
3654 smb_panic_fn = smb_panic;
3658 bool winbindd_cache_validate_and_initialize(void)
3660 close_winbindd_cache();
3662 if (lp_winbind_offline_logon()) {
3663 if (winbindd_validate_cache() < 0) {
3664 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
3665 "could be restored.\n"));
3669 return initialize_winbindd_cache();
3672 /*********************************************************************
3673 ********************************************************************/
3675 static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
3676 struct winbindd_tdc_domain **domains,
3677 size_t *num_domains )
3679 struct winbindd_tdc_domain *list = NULL;
3682 bool set_only = false;
3684 /* don't allow duplicates */
3689 for ( i=0; i< (*num_domains); i++ ) {
3690 if ( strequal( new_dom->name, list[i].domain_name ) ) {
3691 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
3702 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, 1 );
3705 list = TALLOC_REALLOC_ARRAY( *domains, *domains,
3706 struct winbindd_tdc_domain,
3711 ZERO_STRUCT( list[idx] );
3717 list[idx].domain_name = talloc_strdup( list, new_dom->name );
3718 list[idx].dns_name = talloc_strdup( list, new_dom->alt_name );
3720 if ( !is_null_sid( &new_dom->sid ) ) {
3721 sid_copy( &list[idx].sid, &new_dom->sid );
3723 sid_copy(&list[idx].sid, &global_sid_NULL);
3726 if ( new_dom->domain_flags != 0x0 )
3727 list[idx].trust_flags = new_dom->domain_flags;
3729 if ( new_dom->domain_type != 0x0 )
3730 list[idx].trust_type = new_dom->domain_type;
3732 if ( new_dom->domain_trust_attribs != 0x0 )
3733 list[idx].trust_attribs = new_dom->domain_trust_attribs;
3737 *num_domains = idx + 1;
3743 /*********************************************************************
3744 ********************************************************************/
3746 static TDB_DATA make_tdc_key( const char *domain_name )
3748 char *keystr = NULL;
3749 TDB_DATA key = { NULL, 0 };
3751 if ( !domain_name ) {
3752 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
3756 if (asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name ) == -1) {
3759 key = string_term_tdb_data(keystr);
3764 /*********************************************************************
3765 ********************************************************************/
3767 static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
3769 unsigned char **buf )
3771 unsigned char *buffer = NULL;
3776 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
3784 /* Store the number of array items first */
3785 len += tdb_pack( buffer+len, buflen-len, "d",
3788 /* now pack each domain trust record */
3789 for ( i=0; i<num_domains; i++ ) {
3794 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
3795 domains[i].domain_name,
3796 domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
3799 len += tdb_pack( buffer+len, buflen-len, "fffddd",
3800 domains[i].domain_name,
3801 domains[i].dns_name,
3802 sid_to_fstring(tmp, &domains[i].sid),
3803 domains[i].trust_flags,
3804 domains[i].trust_attribs,
3805 domains[i].trust_type );
3808 if ( buflen < len ) {
3810 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
3811 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
3825 /*********************************************************************
3826 ********************************************************************/
3828 static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
3829 struct winbindd_tdc_domain **domains )
3831 fstring domain_name, dns_name, sid_string;
3832 uint32 type, attribs, flags;
3836 struct winbindd_tdc_domain *list = NULL;
3838 /* get the number of domains */
3839 len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
3841 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3845 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, num_domains );
3847 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
3851 for ( i=0; i<num_domains; i++ ) {
3852 len += tdb_unpack( buf+len, buflen-len, "fffddd",
3861 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3862 TALLOC_FREE( list );
3866 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
3867 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
3868 domain_name, dns_name, sid_string,
3869 flags, attribs, type));
3871 list[i].domain_name = talloc_strdup( list, domain_name );
3872 list[i].dns_name = talloc_strdup( list, dns_name );
3873 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
3874 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
3877 list[i].trust_flags = flags;
3878 list[i].trust_attribs = attribs;
3879 list[i].trust_type = type;
3887 /*********************************************************************
3888 ********************************************************************/
3890 static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
3892 TDB_DATA key = make_tdc_key( lp_workgroup() );
3893 TDB_DATA data = { NULL, 0 };
3899 /* See if we were asked to delete the cache entry */
3902 ret = tdb_delete( wcache->tdb, key );
3906 data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
3913 ret = tdb_store( wcache->tdb, key, data, 0 );
3916 SAFE_FREE( data.dptr );
3917 SAFE_FREE( key.dptr );
3919 return ( ret != -1 );
3922 /*********************************************************************
3923 ********************************************************************/
3925 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
3927 TDB_DATA key = make_tdc_key( lp_workgroup() );
3928 TDB_DATA data = { NULL, 0 };
3936 data = tdb_fetch( wcache->tdb, key );
3938 SAFE_FREE( key.dptr );
3943 *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
3945 SAFE_FREE( data.dptr );
3953 /*********************************************************************
3954 ********************************************************************/
3956 bool wcache_tdc_add_domain( struct winbindd_domain *domain )
3958 struct winbindd_tdc_domain *dom_list = NULL;
3959 size_t num_domains = 0;
3962 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
3963 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
3964 domain->name, domain->alt_name,
3965 sid_string_dbg(&domain->sid),
3966 domain->domain_flags,
3967 domain->domain_trust_attribs,
3968 domain->domain_type));
3970 if ( !init_wcache() ) {
3974 /* fetch the list */
3976 wcache_tdc_fetch_list( &dom_list, &num_domains );
3978 /* add the new domain */
3980 if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
3984 /* pack the domain */
3986 if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
3994 TALLOC_FREE( dom_list );
3999 /*********************************************************************
4000 ********************************************************************/
4002 struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
4004 struct winbindd_tdc_domain *dom_list = NULL;
4005 size_t num_domains = 0;
4007 struct winbindd_tdc_domain *d = NULL;
4009 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
4011 if ( !init_wcache() ) {
4015 /* fetch the list */
4017 wcache_tdc_fetch_list( &dom_list, &num_domains );
4019 for ( i=0; i<num_domains; i++ ) {
4020 if ( strequal(name, dom_list[i].domain_name) ||
4021 strequal(name, dom_list[i].dns_name) )
4023 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4026 d = TALLOC_P( ctx, struct winbindd_tdc_domain );
4030 d->domain_name = talloc_strdup( d, dom_list[i].domain_name );
4031 d->dns_name = talloc_strdup( d, dom_list[i].dns_name );
4032 sid_copy( &d->sid, &dom_list[i].sid );
4033 d->trust_flags = dom_list[i].trust_flags;
4034 d->trust_type = dom_list[i].trust_type;
4035 d->trust_attribs = dom_list[i].trust_attribs;
4041 TALLOC_FREE( dom_list );
4047 /*********************************************************************
4048 ********************************************************************/
4050 void wcache_tdc_clear( void )
4052 if ( !init_wcache() )
4055 wcache_tdc_store_list( NULL, 0 );
4061 /*********************************************************************
4062 ********************************************************************/
4064 static void wcache_save_user_pwinfo(struct winbindd_domain *domain,
4066 const DOM_SID *user_sid,
4067 const char *homedir,
4072 struct cache_entry *centry;
4075 if ( (centry = centry_start(domain, status)) == NULL )
4078 centry_put_string( centry, homedir );
4079 centry_put_string( centry, shell );
4080 centry_put_string( centry, gecos );
4081 centry_put_uint32( centry, gid );
4083 centry_end(centry, "NSS/PWINFO/%s", sid_to_fstring(tmp, user_sid) );
4085 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid) ));
4087 centry_free(centry);
4090 NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
4091 const DOM_SID *user_sid,
4093 ADS_STRUCT *ads, LDAPMessage *msg,
4094 const char **homedir, const char **shell,
4095 const char **gecos, gid_t *p_gid)
4097 struct winbind_cache *cache = get_cache(domain);
4098 struct cache_entry *centry = NULL;
4105 centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s",
4106 sid_to_fstring(tmp, user_sid));
4111 *homedir = centry_string( centry, ctx );
4112 *shell = centry_string( centry, ctx );
4113 *gecos = centry_string( centry, ctx );
4114 *p_gid = centry_uint32( centry );
4116 centry_free(centry);
4118 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4119 sid_string_dbg(user_sid)));
4121 return NT_STATUS_OK;
4125 nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg,
4126 homedir, shell, gecos, p_gid );
4128 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status)));
4130 if ( NT_STATUS_IS_OK(nt_status) ) {
4131 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir));
4132 DEBUGADD(10, ("\tshell = '%s'\n", *shell));
4133 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos));
4134 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid));
4136 wcache_save_user_pwinfo( domain, nt_status, user_sid,
4137 *homedir, *shell, *gecos, *p_gid );
4140 if ( NT_STATUS_EQUAL( nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
4141 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4143 set_domain_offline( domain );
4150 /* the cache backend methods are exposed via this structure */
4151 struct winbindd_methods cache_methods = {