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/>.
27 #include "system/filesys.h"
29 #include "tdb_validate.h"
30 #include "../libcli/auth/libcli_auth.h"
31 #include "../librpc/gen_ndr/ndr_wbint.h"
34 #include "../libcli/security/security.h"
35 #include "passdb/machine_sid.h"
39 #define DBGC_CLASS DBGC_WINBIND
41 #define WINBINDD_CACHE_VER1 1 /* initial db version */
42 #define WINBINDD_CACHE_VER2 2 /* second version with timeouts for NDR entries */
44 #define WINBINDD_CACHE_VERSION WINBINDD_CACHE_VER2
45 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
47 extern struct winbindd_methods reconnect_methods;
49 extern struct winbindd_methods ads_methods;
51 extern struct winbindd_methods builtin_passdb_methods;
52 extern struct winbindd_methods sam_passdb_methods;
55 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
56 * Here are the list of entry types that are *not* stored
57 * as form struct cache_entry in the cache.
60 static const char *non_centry_keys[] = {
63 WINBINDD_CACHE_VERSION_KEYSTR,
67 /************************************************************************
68 Is this key a non-centry type ?
69 ************************************************************************/
71 static bool is_non_centry_key(TDB_DATA kbuf)
75 if (kbuf.dptr == NULL || kbuf.dsize == 0) {
78 for (i = 0; non_centry_keys[i] != NULL; i++) {
79 size_t namelen = strlen(non_centry_keys[i]);
80 if (kbuf.dsize < namelen) {
83 if (strncmp(non_centry_keys[i], (const char *)kbuf.dptr, namelen) == 0) {
90 /* Global online/offline state - False when online. winbindd starts up online
91 and sets this to true if the first query fails and there's an entry in
92 the cache tdb telling us to stay offline. */
94 static bool global_winbindd_offline_state;
96 struct winbind_cache {
102 uint32 sequence_number;
108 void (*smb_panic_fn)(const char *const why) = smb_panic;
110 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
112 static struct winbind_cache *wcache;
114 /* get the winbind_cache structure */
115 static struct winbind_cache *get_cache(struct winbindd_domain *domain)
117 struct winbind_cache *ret = wcache;
119 /* We have to know what type of domain we are dealing with first. */
121 if (domain->internal) {
122 domain->backend = &builtin_passdb_methods;
123 domain->initialized = True;
126 if (strequal(domain->name, get_global_sam_name()) &&
127 sid_check_is_our_sam(&domain->sid)) {
128 domain->backend = &sam_passdb_methods;
129 domain->initialized = True;
132 if ( !domain->initialized ) {
133 init_dc_connection( domain );
137 OK. listen up becasue I'm only going to say this once.
138 We have the following scenarios to consider
139 (a) trusted AD domains on a Samba DC,
140 (b) trusted AD domains and we are joined to a non-kerberos domain
141 (c) trusted AD domains and we are joined to a kerberos (AD) domain
143 For (a) we can always contact the trusted domain using krb5
144 since we have the domain trust account password
146 For (b) we can only use RPC since we have no way of
147 getting a krb5 ticket in our own domain
149 For (c) we can always use krb5 since we have a kerberos trust
154 if (!domain->backend) {
156 struct winbindd_domain *our_domain = domain;
158 /* find our domain first so we can figure out if we
159 are joined to a kerberized domain */
161 if ( !domain->primary )
162 our_domain = find_our_domain();
164 if ((our_domain->active_directory || IS_DC)
165 && domain->active_directory
166 && !lp_winbind_rpc_only()) {
167 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain->name));
168 domain->backend = &ads_methods;
170 #endif /* HAVE_ADS */
171 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain->name));
172 domain->backend = &reconnect_methods;
175 #endif /* HAVE_ADS */
181 ret = SMB_XMALLOC_P(struct winbind_cache);
185 wcache_flush_cache();
191 free a centry structure
193 static void centry_free(struct cache_entry *centry)
197 SAFE_FREE(centry->data);
201 static bool centry_check_bytes(struct cache_entry *centry, size_t nbytes)
203 if (centry->len - centry->ofs < nbytes) {
204 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
205 (unsigned int)nbytes,
206 centry->len - centry->ofs));
213 pull a uint64_t from a cache entry
215 static uint64_t centry_uint64_t(struct cache_entry *centry)
219 if (!centry_check_bytes(centry, 8)) {
220 smb_panic_fn("centry_uint64_t");
222 ret = BVAL(centry->data, centry->ofs);
228 pull a uint32 from a cache entry
230 static uint32 centry_uint32(struct cache_entry *centry)
234 if (!centry_check_bytes(centry, 4)) {
235 smb_panic_fn("centry_uint32");
237 ret = IVAL(centry->data, centry->ofs);
243 pull a uint16 from a cache entry
245 static uint16 centry_uint16(struct cache_entry *centry)
248 if (!centry_check_bytes(centry, 2)) {
249 smb_panic_fn("centry_uint16");
251 ret = SVAL(centry->data, centry->ofs);
257 pull a uint8 from a cache entry
259 static uint8 centry_uint8(struct cache_entry *centry)
262 if (!centry_check_bytes(centry, 1)) {
263 smb_panic_fn("centry_uint8");
265 ret = CVAL(centry->data, centry->ofs);
271 pull a NTTIME from a cache entry
273 static NTTIME centry_nttime(struct cache_entry *centry)
276 if (!centry_check_bytes(centry, 8)) {
277 smb_panic_fn("centry_nttime");
279 ret = IVAL(centry->data, centry->ofs);
281 ret += (uint64)IVAL(centry->data, centry->ofs) << 32;
287 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
289 static time_t centry_time(struct cache_entry *centry)
291 return (time_t)centry_nttime(centry);
294 /* pull a string from a cache entry, using the supplied
297 static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
302 len = centry_uint8(centry);
305 /* a deliberate NULL string */
309 if (!centry_check_bytes(centry, (size_t)len)) {
310 smb_panic_fn("centry_string");
313 ret = talloc_array(mem_ctx, char, len+1);
315 smb_panic_fn("centry_string out of memory\n");
317 memcpy(ret,centry->data + centry->ofs, len);
323 /* pull a hash16 from a cache entry, using the supplied
326 static char *centry_hash16(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
331 len = centry_uint8(centry);
334 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
339 if (!centry_check_bytes(centry, 16)) {
343 ret = talloc_array(mem_ctx, char, 16);
345 smb_panic_fn("centry_hash out of memory\n");
347 memcpy(ret,centry->data + centry->ofs, 16);
352 /* pull a sid from a cache entry, using the supplied
355 static bool centry_sid(struct cache_entry *centry, struct dom_sid *sid)
360 sid_string = centry_string(centry, talloc_tos());
361 if (sid_string == NULL) {
364 ret = string_to_sid(sid, sid_string);
365 TALLOC_FREE(sid_string);
371 pull a NTSTATUS from a cache entry
373 static NTSTATUS centry_ntstatus(struct cache_entry *centry)
377 status = NT_STATUS(centry_uint32(centry));
382 /* the server is considered down if it can't give us a sequence number */
383 static bool wcache_server_down(struct winbindd_domain *domain)
390 ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
393 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
398 static bool wcache_fetch_seqnum(const char *domain_name, uint32_t *seqnum,
399 uint32_t *last_seq_check)
404 if (wcache->tdb == NULL) {
405 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
409 key = talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name);
411 DEBUG(10, ("talloc failed\n"));
415 data = tdb_fetch_bystring(wcache->tdb, key);
418 if (data.dptr == NULL) {
419 DEBUG(10, ("wcache_fetch_seqnum: %s not found\n",
423 if (data.dsize != 8) {
424 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
426 SAFE_FREE(data.dptr);
430 *seqnum = IVAL(data.dptr, 0);
431 *last_seq_check = IVAL(data.dptr, 4);
432 SAFE_FREE(data.dptr);
437 static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
439 uint32 last_check, time_diff;
441 if (!wcache_fetch_seqnum(domain->name, &domain->sequence_number,
443 return NT_STATUS_UNSUCCESSFUL;
445 domain->last_seq_check = last_check;
447 /* have we expired? */
449 time_diff = now - domain->last_seq_check;
450 if ( time_diff > lp_winbind_cache_time() ) {
451 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
452 domain->name, domain->sequence_number,
453 (uint32)domain->last_seq_check));
454 return NT_STATUS_UNSUCCESSFUL;
457 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
458 domain->name, domain->sequence_number,
459 (uint32)domain->last_seq_check));
464 bool wcache_store_seqnum(const char *domain_name, uint32_t seqnum,
465 time_t last_seq_check)
471 if (wcache->tdb == NULL) {
472 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
476 key_str = talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name);
477 if (key_str == NULL) {
478 DEBUG(10, ("talloc_asprintf failed\n"));
482 SIVAL(buf, 0, seqnum);
483 SIVAL(buf, 4, last_seq_check);
485 ret = tdb_store_bystring(wcache->tdb, key_str,
486 make_tdb_data(buf, sizeof(buf)), TDB_REPLACE);
487 TALLOC_FREE(key_str);
489 DEBUG(10, ("tdb_store_bystring failed: %s\n",
490 tdb_errorstr_compat(wcache->tdb)));
491 TALLOC_FREE(key_str);
495 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
496 domain_name, seqnum, (unsigned)last_seq_check));
501 static bool store_cache_seqnum( struct winbindd_domain *domain )
503 return wcache_store_seqnum(domain->name, domain->sequence_number,
504 domain->last_seq_check);
508 refresh the domain sequence number. If force is true
509 then always refresh it, no matter how recently we fetched it
512 static void refresh_sequence_number(struct winbindd_domain *domain, bool force)
516 time_t t = time(NULL);
517 unsigned cache_time = lp_winbind_cache_time();
519 if (is_domain_offline(domain)) {
525 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
526 /* trying to reconnect is expensive, don't do it too often */
527 if (domain->sequence_number == DOM_SEQUENCE_NONE) {
532 time_diff = t - domain->last_seq_check;
534 /* see if we have to refetch the domain sequence number */
535 if (!force && (time_diff < cache_time) &&
536 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
537 NT_STATUS_IS_OK(domain->last_status)) {
538 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
542 /* try to get the sequence number from the tdb cache first */
543 /* this will update the timestamp as well */
545 status = fetch_cache_seqnum( domain, t );
546 if (NT_STATUS_IS_OK(status) &&
547 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
548 NT_STATUS_IS_OK(domain->last_status)) {
552 /* important! make sure that we know if this is a native
553 mode domain or not. And that we can contact it. */
555 if ( winbindd_can_contact_domain( domain ) ) {
556 status = domain->backend->sequence_number(domain,
557 &domain->sequence_number);
559 /* just use the current time */
560 status = NT_STATUS_OK;
561 domain->sequence_number = time(NULL);
565 /* the above call could have set our domain->backend to NULL when
566 * coming from offline to online mode, make sure to reinitialize the
567 * backend - Guenther */
570 if (!NT_STATUS_IS_OK(status)) {
571 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status)));
572 domain->sequence_number = DOM_SEQUENCE_NONE;
575 domain->last_status = status;
576 domain->last_seq_check = time(NULL);
578 /* save the new sequence number in the cache */
579 store_cache_seqnum( domain );
582 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
583 domain->name, domain->sequence_number));
589 decide if a cache entry has expired
591 static bool centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
593 /* If we've been told to be offline - stay in that state... */
594 if (lp_winbind_offline_logon() && global_winbindd_offline_state) {
595 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
596 keystr, domain->name ));
600 /* when the domain is offline return the cached entry.
601 * This deals with transient offline states... */
603 if (!domain->online) {
604 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
605 keystr, domain->name ));
609 /* if the server is OK and our cache entry came from when it was down then
610 the entry is invalid */
611 if ((domain->sequence_number != DOM_SEQUENCE_NONE) &&
612 (centry->sequence_number == DOM_SEQUENCE_NONE)) {
613 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
614 keystr, domain->name ));
618 /* if the server is down or the cache entry is not older than the
619 current sequence number or it did not timeout then it is OK */
620 if (wcache_server_down(domain)
621 || ((centry->sequence_number == domain->sequence_number)
622 && (centry->timeout > time(NULL)))) {
623 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
624 keystr, domain->name ));
628 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
629 keystr, domain->name ));
635 static struct cache_entry *wcache_fetch_raw(char *kstr)
638 struct cache_entry *centry;
641 key = string_tdb_data(kstr);
642 data = tdb_fetch_compat(wcache->tdb, key);
648 centry = SMB_XMALLOC_P(struct cache_entry);
649 centry->data = (unsigned char *)data.dptr;
650 centry->len = data.dsize;
653 if (centry->len < 16) {
654 /* huh? corrupt cache? */
655 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s "
656 "(len < 16)?\n", kstr));
661 centry->status = centry_ntstatus(centry);
662 centry->sequence_number = centry_uint32(centry);
663 centry->timeout = centry_uint64_t(centry);
668 static bool is_my_own_sam_domain(struct winbindd_domain *domain)
670 if (strequal(domain->name, get_global_sam_name()) &&
671 sid_check_is_our_sam(&domain->sid)) {
678 static bool is_builtin_domain(struct winbindd_domain *domain)
680 if (strequal(domain->name, "BUILTIN") &&
681 sid_check_is_builtin(&domain->sid)) {
689 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
690 number and return status
692 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
693 struct winbindd_domain *domain,
694 const char *format, ...) PRINTF_ATTRIBUTE(3,4);
695 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
696 struct winbindd_domain *domain,
697 const char *format, ...)
701 struct cache_entry *centry;
703 if (!winbindd_use_cache() ||
704 is_my_own_sam_domain(domain) ||
705 is_builtin_domain(domain)) {
709 refresh_sequence_number(domain, false);
711 va_start(ap, format);
712 smb_xvasprintf(&kstr, format, ap);
715 centry = wcache_fetch_raw(kstr);
716 if (centry == NULL) {
721 if (centry_expired(domain, kstr, centry)) {
723 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
724 kstr, domain->name ));
731 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
732 kstr, domain->name ));
738 static void wcache_delete(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
739 static void wcache_delete(const char *format, ...)
745 va_start(ap, format);
746 smb_xvasprintf(&kstr, format, ap);
749 key = string_tdb_data(kstr);
751 tdb_delete(wcache->tdb, key);
756 make sure we have at least len bytes available in a centry
758 static void centry_expand(struct cache_entry *centry, uint32 len)
760 if (centry->len - centry->ofs >= len)
763 centry->data = SMB_REALLOC_ARRAY(centry->data, unsigned char,
766 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
767 smb_panic_fn("out of memory in centry_expand");
772 push a uint64_t into a centry
774 static void centry_put_uint64_t(struct cache_entry *centry, uint64_t v)
776 centry_expand(centry, 8);
777 SBVAL(centry->data, centry->ofs, v);
782 push a uint32 into a centry
784 static void centry_put_uint32(struct cache_entry *centry, uint32 v)
786 centry_expand(centry, 4);
787 SIVAL(centry->data, centry->ofs, v);
792 push a uint16 into a centry
794 static void centry_put_uint16(struct cache_entry *centry, uint16 v)
796 centry_expand(centry, 2);
797 SSVAL(centry->data, centry->ofs, v);
802 push a uint8 into a centry
804 static void centry_put_uint8(struct cache_entry *centry, uint8 v)
806 centry_expand(centry, 1);
807 SCVAL(centry->data, centry->ofs, v);
812 push a string into a centry
814 static void centry_put_string(struct cache_entry *centry, const char *s)
819 /* null strings are marked as len 0xFFFF */
820 centry_put_uint8(centry, 0xFF);
825 /* can't handle more than 254 char strings. Truncating is probably best */
827 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len));
830 centry_put_uint8(centry, len);
831 centry_expand(centry, len);
832 memcpy(centry->data + centry->ofs, s, len);
837 push a 16 byte hash into a centry - treat as 16 byte string.
839 static void centry_put_hash16(struct cache_entry *centry, const uint8 val[16])
841 centry_put_uint8(centry, 16);
842 centry_expand(centry, 16);
843 memcpy(centry->data + centry->ofs, val, 16);
847 static void centry_put_sid(struct cache_entry *centry, const struct dom_sid *sid)
850 centry_put_string(centry, sid_to_fstring(sid_string, sid));
855 put NTSTATUS into a centry
857 static void centry_put_ntstatus(struct cache_entry *centry, NTSTATUS status)
859 uint32 status_value = NT_STATUS_V(status);
860 centry_put_uint32(centry, status_value);
865 push a NTTIME into a centry
867 static void centry_put_nttime(struct cache_entry *centry, NTTIME nt)
869 centry_expand(centry, 8);
870 SIVAL(centry->data, centry->ofs, nt & 0xFFFFFFFF);
872 SIVAL(centry->data, centry->ofs, nt >> 32);
877 push a time_t into a centry - use a 64 bit size.
878 NTTIME here is being used as a convenient 64-bit size.
880 static void centry_put_time(struct cache_entry *centry, time_t t)
882 NTTIME nt = (NTTIME)t;
883 centry_put_nttime(centry, nt);
887 start a centry for output. When finished, call centry_end()
889 struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status)
891 struct cache_entry *centry;
896 centry = SMB_XMALLOC_P(struct cache_entry);
898 centry->len = 8192; /* reasonable default */
899 centry->data = SMB_XMALLOC_ARRAY(uint8, centry->len);
901 centry->sequence_number = domain->sequence_number;
902 centry->timeout = lp_winbind_cache_time() + time(NULL);
903 centry_put_ntstatus(centry, status);
904 centry_put_uint32(centry, centry->sequence_number);
905 centry_put_uint64_t(centry, centry->timeout);
910 finish a centry and write it to the tdb
912 static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
913 static void centry_end(struct cache_entry *centry, const char *format, ...)
919 if (!winbindd_use_cache()) {
923 va_start(ap, format);
924 smb_xvasprintf(&kstr, format, ap);
927 key = string_tdb_data(kstr);
928 data.dptr = centry->data;
929 data.dsize = centry->ofs;
931 tdb_store(wcache->tdb, key, data, TDB_REPLACE);
935 static void wcache_save_name_to_sid(struct winbindd_domain *domain,
936 NTSTATUS status, const char *domain_name,
937 const char *name, const struct dom_sid *sid,
938 enum lsa_SidType type)
940 struct cache_entry *centry;
943 centry = centry_start(domain, status);
947 if ((domain_name == NULL) || (domain_name[0] == '\0')) {
948 struct winbindd_domain *mydomain =
949 find_domain_from_sid_noinit(sid);
950 if (mydomain != NULL) {
951 domain_name = mydomain->name;
955 centry_put_uint32(centry, type);
956 centry_put_sid(centry, sid);
957 fstrcpy(uname, name);
958 (void)strupper_m(uname);
959 centry_end(centry, "NS/%s/%s", domain_name, uname);
960 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name,
961 uname, sid_string_dbg(sid), nt_errstr(status)));
965 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
966 const struct dom_sid *sid, const char *domain_name, const char *name, enum lsa_SidType type)
968 struct cache_entry *centry;
971 centry = centry_start(domain, status);
975 if ((domain_name == NULL) || (domain_name[0] == '\0')) {
976 struct winbindd_domain *mydomain =
977 find_domain_from_sid_noinit(sid);
978 if (mydomain != NULL) {
979 domain_name = mydomain->name;
983 if (NT_STATUS_IS_OK(status)) {
984 centry_put_uint32(centry, type);
985 centry_put_string(centry, domain_name);
986 centry_put_string(centry, name);
989 centry_end(centry, "SN/%s", sid_to_fstring(sid_string, sid));
990 DEBUG(10,("wcache_save_sid_to_name: %s -> %s\\%s (%s)\n", sid_string,
991 domain_name, name, nt_errstr(status)));
996 static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status,
997 struct wbint_userinfo *info)
999 struct cache_entry *centry;
1002 if (is_null_sid(&info->user_sid)) {
1006 centry = centry_start(domain, status);
1009 centry_put_string(centry, info->acct_name);
1010 centry_put_string(centry, info->full_name);
1011 centry_put_string(centry, info->homedir);
1012 centry_put_string(centry, info->shell);
1013 centry_put_uint32(centry, info->primary_gid);
1014 centry_put_sid(centry, &info->user_sid);
1015 centry_put_sid(centry, &info->group_sid);
1016 centry_end(centry, "U/%s", sid_to_fstring(sid_string,
1018 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
1019 centry_free(centry);
1022 static void wcache_save_lockout_policy(struct winbindd_domain *domain,
1024 struct samr_DomInfo12 *lockout_policy)
1026 struct cache_entry *centry;
1028 centry = centry_start(domain, status);
1032 centry_put_nttime(centry, lockout_policy->lockout_duration);
1033 centry_put_nttime(centry, lockout_policy->lockout_window);
1034 centry_put_uint16(centry, lockout_policy->lockout_threshold);
1036 centry_end(centry, "LOC_POL/%s", domain->name);
1038 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
1040 centry_free(centry);
1045 static void wcache_save_password_policy(struct winbindd_domain *domain,
1047 struct samr_DomInfo1 *policy)
1049 struct cache_entry *centry;
1051 centry = centry_start(domain, status);
1055 centry_put_uint16(centry, policy->min_password_length);
1056 centry_put_uint16(centry, policy->password_history_length);
1057 centry_put_uint32(centry, policy->password_properties);
1058 centry_put_nttime(centry, policy->max_password_age);
1059 centry_put_nttime(centry, policy->min_password_age);
1061 centry_end(centry, "PWD_POL/%s", domain->name);
1063 DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
1065 centry_free(centry);
1068 /***************************************************************************
1069 ***************************************************************************/
1071 static void wcache_save_username_alias(struct winbindd_domain *domain,
1073 const char *name, const char *alias)
1075 struct cache_entry *centry;
1078 if ( (centry = centry_start(domain, status)) == NULL )
1081 centry_put_string( centry, alias );
1083 fstrcpy(uname, name);
1084 (void)strupper_m(uname);
1085 centry_end(centry, "NSS/NA/%s", uname);
1087 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name, alias ));
1089 centry_free(centry);
1092 static void wcache_save_alias_username(struct winbindd_domain *domain,
1094 const char *alias, const char *name)
1096 struct cache_entry *centry;
1099 if ( (centry = centry_start(domain, status)) == NULL )
1102 centry_put_string( centry, name );
1104 fstrcpy(uname, alias);
1105 (void)strupper_m(uname);
1106 centry_end(centry, "NSS/AN/%s", uname);
1108 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias, name ));
1110 centry_free(centry);
1113 /***************************************************************************
1114 ***************************************************************************/
1116 NTSTATUS resolve_username_to_alias( TALLOC_CTX *mem_ctx,
1117 struct winbindd_domain *domain,
1118 const char *name, char **alias )
1120 struct winbind_cache *cache = get_cache(domain);
1121 struct cache_entry *centry = NULL;
1125 if ( domain->internal )
1126 return NT_STATUS_NOT_SUPPORTED;
1131 upper_name = talloc_strdup(mem_ctx, name);
1132 if (upper_name == NULL) {
1133 return NT_STATUS_NO_MEMORY;
1135 if (!strupper_m(upper_name)) {
1136 talloc_free(upper_name);
1137 return NT_STATUS_INVALID_PARAMETER;
1140 centry = wcache_fetch(cache, domain, "NSS/NA/%s", upper_name);
1142 talloc_free(upper_name);
1147 status = centry->status;
1149 if (!NT_STATUS_IS_OK(status)) {
1150 centry_free(centry);
1154 *alias = centry_string( centry, mem_ctx );
1156 centry_free(centry);
1158 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1159 name, *alias ? *alias : "(none)"));
1161 return (*alias) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1165 /* If its not in cache and we are offline, then fail */
1167 if ( get_global_winbindd_state_offline() || !domain->online ) {
1168 DEBUG(8,("resolve_username_to_alias: rejecting query "
1169 "in offline mode\n"));
1170 return NT_STATUS_NOT_FOUND;
1173 status = nss_map_to_alias( mem_ctx, domain->name, name, alias );
1175 if ( NT_STATUS_IS_OK( status ) ) {
1176 wcache_save_username_alias(domain, status, name, *alias);
1179 if ( NT_STATUS_EQUAL( status, NT_STATUS_NONE_MAPPED ) ) {
1180 wcache_save_username_alias(domain, status, name, "(NULL)");
1183 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1184 nt_errstr(status)));
1186 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1187 set_domain_offline( domain );
1193 /***************************************************************************
1194 ***************************************************************************/
1196 NTSTATUS resolve_alias_to_username( TALLOC_CTX *mem_ctx,
1197 struct winbindd_domain *domain,
1198 const char *alias, char **name )
1200 struct winbind_cache *cache = get_cache(domain);
1201 struct cache_entry *centry = NULL;
1205 if ( domain->internal )
1206 return NT_STATUS_NOT_SUPPORTED;
1211 upper_name = talloc_strdup(mem_ctx, alias);
1212 if (upper_name == NULL) {
1213 return NT_STATUS_NO_MEMORY;
1215 if (!strupper_m(upper_name)) {
1216 talloc_free(upper_name);
1217 return NT_STATUS_INVALID_PARAMETER;
1220 centry = wcache_fetch(cache, domain, "NSS/AN/%s", upper_name);
1222 talloc_free(upper_name);
1227 status = centry->status;
1229 if (!NT_STATUS_IS_OK(status)) {
1230 centry_free(centry);
1234 *name = centry_string( centry, mem_ctx );
1236 centry_free(centry);
1238 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1239 alias, *name ? *name : "(none)"));
1241 return (*name) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1245 /* If its not in cache and we are offline, then fail */
1247 if ( get_global_winbindd_state_offline() || !domain->online ) {
1248 DEBUG(8,("resolve_alias_to_username: rejecting query "
1249 "in offline mode\n"));
1250 return NT_STATUS_NOT_FOUND;
1253 /* an alias cannot contain a domain prefix or '@' */
1255 if (strchr(alias, '\\') || strchr(alias, '@')) {
1256 DEBUG(10,("resolve_alias_to_username: skipping fully "
1257 "qualified name %s\n", alias));
1258 return NT_STATUS_OBJECT_NAME_INVALID;
1261 status = nss_map_from_alias( mem_ctx, domain->name, alias, name );
1263 if ( NT_STATUS_IS_OK( status ) ) {
1264 wcache_save_alias_username( domain, status, alias, *name );
1267 if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1268 wcache_save_alias_username(domain, status, alias, "(NULL)");
1271 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1272 nt_errstr(status)));
1274 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1275 set_domain_offline( domain );
1281 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const struct dom_sid *sid)
1283 struct winbind_cache *cache = get_cache(domain);
1285 fstring key_str, tmp;
1289 return NT_STATUS_INTERNAL_DB_ERROR;
1292 if (is_null_sid(sid)) {
1293 return NT_STATUS_INVALID_SID;
1296 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1297 return NT_STATUS_INVALID_SID;
1300 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
1302 data = tdb_fetch_compat(cache->tdb, string_tdb_data(key_str));
1304 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1307 SAFE_FREE(data.dptr);
1308 return NT_STATUS_OK;
1311 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1312 as new salted ones. */
1314 NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
1315 TALLOC_CTX *mem_ctx,
1316 const struct dom_sid *sid,
1317 const uint8 **cached_nt_pass,
1318 const uint8 **cached_salt)
1320 struct winbind_cache *cache = get_cache(domain);
1321 struct cache_entry *centry = NULL;
1327 return NT_STATUS_INTERNAL_DB_ERROR;
1330 if (is_null_sid(sid)) {
1331 return NT_STATUS_INVALID_SID;
1334 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1335 return NT_STATUS_INVALID_SID;
1338 /* Try and get a salted cred first. If we can't
1339 fall back to an unsalted cred. */
1341 centry = wcache_fetch(cache, domain, "CRED/%s",
1342 sid_to_fstring(tmp, sid));
1344 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1345 sid_string_dbg(sid)));
1346 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1350 * We don't use the time element at this moment,
1351 * but we have to consume it, so that we don't
1352 * neet to change the disk format of the cache.
1354 (void)centry_time(centry);
1356 /* In the salted case this isn't actually the nt_hash itself,
1357 but the MD5 of the salt + nt_hash. Let the caller
1358 sort this out. It can tell as we only return the cached_salt
1359 if we are returning a salted cred. */
1361 *cached_nt_pass = (const uint8 *)centry_hash16(centry, mem_ctx);
1362 if (*cached_nt_pass == NULL) {
1365 sid_to_fstring(sidstr, sid);
1367 /* Bad (old) cred cache. Delete and pretend we
1369 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1371 wcache_delete("CRED/%s", sidstr);
1372 centry_free(centry);
1373 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1376 /* We only have 17 bytes more data in the salted cred case. */
1377 if (centry->len - centry->ofs == 17) {
1378 *cached_salt = (const uint8 *)centry_hash16(centry, mem_ctx);
1380 *cached_salt = NULL;
1383 dump_data_pw("cached_nt_pass", *cached_nt_pass, NT_HASH_LEN);
1385 dump_data_pw("cached_salt", *cached_salt, NT_HASH_LEN);
1388 status = centry->status;
1390 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1391 sid_string_dbg(sid), nt_errstr(status) ));
1393 centry_free(centry);
1397 /* Store creds for a SID - only writes out new salted ones. */
1399 NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
1400 const struct dom_sid *sid,
1401 const uint8 nt_pass[NT_HASH_LEN])
1403 struct cache_entry *centry;
1406 uint8 cred_salt[NT_HASH_LEN];
1407 uint8 salted_hash[NT_HASH_LEN];
1409 if (is_null_sid(sid)) {
1410 return NT_STATUS_INVALID_SID;
1413 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1414 return NT_STATUS_INVALID_SID;
1417 centry = centry_start(domain, NT_STATUS_OK);
1419 return NT_STATUS_INTERNAL_DB_ERROR;
1422 dump_data_pw("nt_pass", nt_pass, NT_HASH_LEN);
1424 centry_put_time(centry, time(NULL));
1426 /* Create a salt and then salt the hash. */
1427 generate_random_buffer(cred_salt, NT_HASH_LEN);
1428 E_md5hash(cred_salt, nt_pass, salted_hash);
1430 centry_put_hash16(centry, salted_hash);
1431 centry_put_hash16(centry, cred_salt);
1432 centry_end(centry, "CRED/%s", sid_to_fstring(sid_string, sid));
1434 DEBUG(10,("wcache_save_creds: %s\n", sid_string));
1436 centry_free(centry);
1438 return NT_STATUS_OK;
1442 /* Query display info. This is the basic user list fn */
1443 static NTSTATUS query_user_list(struct winbindd_domain *domain,
1444 TALLOC_CTX *mem_ctx,
1445 uint32 *num_entries,
1446 struct wbint_userinfo **info)
1448 struct winbind_cache *cache = get_cache(domain);
1449 struct cache_entry *centry = NULL;
1451 unsigned int i, retry;
1452 bool old_status = domain->online;
1457 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1462 *num_entries = centry_uint32(centry);
1464 if (*num_entries == 0)
1467 (*info) = talloc_array(mem_ctx, struct wbint_userinfo, *num_entries);
1469 smb_panic_fn("query_user_list out of memory");
1471 for (i=0; i<(*num_entries); i++) {
1472 (*info)[i].acct_name = centry_string(centry, mem_ctx);
1473 (*info)[i].full_name = centry_string(centry, mem_ctx);
1474 (*info)[i].homedir = centry_string(centry, mem_ctx);
1475 (*info)[i].shell = centry_string(centry, mem_ctx);
1476 centry_sid(centry, &(*info)[i].user_sid);
1477 centry_sid(centry, &(*info)[i].group_sid);
1481 status = centry->status;
1483 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1484 domain->name, nt_errstr(status) ));
1486 centry_free(centry);
1493 /* Return status value returned by seq number check */
1495 if (!NT_STATUS_IS_OK(domain->last_status))
1496 return domain->last_status;
1498 /* Put the query_user_list() in a retry loop. There appears to be
1499 * some bug either with Windows 2000 or Samba's handling of large
1500 * rpc replies. This manifests itself as sudden disconnection
1501 * at a random point in the enumeration of a large (60k) user list.
1502 * The retry loop simply tries the operation again. )-: It's not
1503 * pretty but an acceptable workaround until we work out what the
1504 * real problem is. */
1509 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1512 status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
1513 if (!NT_STATUS_IS_OK(status)) {
1514 DEBUG(3, ("query_user_list: returned 0x%08x, "
1515 "retrying\n", NT_STATUS_V(status)));
1517 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1518 DEBUG(3, ("query_user_list: flushing "
1519 "connection cache\n"));
1520 invalidate_cm_connection(&domain->conn);
1522 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1523 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1524 if (!domain->internal && old_status) {
1525 set_domain_offline(domain);
1527 /* store partial response. */
1528 if (*num_entries > 0) {
1530 * humm, what about the status used for cache?
1531 * Should it be NT_STATUS_OK?
1536 * domain is offline now, and there is no user entries,
1537 * try to fetch from cache again.
1539 if (cache->tdb && !domain->online && !domain->internal && old_status) {
1540 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1541 /* partial response... */
1545 goto do_fetch_cache;
1552 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
1556 refresh_sequence_number(domain, false);
1557 if (!NT_STATUS_IS_OK(status)) {
1560 centry = centry_start(domain, status);
1563 centry_put_uint32(centry, *num_entries);
1564 for (i=0; i<(*num_entries); i++) {
1565 centry_put_string(centry, (*info)[i].acct_name);
1566 centry_put_string(centry, (*info)[i].full_name);
1567 centry_put_string(centry, (*info)[i].homedir);
1568 centry_put_string(centry, (*info)[i].shell);
1569 centry_put_sid(centry, &(*info)[i].user_sid);
1570 centry_put_sid(centry, &(*info)[i].group_sid);
1571 if (domain->backend && domain->backend->consistent) {
1572 /* when the backend is consistent we can pre-prime some mappings */
1573 wcache_save_name_to_sid(domain, NT_STATUS_OK,
1575 (*info)[i].acct_name,
1576 &(*info)[i].user_sid,
1578 wcache_save_sid_to_name(domain, NT_STATUS_OK,
1579 &(*info)[i].user_sid,
1581 (*info)[i].acct_name,
1583 wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
1586 centry_end(centry, "UL/%s", domain->name);
1587 centry_free(centry);
1593 /* list all domain groups */
1594 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
1595 TALLOC_CTX *mem_ctx,
1596 uint32 *num_entries,
1597 struct wb_acct_info **info)
1599 struct winbind_cache *cache = get_cache(domain);
1600 struct cache_entry *centry = NULL;
1605 old_status = domain->online;
1609 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1614 *num_entries = centry_uint32(centry);
1616 if (*num_entries == 0)
1619 (*info) = talloc_array(mem_ctx, struct wb_acct_info, *num_entries);
1621 smb_panic_fn("enum_dom_groups out of memory");
1623 for (i=0; i<(*num_entries); i++) {
1624 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1625 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1626 (*info)[i].rid = centry_uint32(centry);
1630 status = centry->status;
1632 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1633 domain->name, nt_errstr(status) ));
1635 centry_free(centry);
1642 /* Return status value returned by seq number check */
1644 if (!NT_STATUS_IS_OK(domain->last_status))
1645 return domain->last_status;
1647 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1650 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1652 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1653 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1654 if (!domain->internal && old_status) {
1655 set_domain_offline(domain);
1659 !domain->internal &&
1661 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1663 goto do_fetch_cache;
1668 refresh_sequence_number(domain, false);
1669 if (!NT_STATUS_IS_OK(status)) {
1672 centry = centry_start(domain, status);
1675 centry_put_uint32(centry, *num_entries);
1676 for (i=0; i<(*num_entries); i++) {
1677 centry_put_string(centry, (*info)[i].acct_name);
1678 centry_put_string(centry, (*info)[i].acct_desc);
1679 centry_put_uint32(centry, (*info)[i].rid);
1681 centry_end(centry, "GL/%s/domain", domain->name);
1682 centry_free(centry);
1688 /* list all domain groups */
1689 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
1690 TALLOC_CTX *mem_ctx,
1691 uint32 *num_entries,
1692 struct wb_acct_info **info)
1694 struct winbind_cache *cache = get_cache(domain);
1695 struct cache_entry *centry = NULL;
1700 old_status = domain->online;
1704 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1709 *num_entries = centry_uint32(centry);
1711 if (*num_entries == 0)
1714 (*info) = talloc_array(mem_ctx, struct wb_acct_info, *num_entries);
1716 smb_panic_fn("enum_dom_groups out of memory");
1718 for (i=0; i<(*num_entries); i++) {
1719 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1720 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1721 (*info)[i].rid = centry_uint32(centry);
1726 /* If we are returning cached data and the domain controller
1727 is down then we don't know whether the data is up to date
1728 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1731 if (wcache_server_down(domain)) {
1732 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1733 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1735 status = centry->status;
1737 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1738 domain->name, nt_errstr(status) ));
1740 centry_free(centry);
1747 /* Return status value returned by seq number check */
1749 if (!NT_STATUS_IS_OK(domain->last_status))
1750 return domain->last_status;
1752 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1755 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1757 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1758 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1759 if (!domain->internal && old_status) {
1760 set_domain_offline(domain);
1763 !domain->internal &&
1766 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1768 goto do_fetch_cache;
1773 refresh_sequence_number(domain, false);
1774 if (!NT_STATUS_IS_OK(status)) {
1777 centry = centry_start(domain, status);
1780 centry_put_uint32(centry, *num_entries);
1781 for (i=0; i<(*num_entries); i++) {
1782 centry_put_string(centry, (*info)[i].acct_name);
1783 centry_put_string(centry, (*info)[i].acct_desc);
1784 centry_put_uint32(centry, (*info)[i].rid);
1786 centry_end(centry, "GL/%s/local", domain->name);
1787 centry_free(centry);
1793 NTSTATUS wcache_name_to_sid(struct winbindd_domain *domain,
1794 const char *domain_name,
1796 struct dom_sid *sid,
1797 enum lsa_SidType *type)
1799 struct winbind_cache *cache = get_cache(domain);
1800 struct cache_entry *centry;
1804 if (cache->tdb == NULL) {
1805 return NT_STATUS_NOT_FOUND;
1808 uname = talloc_strdup_upper(talloc_tos(), name);
1809 if (uname == NULL) {
1810 return NT_STATUS_NO_MEMORY;
1813 if ((domain_name == NULL) || (domain_name[0] == '\0')) {
1814 domain_name = domain->name;
1817 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1819 if (centry == NULL) {
1820 return NT_STATUS_NOT_FOUND;
1823 status = centry->status;
1824 if (NT_STATUS_IS_OK(status)) {
1825 *type = (enum lsa_SidType)centry_uint32(centry);
1826 centry_sid(centry, sid);
1829 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1830 "%s\n", domain->name, nt_errstr(status) ));
1832 centry_free(centry);
1836 /* convert a single name to a sid in a domain */
1837 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
1838 TALLOC_CTX *mem_ctx,
1839 const char *domain_name,
1842 struct dom_sid *sid,
1843 enum lsa_SidType *type)
1848 old_status = domain->online;
1850 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1851 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1857 /* If the seq number check indicated that there is a problem
1858 * with this DC, then return that status... except for
1859 * access_denied. This is special because the dc may be in
1860 * "restrict anonymous = 1" mode, in which case it will deny
1861 * most unauthenticated operations, but *will* allow the LSA
1862 * name-to-sid that we try as a fallback. */
1864 if (!(NT_STATUS_IS_OK(domain->last_status)
1865 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1866 return domain->last_status;
1868 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1871 status = domain->backend->name_to_sid(domain, mem_ctx, domain_name,
1872 name, flags, sid, type);
1874 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1875 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1876 if (!domain->internal && old_status) {
1877 set_domain_offline(domain);
1879 if (!domain->internal &&
1882 NTSTATUS cache_status;
1883 cache_status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1884 return cache_status;
1888 refresh_sequence_number(domain, false);
1890 if (domain->online &&
1891 (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
1892 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1894 /* Only save the reverse mapping if this was not a UPN */
1895 if (!strchr(name, '@')) {
1896 if (!strupper_m(discard_const_p(char, domain_name))) {
1897 return NT_STATUS_INVALID_PARAMETER;
1899 (void)strlower_m(discard_const_p(char, name));
1900 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1907 NTSTATUS wcache_sid_to_name(struct winbindd_domain *domain,
1908 const struct dom_sid *sid,
1909 TALLOC_CTX *mem_ctx,
1912 enum lsa_SidType *type)
1914 struct winbind_cache *cache = get_cache(domain);
1915 struct cache_entry *centry;
1919 if (cache->tdb == NULL) {
1920 return NT_STATUS_NOT_FOUND;
1923 sid_string = sid_string_tos(sid);
1924 if (sid_string == NULL) {
1925 return NT_STATUS_NO_MEMORY;
1928 centry = wcache_fetch(cache, domain, "SN/%s", sid_string);
1929 TALLOC_FREE(sid_string);
1930 if (centry == NULL) {
1931 return NT_STATUS_NOT_FOUND;
1934 if (NT_STATUS_IS_OK(centry->status)) {
1935 *type = (enum lsa_SidType)centry_uint32(centry);
1936 *domain_name = centry_string(centry, mem_ctx);
1937 *name = centry_string(centry, mem_ctx);
1940 status = centry->status;
1941 centry_free(centry);
1943 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1944 "%s\n", domain->name, nt_errstr(status) ));
1949 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1951 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
1952 TALLOC_CTX *mem_ctx,
1953 const struct dom_sid *sid,
1956 enum lsa_SidType *type)
1961 old_status = domain->online;
1962 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
1964 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1969 *domain_name = NULL;
1971 /* If the seq number check indicated that there is a problem
1972 * with this DC, then return that status... except for
1973 * access_denied. This is special because the dc may be in
1974 * "restrict anonymous = 1" mode, in which case it will deny
1975 * most unauthenticated operations, but *will* allow the LSA
1976 * sid-to-name that we try as a fallback. */
1978 if (!(NT_STATUS_IS_OK(domain->last_status)
1979 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1980 return domain->last_status;
1982 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1985 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1987 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1988 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1989 if (!domain->internal && old_status) {
1990 set_domain_offline(domain);
1992 if (!domain->internal &&
1995 NTSTATUS cache_status;
1996 cache_status = wcache_sid_to_name(domain, sid, mem_ctx,
1997 domain_name, name, type);
1998 return cache_status;
2002 refresh_sequence_number(domain, false);
2003 if (!NT_STATUS_IS_OK(status)) {
2006 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
2008 /* We can't save the name to sid mapping here, as with sid history a
2009 * later name2sid would give the wrong sid. */
2014 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
2015 TALLOC_CTX *mem_ctx,
2016 const struct dom_sid *domain_sid,
2021 enum lsa_SidType **types)
2023 struct winbind_cache *cache = get_cache(domain);
2025 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
2030 old_status = domain->online;
2031 *domain_name = NULL;
2039 if (num_rids == 0) {
2040 return NT_STATUS_OK;
2043 *names = talloc_array(mem_ctx, char *, num_rids);
2044 *types = talloc_array(mem_ctx, enum lsa_SidType, num_rids);
2046 if ((*names == NULL) || (*types == NULL)) {
2047 result = NT_STATUS_NO_MEMORY;
2051 have_mapped = have_unmapped = false;
2053 for (i=0; i<num_rids; i++) {
2055 struct cache_entry *centry;
2058 if (!sid_compose(&sid, domain_sid, rids[i])) {
2059 result = NT_STATUS_INTERNAL_ERROR;
2063 centry = wcache_fetch(cache, domain, "SN/%s",
2064 sid_to_fstring(tmp, &sid));
2069 (*types)[i] = SID_NAME_UNKNOWN;
2070 (*names)[i] = talloc_strdup(*names, "");
2072 if (NT_STATUS_IS_OK(centry->status)) {
2075 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
2077 dom = centry_string(centry, mem_ctx);
2078 if (*domain_name == NULL) {
2084 (*names)[i] = centry_string(centry, *names);
2086 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)
2087 || NT_STATUS_EQUAL(centry->status, STATUS_SOME_UNMAPPED)) {
2088 have_unmapped = true;
2091 /* something's definitely wrong */
2092 result = centry->status;
2093 centry_free(centry);
2097 centry_free(centry);
2101 return NT_STATUS_NONE_MAPPED;
2103 if (!have_unmapped) {
2104 return NT_STATUS_OK;
2106 return STATUS_SOME_UNMAPPED;
2110 TALLOC_FREE(*names);
2111 TALLOC_FREE(*types);
2113 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
2114 rids, num_rids, domain_name,
2117 if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
2118 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2119 if (!domain->internal && old_status) {
2120 set_domain_offline(domain);
2123 !domain->internal &&
2126 have_mapped = have_unmapped = false;
2128 for (i=0; i<num_rids; i++) {
2130 struct cache_entry *centry;
2133 if (!sid_compose(&sid, domain_sid, rids[i])) {
2134 result = NT_STATUS_INTERNAL_ERROR;
2138 centry = wcache_fetch(cache, domain, "SN/%s",
2139 sid_to_fstring(tmp, &sid));
2141 (*types)[i] = SID_NAME_UNKNOWN;
2142 (*names)[i] = talloc_strdup(*names, "");
2146 (*types)[i] = SID_NAME_UNKNOWN;
2147 (*names)[i] = talloc_strdup(*names, "");
2149 if (NT_STATUS_IS_OK(centry->status)) {
2152 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
2154 dom = centry_string(centry, mem_ctx);
2155 if (*domain_name == NULL) {
2161 (*names)[i] = centry_string(centry, *names);
2163 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
2164 have_unmapped = true;
2167 /* something's definitely wrong */
2168 result = centry->status;
2169 centry_free(centry);
2173 centry_free(centry);
2177 return NT_STATUS_NONE_MAPPED;
2179 if (!have_unmapped) {
2180 return NT_STATUS_OK;
2182 return STATUS_SOME_UNMAPPED;
2186 None of the queried rids has been found so save all negative entries
2188 if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
2189 for (i = 0; i < num_rids; i++) {
2191 const char *name = "";
2192 const enum lsa_SidType type = SID_NAME_UNKNOWN;
2193 NTSTATUS status = NT_STATUS_NONE_MAPPED;
2195 if (!sid_compose(&sid, domain_sid, rids[i])) {
2196 return NT_STATUS_INTERNAL_ERROR;
2199 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2207 Some or all of the queried rids have been found.
2209 if (!NT_STATUS_IS_OK(result) &&
2210 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
2214 refresh_sequence_number(domain, false);
2216 for (i=0; i<num_rids; i++) {
2220 if (!sid_compose(&sid, domain_sid, rids[i])) {
2221 result = NT_STATUS_INTERNAL_ERROR;
2225 status = (*types)[i] == SID_NAME_UNKNOWN ?
2226 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
2228 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2229 (*names)[i], (*types)[i]);
2235 TALLOC_FREE(*names);
2236 TALLOC_FREE(*types);
2240 NTSTATUS wcache_query_user(struct winbindd_domain *domain,
2241 TALLOC_CTX *mem_ctx,
2242 const struct dom_sid *user_sid,
2243 struct wbint_userinfo *info)
2245 struct winbind_cache *cache = get_cache(domain);
2246 struct cache_entry *centry = NULL;
2250 if (cache->tdb == NULL) {
2251 return NT_STATUS_NOT_FOUND;
2254 sid_string = sid_string_tos(user_sid);
2255 if (sid_string == NULL) {
2256 return NT_STATUS_NO_MEMORY;
2259 centry = wcache_fetch(cache, domain, "U/%s", sid_string);
2260 TALLOC_FREE(sid_string);
2261 if (centry == NULL) {
2262 return NT_STATUS_NOT_FOUND;
2266 * If we have an access denied cache entry and a cached info3
2267 * in the samlogon cache then do a query. This will force the
2268 * rpc back end to return the info3 data.
2271 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED) &&
2272 netsamlogon_cache_have(user_sid)) {
2273 DEBUG(10, ("query_user: cached access denied and have cached "
2275 domain->last_status = NT_STATUS_OK;
2276 centry_free(centry);
2277 return NT_STATUS_NOT_FOUND;
2280 /* if status is not ok then this is a negative hit
2281 and the rest of the data doesn't matter */
2282 status = centry->status;
2283 if (NT_STATUS_IS_OK(status)) {
2284 info->acct_name = centry_string(centry, mem_ctx);
2285 info->full_name = centry_string(centry, mem_ctx);
2286 info->homedir = centry_string(centry, mem_ctx);
2287 info->shell = centry_string(centry, mem_ctx);
2288 info->primary_gid = centry_uint32(centry);
2289 centry_sid(centry, &info->user_sid);
2290 centry_sid(centry, &info->group_sid);
2293 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2294 "%s\n", domain->name, nt_errstr(status) ));
2296 centry_free(centry);
2300 /* Lookup user information from a rid */
2301 static NTSTATUS query_user(struct winbindd_domain *domain,
2302 TALLOC_CTX *mem_ctx,
2303 const struct dom_sid *user_sid,
2304 struct wbint_userinfo *info)
2309 old_status = domain->online;
2310 status = wcache_query_user(domain, mem_ctx, user_sid, info);
2311 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2317 /* Return status value returned by seq number check */
2319 if (!NT_STATUS_IS_OK(domain->last_status))
2320 return domain->last_status;
2322 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2325 status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
2327 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2328 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2329 if (!domain->internal && old_status) {
2330 set_domain_offline(domain);
2332 if (!domain->internal &&
2335 NTSTATUS cache_status;
2336 cache_status = wcache_query_user(domain, mem_ctx, user_sid, info);
2337 return cache_status;
2341 refresh_sequence_number(domain, false);
2342 if (!NT_STATUS_IS_OK(status)) {
2345 wcache_save_user(domain, status, info);
2350 NTSTATUS wcache_lookup_usergroups(struct winbindd_domain *domain,
2351 TALLOC_CTX *mem_ctx,
2352 const struct dom_sid *user_sid,
2353 uint32_t *pnum_sids,
2354 struct dom_sid **psids)
2356 struct winbind_cache *cache = get_cache(domain);
2357 struct cache_entry *centry = NULL;
2359 uint32_t i, num_sids;
2360 struct dom_sid *sids;
2363 if (cache->tdb == NULL) {
2364 return NT_STATUS_NOT_FOUND;
2367 centry = wcache_fetch(cache, domain, "UG/%s",
2368 sid_to_fstring(sid_string, user_sid));
2369 if (centry == NULL) {
2370 return NT_STATUS_NOT_FOUND;
2373 /* If we have an access denied cache entry and a cached info3 in the
2374 samlogon cache then do a query. This will force the rpc back end
2375 to return the info3 data. */
2377 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)
2378 && netsamlogon_cache_have(user_sid)) {
2379 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2381 domain->last_status = NT_STATUS_OK;
2382 centry_free(centry);
2383 return NT_STATUS_NOT_FOUND;
2386 num_sids = centry_uint32(centry);
2387 sids = talloc_array(mem_ctx, struct dom_sid, num_sids);
2389 centry_free(centry);
2390 return NT_STATUS_NO_MEMORY;
2393 for (i=0; i<num_sids; i++) {
2394 centry_sid(centry, &sids[i]);
2397 status = centry->status;
2399 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2400 "status: %s\n", domain->name, nt_errstr(status)));
2402 centry_free(centry);
2404 *pnum_sids = num_sids;
2409 /* Lookup groups a user is a member of. */
2410 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
2411 TALLOC_CTX *mem_ctx,
2412 const struct dom_sid *user_sid,
2413 uint32 *num_groups, struct dom_sid **user_gids)
2415 struct cache_entry *centry = NULL;
2421 old_status = domain->online;
2422 status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2423 num_groups, user_gids);
2424 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2429 (*user_gids) = NULL;
2431 /* Return status value returned by seq number check */
2433 if (!NT_STATUS_IS_OK(domain->last_status))
2434 return domain->last_status;
2436 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2439 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
2441 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2442 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2443 if (!domain->internal && old_status) {
2444 set_domain_offline(domain);
2446 if (!domain->internal &&
2449 NTSTATUS cache_status;
2450 cache_status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2451 num_groups, user_gids);
2452 return cache_status;
2455 if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
2459 refresh_sequence_number(domain, false);
2460 if (!NT_STATUS_IS_OK(status)) {
2463 centry = centry_start(domain, status);
2467 centry_put_uint32(centry, *num_groups);
2468 for (i=0; i<(*num_groups); i++) {
2469 centry_put_sid(centry, &(*user_gids)[i]);
2472 centry_end(centry, "UG/%s", sid_to_fstring(sid_string, user_sid));
2473 centry_free(centry);
2479 static char *wcache_make_sidlist(TALLOC_CTX *mem_ctx, uint32_t num_sids,
2480 const struct dom_sid *sids)
2485 sidlist = talloc_strdup(mem_ctx, "");
2486 if (sidlist == NULL) {
2489 for (i=0; i<num_sids; i++) {
2491 sidlist = talloc_asprintf_append_buffer(
2492 sidlist, "/%s", sid_to_fstring(tmp, &sids[i]));
2493 if (sidlist == NULL) {
2500 NTSTATUS wcache_lookup_useraliases(struct winbindd_domain *domain,
2501 TALLOC_CTX *mem_ctx, uint32_t num_sids,
2502 const struct dom_sid *sids,
2503 uint32_t *pnum_aliases, uint32_t **paliases)
2505 struct winbind_cache *cache = get_cache(domain);
2506 struct cache_entry *centry = NULL;
2507 uint32_t num_aliases;
2513 if (cache->tdb == NULL) {
2514 return NT_STATUS_NOT_FOUND;
2517 if (num_sids == 0) {
2520 return NT_STATUS_OK;
2523 /* We need to cache indexed by the whole list of SIDs, the aliases
2524 * resulting might come from any of the SIDs. */
2526 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2527 if (sidlist == NULL) {
2528 return NT_STATUS_NO_MEMORY;
2531 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
2532 TALLOC_FREE(sidlist);
2533 if (centry == NULL) {
2534 return NT_STATUS_NOT_FOUND;
2537 num_aliases = centry_uint32(centry);
2538 aliases = talloc_array(mem_ctx, uint32_t, num_aliases);
2539 if (aliases == NULL) {
2540 centry_free(centry);
2541 return NT_STATUS_NO_MEMORY;
2544 for (i=0; i<num_aliases; i++) {
2545 aliases[i] = centry_uint32(centry);
2548 status = centry->status;
2550 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2551 "status %s\n", domain->name, nt_errstr(status)));
2553 centry_free(centry);
2555 *pnum_aliases = num_aliases;
2556 *paliases = aliases;
2561 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
2562 TALLOC_CTX *mem_ctx,
2563 uint32 num_sids, const struct dom_sid *sids,
2564 uint32 *num_aliases, uint32 **alias_rids)
2566 struct cache_entry *centry = NULL;
2572 old_status = domain->online;
2573 status = wcache_lookup_useraliases(domain, mem_ctx, num_sids, sids,
2574 num_aliases, alias_rids);
2575 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2580 (*alias_rids) = NULL;
2582 if (!NT_STATUS_IS_OK(domain->last_status))
2583 return domain->last_status;
2585 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2586 "for domain %s\n", domain->name ));
2588 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2589 if (sidlist == NULL) {
2590 return NT_STATUS_NO_MEMORY;
2593 status = domain->backend->lookup_useraliases(domain, mem_ctx,
2595 num_aliases, alias_rids);
2597 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2598 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2599 if (!domain->internal && old_status) {
2600 set_domain_offline(domain);
2602 if (!domain->internal &&
2605 NTSTATUS cache_status;
2606 cache_status = wcache_lookup_useraliases(domain, mem_ctx, num_sids,
2607 sids, num_aliases, alias_rids);
2608 return cache_status;
2612 refresh_sequence_number(domain, false);
2613 if (!NT_STATUS_IS_OK(status)) {
2616 centry = centry_start(domain, status);
2619 centry_put_uint32(centry, *num_aliases);
2620 for (i=0; i<(*num_aliases); i++)
2621 centry_put_uint32(centry, (*alias_rids)[i]);
2622 centry_end(centry, "UA%s", sidlist);
2623 centry_free(centry);
2629 NTSTATUS wcache_lookup_groupmem(struct winbindd_domain *domain,
2630 TALLOC_CTX *mem_ctx,
2631 const struct dom_sid *group_sid,
2632 uint32_t *num_names,
2633 struct dom_sid **sid_mem, char ***names,
2634 uint32_t **name_types)
2636 struct winbind_cache *cache = get_cache(domain);
2637 struct cache_entry *centry = NULL;
2642 if (cache->tdb == NULL) {
2643 return NT_STATUS_NOT_FOUND;
2646 sid_string = sid_string_tos(group_sid);
2647 if (sid_string == NULL) {
2648 return NT_STATUS_NO_MEMORY;
2651 centry = wcache_fetch(cache, domain, "GM/%s", sid_string);
2652 TALLOC_FREE(sid_string);
2653 if (centry == NULL) {
2654 return NT_STATUS_NOT_FOUND;
2661 *num_names = centry_uint32(centry);
2662 if (*num_names == 0) {
2663 centry_free(centry);
2664 return NT_STATUS_OK;
2667 *sid_mem = talloc_array(mem_ctx, struct dom_sid, *num_names);
2668 *names = talloc_array(mem_ctx, char *, *num_names);
2669 *name_types = talloc_array(mem_ctx, uint32, *num_names);
2671 if ((*sid_mem == NULL) || (*names == NULL) || (*name_types == NULL)) {
2672 TALLOC_FREE(*sid_mem);
2673 TALLOC_FREE(*names);
2674 TALLOC_FREE(*name_types);
2675 centry_free(centry);
2676 return NT_STATUS_NO_MEMORY;
2679 for (i=0; i<(*num_names); i++) {
2680 centry_sid(centry, &(*sid_mem)[i]);
2681 (*names)[i] = centry_string(centry, mem_ctx);
2682 (*name_types)[i] = centry_uint32(centry);
2685 status = centry->status;
2687 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2688 "status: %s\n", domain->name, nt_errstr(status)));
2690 centry_free(centry);
2694 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
2695 TALLOC_CTX *mem_ctx,
2696 const struct dom_sid *group_sid,
2697 enum lsa_SidType type,
2699 struct dom_sid **sid_mem, char ***names,
2700 uint32 **name_types)
2702 struct cache_entry *centry = NULL;
2708 old_status = domain->online;
2709 status = wcache_lookup_groupmem(domain, mem_ctx, group_sid, num_names,
2710 sid_mem, names, name_types);
2711 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2718 (*name_types) = NULL;
2720 /* Return status value returned by seq number check */
2722 if (!NT_STATUS_IS_OK(domain->last_status))
2723 return domain->last_status;
2725 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2728 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid,
2730 sid_mem, names, name_types);
2732 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2733 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2734 if (!domain->internal && old_status) {
2735 set_domain_offline(domain);
2737 if (!domain->internal &&
2740 NTSTATUS cache_status;
2741 cache_status = wcache_lookup_groupmem(domain, mem_ctx, group_sid,
2742 num_names, sid_mem, names,
2744 return cache_status;
2748 refresh_sequence_number(domain, false);
2749 if (!NT_STATUS_IS_OK(status)) {
2752 centry = centry_start(domain, status);
2755 centry_put_uint32(centry, *num_names);
2756 for (i=0; i<(*num_names); i++) {
2757 centry_put_sid(centry, &(*sid_mem)[i]);
2758 centry_put_string(centry, (*names)[i]);
2759 centry_put_uint32(centry, (*name_types)[i]);
2761 centry_end(centry, "GM/%s", sid_to_fstring(sid_string, group_sid));
2762 centry_free(centry);
2768 /* find the sequence number for a domain */
2769 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
2771 refresh_sequence_number(domain, false);
2773 *seq = domain->sequence_number;
2775 return NT_STATUS_OK;
2778 /* enumerate trusted domains
2779 * (we need to have the list of trustdoms in the cache when we go offline) -
2781 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
2782 TALLOC_CTX *mem_ctx,
2783 struct netr_DomainTrustList *trusts)
2786 struct winbind_cache *cache;
2787 struct winbindd_tdc_domain *dom_list = NULL;
2788 size_t num_domains = 0;
2789 bool retval = false;
2793 old_status = domain->online;
2795 trusts->array = NULL;
2797 cache = get_cache(domain);
2798 if (!cache || !cache->tdb) {
2802 if (domain->online) {
2806 retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2807 if (!retval || !num_domains || !dom_list) {
2808 TALLOC_FREE(dom_list);
2813 trusts->array = talloc_zero_array(mem_ctx, struct netr_DomainTrust, num_domains);
2814 if (!trusts->array) {
2815 TALLOC_FREE(dom_list);
2816 return NT_STATUS_NO_MEMORY;
2819 for (i = 0; i < num_domains; i++) {
2820 struct netr_DomainTrust *trust;
2821 struct dom_sid *sid;
2822 struct winbindd_domain *dom;
2824 dom = find_domain_from_name_noinit(dom_list[i].domain_name);
2825 if (dom && dom->internal) {
2829 trust = &trusts->array[trusts->count];
2830 trust->netbios_name = talloc_strdup(trusts->array, dom_list[i].domain_name);
2831 trust->dns_name = talloc_strdup(trusts->array, dom_list[i].dns_name);
2832 sid = talloc(trusts->array, struct dom_sid);
2833 if (!trust->netbios_name || !trust->dns_name ||
2835 TALLOC_FREE(dom_list);
2836 TALLOC_FREE(trusts->array);
2837 return NT_STATUS_NO_MEMORY;
2840 trust->trust_flags = dom_list[i].trust_flags;
2841 trust->trust_attributes = dom_list[i].trust_attribs;
2842 trust->trust_type = dom_list[i].trust_type;
2843 sid_copy(sid, &dom_list[i].sid);
2848 TALLOC_FREE(dom_list);
2849 return NT_STATUS_OK;
2852 /* Return status value returned by seq number check */
2854 if (!NT_STATUS_IS_OK(domain->last_status))
2855 return domain->last_status;
2857 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2860 status = domain->backend->trusted_domains(domain, mem_ctx, trusts);
2862 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2863 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2864 if (!domain->internal && old_status) {
2865 set_domain_offline(domain);
2867 if (!domain->internal &&
2870 retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2871 if (retval && num_domains && dom_list) {
2872 TALLOC_FREE(trusts->array);
2874 goto do_fetch_cache;
2878 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2879 * so that the generic centry handling still applies correctly -
2882 if (!NT_STATUS_IS_ERR(status)) {
2883 status = NT_STATUS_OK;
2888 /* get lockout policy */
2889 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
2890 TALLOC_CTX *mem_ctx,
2891 struct samr_DomInfo12 *policy)
2893 struct winbind_cache *cache = get_cache(domain);
2894 struct cache_entry *centry = NULL;
2898 old_status = domain->online;
2902 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2908 policy->lockout_duration = centry_nttime(centry);
2909 policy->lockout_window = centry_nttime(centry);
2910 policy->lockout_threshold = centry_uint16(centry);
2912 status = centry->status;
2914 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2915 domain->name, nt_errstr(status) ));
2917 centry_free(centry);
2921 ZERO_STRUCTP(policy);
2923 /* Return status value returned by seq number check */
2925 if (!NT_STATUS_IS_OK(domain->last_status))
2926 return domain->last_status;
2928 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2931 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2933 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2934 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2935 if (!domain->internal && old_status) {
2936 set_domain_offline(domain);
2939 !domain->internal &&
2942 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2944 goto do_fetch_cache;
2949 refresh_sequence_number(domain, false);
2950 if (!NT_STATUS_IS_OK(status)) {
2953 wcache_save_lockout_policy(domain, status, policy);
2958 /* get password policy */
2959 static NTSTATUS password_policy(struct winbindd_domain *domain,
2960 TALLOC_CTX *mem_ctx,
2961 struct samr_DomInfo1 *policy)
2963 struct winbind_cache *cache = get_cache(domain);
2964 struct cache_entry *centry = NULL;
2968 old_status = domain->online;
2972 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2978 policy->min_password_length = centry_uint16(centry);
2979 policy->password_history_length = centry_uint16(centry);
2980 policy->password_properties = centry_uint32(centry);
2981 policy->max_password_age = centry_nttime(centry);
2982 policy->min_password_age = centry_nttime(centry);
2984 status = centry->status;
2986 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2987 domain->name, nt_errstr(status) ));
2989 centry_free(centry);
2993 ZERO_STRUCTP(policy);
2995 /* Return status value returned by seq number check */
2997 if (!NT_STATUS_IS_OK(domain->last_status))
2998 return domain->last_status;
3000 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
3003 status = domain->backend->password_policy(domain, mem_ctx, policy);
3005 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
3006 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
3007 if (!domain->internal && old_status) {
3008 set_domain_offline(domain);
3011 !domain->internal &&
3014 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
3016 goto do_fetch_cache;
3021 refresh_sequence_number(domain, false);
3022 if (!NT_STATUS_IS_OK(status)) {
3025 wcache_save_password_policy(domain, status, policy);
3031 /* Invalidate cached user and group lists coherently */
3033 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3036 if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
3037 strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
3038 tdb_delete(the_tdb, kbuf);
3043 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3045 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
3046 const struct dom_sid *sid)
3048 fstring key_str, sid_string;
3049 struct winbind_cache *cache;
3051 /* dont clear cached U/SID and UG/SID entries when we want to logon
3054 if (lp_winbind_offline_logon()) {
3061 cache = get_cache(domain);
3067 /* Clear U/SID cache entry */
3068 fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, sid));
3069 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
3070 tdb_delete(cache->tdb, string_tdb_data(key_str));
3072 /* Clear UG/SID cache entry */
3073 fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, sid));
3074 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
3075 tdb_delete(cache->tdb, string_tdb_data(key_str));
3077 /* Samba/winbindd never needs this. */
3078 netsamlogon_clear_cached_user(sid);
3081 bool wcache_invalidate_cache(void)
3083 struct winbindd_domain *domain;
3085 for (domain = domain_list(); domain; domain = domain->next) {
3086 struct winbind_cache *cache = get_cache(domain);
3088 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3089 "entries for %s\n", domain->name));
3092 tdb_traverse(cache->tdb, traverse_fn, NULL);
3101 bool wcache_invalidate_cache_noinit(void)
3103 struct winbindd_domain *domain;
3105 for (domain = domain_list(); domain; domain = domain->next) {
3106 struct winbind_cache *cache;
3108 /* Skip uninitialized domains. */
3109 if (!domain->initialized && !domain->internal) {
3113 cache = get_cache(domain);
3115 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3116 "entries for %s\n", domain->name));
3119 tdb_traverse(cache->tdb, traverse_fn, NULL);
3121 * Flushing cache has nothing to with domains.
3122 * return here if we successfully flushed once.
3123 * To avoid unnecessary traversing the cache.
3134 bool init_wcache(void)
3136 if (wcache == NULL) {
3137 wcache = SMB_XMALLOC_P(struct winbind_cache);
3138 ZERO_STRUCTP(wcache);
3141 if (wcache->tdb != NULL)
3144 /* when working offline we must not clear the cache on restart */
3145 wcache->tdb = tdb_open_log(state_path("winbindd_cache.tdb"),
3146 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3147 TDB_INCOMPATIBLE_HASH |
3148 (lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
3149 O_RDWR|O_CREAT, 0600);
3151 if (wcache->tdb == NULL) {
3152 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3159 /************************************************************************
3160 This is called by the parent to initialize the cache file.
3161 We don't need sophisticated locking here as we know we're the
3163 ************************************************************************/
3165 bool initialize_winbindd_cache(void)
3167 bool cache_bad = true;
3170 if (!init_wcache()) {
3171 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3175 /* Check version number. */
3176 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
3177 vers == WINBINDD_CACHE_VERSION) {
3182 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3183 "and re-creating with version number %d\n",
3184 WINBINDD_CACHE_VERSION ));
3186 tdb_close(wcache->tdb);
3189 if (unlink(state_path("winbindd_cache.tdb")) == -1) {
3190 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3191 state_path("winbindd_cache.tdb"),
3195 if (!init_wcache()) {
3196 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3197 "init_wcache failed.\n"));
3201 /* Write the version. */
3202 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
3203 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3204 tdb_errorstr_compat(wcache->tdb) ));
3209 tdb_close(wcache->tdb);
3214 void close_winbindd_cache(void)
3220 tdb_close(wcache->tdb);
3225 bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
3226 char **domain_name, char **name,
3227 enum lsa_SidType *type)
3229 struct winbindd_domain *domain;
3232 domain = find_lookup_domain_from_sid(sid);
3233 if (domain == NULL) {
3236 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
3238 return NT_STATUS_IS_OK(status);
3241 bool lookup_cached_name(const char *domain_name,
3243 struct dom_sid *sid,
3244 enum lsa_SidType *type)
3246 struct winbindd_domain *domain;
3248 bool original_online_state;
3250 domain = find_lookup_domain_from_name(domain_name);
3251 if (domain == NULL) {
3255 /* If we are doing a cached logon, temporarily set the domain
3256 offline so the cache won't expire the entry */
3258 original_online_state = domain->online;
3259 domain->online = false;
3260 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
3261 domain->online = original_online_state;
3263 return NT_STATUS_IS_OK(status);
3266 void cache_name2sid(struct winbindd_domain *domain,
3267 const char *domain_name, const char *name,
3268 enum lsa_SidType type, const struct dom_sid *sid)
3270 refresh_sequence_number(domain, false);
3271 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
3276 * The original idea that this cache only contains centries has
3277 * been blurred - now other stuff gets put in here. Ensure we
3278 * ignore these things on cleanup.
3281 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
3282 TDB_DATA dbuf, void *state)
3284 struct cache_entry *centry;
3286 if (is_non_centry_key(kbuf)) {
3290 centry = wcache_fetch_raw((char *)kbuf.dptr);
3295 if (!NT_STATUS_IS_OK(centry->status)) {
3296 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
3297 tdb_delete(the_tdb, kbuf);
3300 centry_free(centry);
3304 /* flush the cache */
3305 void wcache_flush_cache(void)
3310 tdb_close(wcache->tdb);
3313 if (!winbindd_use_cache()) {
3317 /* when working offline we must not clear the cache on restart */
3318 wcache->tdb = tdb_open_log(state_path("winbindd_cache.tdb"),
3319 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3320 TDB_INCOMPATIBLE_HASH |
3321 (lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
3322 O_RDWR|O_CREAT, 0600);
3325 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3329 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
3331 DEBUG(10,("wcache_flush_cache success\n"));
3334 /* Count cached creds */
3336 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3339 int *cred_count = (int*)state;
3341 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3347 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
3349 struct winbind_cache *cache = get_cache(domain);
3354 return NT_STATUS_INTERNAL_DB_ERROR;
3357 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
3359 return NT_STATUS_OK;
3363 struct cred_list *prev, *next;
3368 static struct cred_list *wcache_cred_list;
3370 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3373 struct cred_list *cred;
3375 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3377 cred = SMB_MALLOC_P(struct cred_list);
3379 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3385 /* save a copy of the key */
3387 fstrcpy(cred->name, (const char *)kbuf.dptr);
3388 DLIST_ADD(wcache_cred_list, cred);
3394 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const struct dom_sid *sid)
3396 struct winbind_cache *cache = get_cache(domain);
3399 struct cred_list *cred, *oldest = NULL;
3402 return NT_STATUS_INTERNAL_DB_ERROR;
3405 /* we possibly already have an entry */
3406 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
3408 fstring key_str, tmp;
3410 DEBUG(11,("we already have an entry, deleting that\n"));
3412 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
3414 tdb_delete(cache->tdb, string_tdb_data(key_str));
3416 return NT_STATUS_OK;
3419 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
3421 return NT_STATUS_OK;
3422 } else if ((ret < 0) || (wcache_cred_list == NULL)) {
3423 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3426 ZERO_STRUCTP(oldest);
3428 for (cred = wcache_cred_list; cred; cred = cred->next) {
3433 data = tdb_fetch_compat(cache->tdb, string_tdb_data(cred->name));
3435 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3437 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
3441 t = IVAL(data.dptr, 0);
3442 SAFE_FREE(data.dptr);
3445 oldest = SMB_MALLOC_P(struct cred_list);
3446 if (oldest == NULL) {
3447 status = NT_STATUS_NO_MEMORY;
3451 fstrcpy(oldest->name, cred->name);
3452 oldest->created = t;
3456 if (t < oldest->created) {
3457 fstrcpy(oldest->name, cred->name);
3458 oldest->created = t;
3462 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
3463 status = NT_STATUS_OK;
3465 status = NT_STATUS_UNSUCCESSFUL;
3468 SAFE_FREE(wcache_cred_list);
3474 /* Change the global online/offline state. */
3475 bool set_global_winbindd_state_offline(void)
3479 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3481 /* Only go offline if someone has created
3482 the key "WINBINDD_OFFLINE" in the cache tdb. */
3484 if (wcache == NULL || wcache->tdb == NULL) {
3485 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3489 if (!lp_winbind_offline_logon()) {
3490 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3494 if (global_winbindd_offline_state) {
3495 /* Already offline. */
3499 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
3501 if (!data.dptr || data.dsize != 4) {
3502 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3503 SAFE_FREE(data.dptr);
3506 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3507 global_winbindd_offline_state = true;
3508 SAFE_FREE(data.dptr);
3513 void set_global_winbindd_state_online(void)
3515 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3517 if (!lp_winbind_offline_logon()) {
3518 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3522 if (!global_winbindd_offline_state) {
3523 /* Already online. */
3526 global_winbindd_offline_state = false;
3532 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3533 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
3536 bool get_global_winbindd_state_offline(void)
3538 return global_winbindd_offline_state;
3541 /***********************************************************************
3542 Validate functions for all possible cache tdb keys.
3543 ***********************************************************************/
3545 static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
3546 struct tdb_validation_status *state)
3548 struct cache_entry *centry;
3550 centry = SMB_XMALLOC_P(struct cache_entry);
3551 centry->data = (unsigned char *)memdup(data.dptr, data.dsize);
3552 if (!centry->data) {
3556 centry->len = data.dsize;
3559 if (centry->len < 16) {
3560 /* huh? corrupt cache? */
3561 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3562 "(len < 16) ?\n", kstr));
3563 centry_free(centry);
3564 state->bad_entry = true;
3565 state->success = false;
3569 centry->status = NT_STATUS(centry_uint32(centry));
3570 centry->sequence_number = centry_uint32(centry);
3571 centry->timeout = centry_uint64_t(centry);
3575 static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3576 struct tdb_validation_status *state)
3578 if (dbuf.dsize != 8) {
3579 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3580 keystr, (unsigned int)dbuf.dsize ));
3581 state->bad_entry = true;
3587 static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3588 struct tdb_validation_status *state)
3590 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3595 (void)centry_uint32(centry);
3596 if (NT_STATUS_IS_OK(centry->status)) {
3598 (void)centry_sid(centry, &sid);
3601 centry_free(centry);
3603 if (!(state->success)) {
3606 DEBUG(10,("validate_ns: %s ok\n", keystr));
3610 static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3611 struct tdb_validation_status *state)
3613 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3618 if (NT_STATUS_IS_OK(centry->status)) {
3619 (void)centry_uint32(centry);
3620 (void)centry_string(centry, mem_ctx);
3621 (void)centry_string(centry, mem_ctx);
3624 centry_free(centry);
3626 if (!(state->success)) {
3629 DEBUG(10,("validate_sn: %s ok\n", keystr));
3633 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3634 struct tdb_validation_status *state)
3636 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3643 (void)centry_string(centry, mem_ctx);
3644 (void)centry_string(centry, mem_ctx);
3645 (void)centry_string(centry, mem_ctx);
3646 (void)centry_string(centry, mem_ctx);
3647 (void)centry_uint32(centry);
3648 (void)centry_sid(centry, &sid);
3649 (void)centry_sid(centry, &sid);
3651 centry_free(centry);
3653 if (!(state->success)) {
3656 DEBUG(10,("validate_u: %s ok\n", keystr));
3660 static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3661 struct tdb_validation_status *state)
3663 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3669 (void)centry_nttime(centry);
3670 (void)centry_nttime(centry);
3671 (void)centry_uint16(centry);
3673 centry_free(centry);
3675 if (!(state->success)) {
3678 DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
3682 static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3683 struct tdb_validation_status *state)
3685 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3691 (void)centry_uint16(centry);
3692 (void)centry_uint16(centry);
3693 (void)centry_uint32(centry);
3694 (void)centry_nttime(centry);
3695 (void)centry_nttime(centry);
3697 centry_free(centry);
3699 if (!(state->success)) {
3702 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
3706 static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3707 struct tdb_validation_status *state)
3709 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3715 (void)centry_time(centry);
3716 (void)centry_hash16(centry, mem_ctx);
3718 /* We only have 17 bytes more data in the salted cred case. */
3719 if (centry->len - centry->ofs == 17) {
3720 (void)centry_hash16(centry, mem_ctx);
3723 centry_free(centry);
3725 if (!(state->success)) {
3728 DEBUG(10,("validate_cred: %s ok\n", keystr));
3732 static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3733 struct tdb_validation_status *state)
3735 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3736 int32 num_entries, i;
3742 num_entries = (int32)centry_uint32(centry);
3744 for (i=0; i< num_entries; i++) {
3746 (void)centry_string(centry, mem_ctx);
3747 (void)centry_string(centry, mem_ctx);
3748 (void)centry_string(centry, mem_ctx);
3749 (void)centry_string(centry, mem_ctx);
3750 (void)centry_sid(centry, &sid);
3751 (void)centry_sid(centry, &sid);
3754 centry_free(centry);
3756 if (!(state->success)) {
3759 DEBUG(10,("validate_ul: %s ok\n", keystr));
3763 static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3764 struct tdb_validation_status *state)
3766 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3767 int32 num_entries, i;
3773 num_entries = centry_uint32(centry);
3775 for (i=0; i< num_entries; i++) {
3776 (void)centry_string(centry, mem_ctx);
3777 (void)centry_string(centry, mem_ctx);
3778 (void)centry_uint32(centry);
3781 centry_free(centry);
3783 if (!(state->success)) {
3786 DEBUG(10,("validate_gl: %s ok\n", keystr));
3790 static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3791 struct tdb_validation_status *state)
3793 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3794 int32 num_groups, i;
3800 num_groups = centry_uint32(centry);
3802 for (i=0; i< num_groups; i++) {
3804 centry_sid(centry, &sid);
3807 centry_free(centry);
3809 if (!(state->success)) {
3812 DEBUG(10,("validate_ug: %s ok\n", keystr));
3816 static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3817 struct tdb_validation_status *state)
3819 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3820 int32 num_aliases, i;
3826 num_aliases = centry_uint32(centry);
3828 for (i=0; i < num_aliases; i++) {
3829 (void)centry_uint32(centry);
3832 centry_free(centry);
3834 if (!(state->success)) {
3837 DEBUG(10,("validate_ua: %s ok\n", keystr));
3841 static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3842 struct tdb_validation_status *state)
3844 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3851 num_names = centry_uint32(centry);
3853 for (i=0; i< num_names; i++) {
3855 centry_sid(centry, &sid);
3856 (void)centry_string(centry, mem_ctx);
3857 (void)centry_uint32(centry);
3860 centry_free(centry);
3862 if (!(state->success)) {
3865 DEBUG(10,("validate_gm: %s ok\n", keystr));
3869 static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3870 struct tdb_validation_status *state)
3872 /* Can't say anything about this other than must be nonzero. */
3873 if (dbuf.dsize == 0) {
3874 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3876 state->bad_entry = true;
3877 state->success = false;
3881 DEBUG(10,("validate_dr: %s ok\n", keystr));
3885 static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3886 struct tdb_validation_status *state)
3888 /* Can't say anything about this other than must be nonzero. */
3889 if (dbuf.dsize == 0) {
3890 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3892 state->bad_entry = true;
3893 state->success = false;
3897 DEBUG(10,("validate_de: %s ok\n", keystr));
3901 static int validate_pwinfo(TALLOC_CTX *mem_ctx, const char *keystr,
3902 TDB_DATA dbuf, struct tdb_validation_status *state)
3904 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3910 (void)centry_string(centry, mem_ctx);
3911 (void)centry_string(centry, mem_ctx);
3912 (void)centry_string(centry, mem_ctx);
3913 (void)centry_uint32(centry);
3915 centry_free(centry);
3917 if (!(state->success)) {
3920 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3924 static int validate_nss_an(TALLOC_CTX *mem_ctx, const char *keystr,
3926 struct tdb_validation_status *state)
3928 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3934 (void)centry_string( centry, mem_ctx );
3936 centry_free(centry);
3938 if (!(state->success)) {
3941 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3945 static int validate_nss_na(TALLOC_CTX *mem_ctx, const char *keystr,
3947 struct tdb_validation_status *state)
3949 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3955 (void)centry_string( centry, mem_ctx );
3957 centry_free(centry);
3959 if (!(state->success)) {
3962 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3966 static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
3968 struct tdb_validation_status *state)
3970 if (dbuf.dsize == 0) {
3971 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3972 "key %s (len ==0) ?\n", keystr));
3973 state->bad_entry = true;
3974 state->success = false;
3978 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
3979 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3983 static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3984 struct tdb_validation_status *state)
3986 if (dbuf.dsize != 4) {
3987 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3988 keystr, (unsigned int)dbuf.dsize ));
3989 state->bad_entry = true;
3990 state->success = false;
3993 DEBUG(10,("validate_offline: %s ok\n", keystr));
3997 static int validate_ndr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3998 struct tdb_validation_status *state)
4001 * Ignore validation for now. The proper way to do this is with a
4002 * checksum. Just pure parsing does not really catch much.
4007 static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
4008 struct tdb_validation_status *state)
4010 if (dbuf.dsize != 4) {
4011 DEBUG(0, ("validate_cache_version: Corrupt cache for "
4012 "key %s (len %u != 4) ?\n",
4013 keystr, (unsigned int)dbuf.dsize));
4014 state->bad_entry = true;
4015 state->success = false;
4019 DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
4023 /***********************************************************************
4024 A list of all possible cache tdb keys with associated validation
4026 ***********************************************************************/
4028 struct key_val_struct {
4029 const char *keyname;
4030 int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
4032 {"SEQNUM/", validate_seqnum},
4033 {"NS/", validate_ns},
4034 {"SN/", validate_sn},
4036 {"LOC_POL/", validate_loc_pol},
4037 {"PWD_POL/", validate_pwd_pol},
4038 {"CRED/", validate_cred},
4039 {"UL/", validate_ul},
4040 {"GL/", validate_gl},
4041 {"UG/", validate_ug},
4042 {"UA", validate_ua},
4043 {"GM/", validate_gm},
4044 {"DR/", validate_dr},
4045 {"DE/", validate_de},
4046 {"NSS/PWINFO/", validate_pwinfo},
4047 {"TRUSTDOMCACHE/", validate_trustdomcache},
4048 {"NSS/NA/", validate_nss_na},
4049 {"NSS/AN/", validate_nss_an},
4050 {"WINBINDD_OFFLINE", validate_offline},
4051 {"NDR/", validate_ndr},
4052 {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
4056 /***********************************************************************
4057 Function to look at every entry in the tdb and validate it as far as
4059 ***********************************************************************/
4061 static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
4064 unsigned int max_key_len = 1024;
4065 struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
4067 /* Paranoia check. */
4068 if (strncmp("UA/", (const char *)kbuf.dptr, 3) == 0) {
4069 max_key_len = 1024 * 1024;
4071 if (kbuf.dsize > max_key_len) {
4072 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4074 (unsigned int)kbuf.dsize, (unsigned int)max_key_len));
4078 for (i = 0; key_val[i].keyname; i++) {
4079 size_t namelen = strlen(key_val[i].keyname);
4080 if (kbuf.dsize >= namelen && (
4081 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
4082 TALLOC_CTX *mem_ctx;
4086 keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
4090 memcpy(keystr, kbuf.dptr, kbuf.dsize);
4091 keystr[kbuf.dsize] = '\0';
4093 mem_ctx = talloc_init("validate_ctx");
4099 ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
4103 talloc_destroy(mem_ctx);
4108 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4109 dump_data(0, (uint8 *)kbuf.dptr, kbuf.dsize);
4110 DEBUG(0,("data :\n"));
4111 dump_data(0, (uint8 *)dbuf.dptr, dbuf.dsize);
4112 v_state->unknown_key = true;
4113 v_state->success = false;
4114 return 1; /* terminate. */
4117 static void validate_panic(const char *const why)
4119 DEBUG(0,("validating cache: would panic %s\n", why ));
4120 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4124 static int wbcache_update_centry_fn(TDB_CONTEXT *tdb,
4132 if (is_non_centry_key(key)) {
4136 if (data.dptr == NULL || data.dsize == 0) {
4137 if (tdb_delete(tdb, key) < 0) {
4138 DEBUG(0, ("tdb_delete for [%s] failed!\n",
4144 /* add timeout to blob (uint64_t) */
4145 blob.dsize = data.dsize + 8;
4147 blob.dptr = SMB_XMALLOC_ARRAY(uint8_t, blob.dsize);
4148 if (blob.dptr == NULL) {
4151 memset(blob.dptr, 0, blob.dsize);
4153 /* copy status and seqnum */
4154 memcpy(blob.dptr, data.dptr, 8);
4157 ctimeout = lp_winbind_cache_time() + time(NULL);
4158 SBVAL(blob.dptr, 8, ctimeout);
4161 memcpy(blob.dptr + 16, data.dptr + 8, data.dsize - 8);
4163 if (tdb_store(tdb, key, blob, TDB_REPLACE) < 0) {
4164 DEBUG(0, ("tdb_store to update [%s] failed!\n",
4166 SAFE_FREE(blob.dptr);
4170 SAFE_FREE(blob.dptr);
4174 static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT *tdb)
4178 DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
4180 rc = tdb_traverse(tdb, wbcache_update_centry_fn, NULL);
4188 /***********************************************************************
4189 Try and validate every entry in the winbindd cache. If we fail here,
4190 delete the cache tdb and return non-zero.
4191 ***********************************************************************/
4193 int winbindd_validate_cache(void)
4196 const char *tdb_path = state_path("winbindd_cache.tdb");
4197 TDB_CONTEXT *tdb = NULL;
4201 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4202 smb_panic_fn = validate_panic;
4204 tdb = tdb_open_log(tdb_path,
4205 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
4206 TDB_INCOMPATIBLE_HASH |
4207 ( lp_winbind_offline_logon()
4209 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
4213 DEBUG(0, ("winbindd_validate_cache: "
4214 "error opening/initializing tdb\n"));
4218 /* Version check and upgrade code. */
4219 if (!tdb_fetch_uint32(tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers_id)) {
4220 DEBUG(10, ("Fresh database\n"));
4221 tdb_store_uint32(tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION);
4222 vers_id = WINBINDD_CACHE_VERSION;
4225 if (vers_id != WINBINDD_CACHE_VERSION) {
4226 if (vers_id == WINBINDD_CACHE_VER1) {
4227 ok = wbcache_upgrade_v1_to_v2(tdb);
4229 DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
4234 tdb_store_uint32(tdb,
4235 WINBINDD_CACHE_VERSION_KEYSTR,
4236 WINBINDD_CACHE_VERSION);
4237 vers_id = WINBINDD_CACHE_VER2;
4243 ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
4246 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4247 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
4252 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4253 smb_panic_fn = smb_panic;
4257 /***********************************************************************
4258 Try and validate every entry in the winbindd cache.
4259 ***********************************************************************/
4261 int winbindd_validate_cache_nobackup(void)
4264 const char *tdb_path = state_path("winbindd_cache.tdb");
4266 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4267 smb_panic_fn = validate_panic;
4270 if (wcache == NULL || wcache->tdb == NULL) {
4271 ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
4273 ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
4277 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4281 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4283 smb_panic_fn = smb_panic;
4287 bool winbindd_cache_validate_and_initialize(void)
4289 close_winbindd_cache();
4291 if (lp_winbind_offline_logon()) {
4292 if (winbindd_validate_cache() < 0) {
4293 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4294 "could be restored.\n"));
4298 return initialize_winbindd_cache();
4301 /*********************************************************************
4302 ********************************************************************/
4304 static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
4305 struct winbindd_tdc_domain **domains,
4306 size_t *num_domains )
4308 struct winbindd_tdc_domain *list = NULL;
4311 bool set_only = false;
4313 /* don't allow duplicates */
4318 for ( i=0; i< (*num_domains); i++ ) {
4319 if ( strequal( new_dom->name, list[i].domain_name ) ) {
4320 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4331 list = talloc_array( NULL, struct winbindd_tdc_domain, 1 );
4334 list = talloc_realloc( *domains, *domains,
4335 struct winbindd_tdc_domain,
4340 ZERO_STRUCT( list[idx] );
4346 list[idx].domain_name = talloc_strdup(list, new_dom->name);
4347 if (list[idx].domain_name == NULL) {
4350 if (new_dom->alt_name != NULL) {
4351 list[idx].dns_name = talloc_strdup(list, new_dom->alt_name);
4352 if (list[idx].dns_name == NULL) {
4357 if ( !is_null_sid( &new_dom->sid ) ) {
4358 sid_copy( &list[idx].sid, &new_dom->sid );
4360 sid_copy(&list[idx].sid, &global_sid_NULL);
4363 if ( new_dom->domain_flags != 0x0 )
4364 list[idx].trust_flags = new_dom->domain_flags;
4366 if ( new_dom->domain_type != 0x0 )
4367 list[idx].trust_type = new_dom->domain_type;
4369 if ( new_dom->domain_trust_attribs != 0x0 )
4370 list[idx].trust_attribs = new_dom->domain_trust_attribs;
4374 *num_domains = idx + 1;
4380 /*********************************************************************
4381 ********************************************************************/
4383 static TDB_DATA make_tdc_key( const char *domain_name )
4385 char *keystr = NULL;
4386 TDB_DATA key = { NULL, 0 };
4388 if ( !domain_name ) {
4389 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4393 if (asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name ) == -1) {
4396 key = string_term_tdb_data(keystr);
4401 /*********************************************************************
4402 ********************************************************************/
4404 static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
4406 unsigned char **buf )
4408 unsigned char *buffer = NULL;
4413 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4421 /* Store the number of array items first */
4422 len += tdb_pack( buffer+len, buflen-len, "d",
4425 /* now pack each domain trust record */
4426 for ( i=0; i<num_domains; i++ ) {
4431 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4432 domains[i].domain_name,
4433 domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
4436 len += tdb_pack( buffer+len, buflen-len, "fffddd",
4437 domains[i].domain_name,
4438 domains[i].dns_name ? domains[i].dns_name : "",
4439 sid_to_fstring(tmp, &domains[i].sid),
4440 domains[i].trust_flags,
4441 domains[i].trust_attribs,
4442 domains[i].trust_type );
4445 if ( buflen < len ) {
4447 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
4448 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4462 /*********************************************************************
4463 ********************************************************************/
4465 static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
4466 struct winbindd_tdc_domain **domains )
4468 fstring domain_name, dns_name, sid_string;
4469 uint32 type, attribs, flags;
4473 struct winbindd_tdc_domain *list = NULL;
4475 /* get the number of domains */
4476 len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
4478 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4482 list = talloc_array( NULL, struct winbindd_tdc_domain, num_domains );
4484 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4488 for ( i=0; i<num_domains; i++ ) {
4491 this_len = tdb_unpack( buf+len, buflen-len, "fffddd",
4499 if ( this_len == -1 ) {
4500 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4501 TALLOC_FREE( list );
4506 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4507 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4508 domain_name, dns_name, sid_string,
4509 flags, attribs, type));
4511 list[i].domain_name = talloc_strdup( list, domain_name );
4512 list[i].dns_name = NULL;
4513 if (dns_name[0] != '\0') {
4514 list[i].dns_name = talloc_strdup(list, dns_name);
4516 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
4517 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4520 list[i].trust_flags = flags;
4521 list[i].trust_attribs = attribs;
4522 list[i].trust_type = type;
4530 /*********************************************************************
4531 ********************************************************************/
4533 static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
4535 TDB_DATA key = make_tdc_key( lp_workgroup() );
4536 TDB_DATA data = { NULL, 0 };
4542 /* See if we were asked to delete the cache entry */
4545 ret = tdb_delete( wcache->tdb, key );
4549 data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
4556 ret = tdb_store( wcache->tdb, key, data, 0 );
4559 SAFE_FREE( data.dptr );
4560 SAFE_FREE( key.dptr );
4562 return ( ret == 0 );
4565 /*********************************************************************
4566 ********************************************************************/
4568 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
4570 TDB_DATA key = make_tdc_key( lp_workgroup() );
4571 TDB_DATA data = { NULL, 0 };
4579 data = tdb_fetch_compat( wcache->tdb, key );
4581 SAFE_FREE( key.dptr );
4586 *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
4588 SAFE_FREE( data.dptr );
4596 /*********************************************************************
4597 ********************************************************************/
4599 bool wcache_tdc_add_domain( struct winbindd_domain *domain )
4601 struct winbindd_tdc_domain *dom_list = NULL;
4602 size_t num_domains = 0;
4605 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4606 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4607 domain->name, domain->alt_name,
4608 sid_string_dbg(&domain->sid),
4609 domain->domain_flags,
4610 domain->domain_trust_attribs,
4611 domain->domain_type));
4613 if ( !init_wcache() ) {
4617 /* fetch the list */
4619 wcache_tdc_fetch_list( &dom_list, &num_domains );
4621 /* add the new domain */
4623 if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
4627 /* pack the domain */
4629 if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
4637 TALLOC_FREE( dom_list );
4642 static struct winbindd_tdc_domain *wcache_tdc_dup_domain(
4643 TALLOC_CTX *mem_ctx, const struct winbindd_tdc_domain *src)
4645 struct winbindd_tdc_domain *dst;
4647 dst = talloc(mem_ctx, struct winbindd_tdc_domain);
4651 dst->domain_name = talloc_strdup(dst, src->domain_name);
4652 if (dst->domain_name == NULL) {
4656 dst->dns_name = NULL;
4657 if (src->dns_name != NULL) {
4658 dst->dns_name = talloc_strdup(dst, src->dns_name);
4659 if (dst->dns_name == NULL) {
4664 sid_copy(&dst->sid, &src->sid);
4665 dst->trust_flags = src->trust_flags;
4666 dst->trust_type = src->trust_type;
4667 dst->trust_attribs = src->trust_attribs;
4674 /*********************************************************************
4675 ********************************************************************/
4677 struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
4679 struct winbindd_tdc_domain *dom_list = NULL;
4680 size_t num_domains = 0;
4682 struct winbindd_tdc_domain *d = NULL;
4684 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
4686 if ( !init_wcache() ) {
4690 /* fetch the list */
4692 wcache_tdc_fetch_list( &dom_list, &num_domains );
4694 for ( i=0; i<num_domains; i++ ) {
4695 if ( strequal(name, dom_list[i].domain_name) ||
4696 strequal(name, dom_list[i].dns_name) )
4698 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4701 d = wcache_tdc_dup_domain(ctx, &dom_list[i]);
4706 TALLOC_FREE( dom_list );
4711 /*********************************************************************
4712 ********************************************************************/
4714 struct winbindd_tdc_domain*
4715 wcache_tdc_fetch_domainbysid(TALLOC_CTX *ctx,
4716 const struct dom_sid *sid)
4718 struct winbindd_tdc_domain *dom_list = NULL;
4719 size_t num_domains = 0;
4721 struct winbindd_tdc_domain *d = NULL;
4723 DEBUG(10,("wcache_tdc_fetch_domainbysid: Searching for domain %s\n",
4724 sid_string_dbg(sid)));
4726 if (!init_wcache()) {
4730 /* fetch the list */
4732 wcache_tdc_fetch_list(&dom_list, &num_domains);
4734 for (i = 0; i<num_domains; i++) {
4735 if (dom_sid_equal(sid, &(dom_list[i].sid))) {
4736 DEBUG(10, ("wcache_tdc_fetch_domainbysid: "
4737 "Found domain %s for SID %s\n",
4738 dom_list[i].domain_name,
4739 sid_string_dbg(sid)));
4741 d = wcache_tdc_dup_domain(ctx, &dom_list[i]);
4746 TALLOC_FREE(dom_list);
4752 /*********************************************************************
4753 ********************************************************************/
4755 void wcache_tdc_clear( void )
4757 if ( !init_wcache() )
4760 wcache_tdc_store_list( NULL, 0 );
4766 /*********************************************************************
4767 ********************************************************************/
4769 static void wcache_save_user_pwinfo(struct winbindd_domain *domain,
4771 const struct dom_sid *user_sid,
4772 const char *homedir,
4777 struct cache_entry *centry;
4780 if ( (centry = centry_start(domain, status)) == NULL )
4783 centry_put_string( centry, homedir );
4784 centry_put_string( centry, shell );
4785 centry_put_string( centry, gecos );
4786 centry_put_uint32( centry, gid );
4788 centry_end(centry, "NSS/PWINFO/%s", sid_to_fstring(tmp, user_sid) );
4790 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid) ));
4792 centry_free(centry);
4797 NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
4798 const struct dom_sid *user_sid,
4800 const char **homedir, const char **shell,
4801 const char **gecos, gid_t *p_gid)
4803 struct winbind_cache *cache = get_cache(domain);
4804 struct cache_entry *centry = NULL;
4811 centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s",
4812 sid_to_fstring(tmp, user_sid));
4817 *homedir = centry_string( centry, ctx );
4818 *shell = centry_string( centry, ctx );
4819 *gecos = centry_string( centry, ctx );
4820 *p_gid = centry_uint32( centry );
4822 centry_free(centry);
4824 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4825 sid_string_dbg(user_sid)));
4827 return NT_STATUS_OK;
4831 nt_status = nss_get_info( domain->name, user_sid, ctx,
4832 homedir, shell, gecos, p_gid );
4834 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status)));
4836 if ( NT_STATUS_IS_OK(nt_status) ) {
4837 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir));
4838 DEBUGADD(10, ("\tshell = '%s'\n", *shell));
4839 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos));
4840 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid));
4842 wcache_save_user_pwinfo( domain, nt_status, user_sid,
4843 *homedir, *shell, *gecos, *p_gid );
4846 if ( NT_STATUS_EQUAL( nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
4847 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4849 set_domain_offline( domain );
4857 /* the cache backend methods are exposed via this structure */
4858 struct winbindd_methods cache_methods = {
4876 static bool wcache_ndr_key(TALLOC_CTX *mem_ctx, const char *domain_name,
4877 uint32_t opnum, const DATA_BLOB *req,
4883 key = talloc_asprintf(mem_ctx, "NDR/%s/%d/", domain_name, (int)opnum);
4887 keylen = talloc_get_size(key) - 1;
4889 key = talloc_realloc(mem_ctx, key, char, keylen + req->length);
4893 memcpy(key + keylen, req->data, req->length);
4895 pkey->dptr = (uint8_t *)key;
4896 pkey->dsize = talloc_get_size(key);
4900 static bool wcache_opnum_cacheable(uint32_t opnum)
4903 case NDR_WBINT_PING:
4904 case NDR_WBINT_QUERYSEQUENCENUMBER:
4905 case NDR_WBINT_ALLOCATEUID:
4906 case NDR_WBINT_ALLOCATEGID:
4907 case NDR_WBINT_CHECKMACHINEACCOUNT:
4908 case NDR_WBINT_CHANGEMACHINEACCOUNT:
4909 case NDR_WBINT_PINGDC:
4915 bool wcache_fetch_ndr(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
4916 uint32_t opnum, const DATA_BLOB *req, DATA_BLOB *resp)
4921 if (!wcache_opnum_cacheable(opnum) ||
4922 is_my_own_sam_domain(domain) ||
4923 is_builtin_domain(domain)) {
4927 if (wcache->tdb == NULL) {
4931 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4934 data = tdb_fetch_compat(wcache->tdb, key);
4935 TALLOC_FREE(key.dptr);
4937 if (data.dptr == NULL) {
4940 if (data.dsize < 12) {
4944 if (!is_domain_offline(domain)) {
4945 uint32_t entry_seqnum, dom_seqnum, last_check;
4946 uint64_t entry_timeout;
4948 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum,
4952 entry_seqnum = IVAL(data.dptr, 0);
4953 if (entry_seqnum != dom_seqnum) {
4954 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4955 (int)entry_seqnum));
4958 entry_timeout = BVAL(data.dptr, 4);
4959 if (time(NULL) > entry_timeout) {
4960 DEBUG(10, ("Entry has timed out\n"));
4965 resp->data = (uint8_t *)talloc_memdup(mem_ctx, data.dptr + 12,
4967 if (resp->data == NULL) {
4968 DEBUG(10, ("talloc failed\n"));
4971 resp->length = data.dsize - 12;
4975 SAFE_FREE(data.dptr);
4979 void wcache_store_ndr(struct winbindd_domain *domain, uint32_t opnum,
4980 const DATA_BLOB *req, const DATA_BLOB *resp)
4983 uint32_t dom_seqnum, last_check;
4986 if (!wcache_opnum_cacheable(opnum) ||
4987 is_my_own_sam_domain(domain) ||
4988 is_builtin_domain(domain)) {
4992 if (wcache->tdb == NULL) {
4996 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum, &last_check)) {
4997 DEBUG(10, ("could not fetch seqnum for domain %s\n",
5002 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
5006 timeout = time(NULL) + lp_winbind_cache_time();
5008 data.dsize = resp->length + 12;
5009 data.dptr = talloc_array(key.dptr, uint8_t, data.dsize);
5010 if (data.dptr == NULL) {
5014 SIVAL(data.dptr, 0, dom_seqnum);
5015 SBVAL(data.dptr, 4, timeout);
5016 memcpy(data.dptr + 12, resp->data, resp->length);
5018 tdb_store(wcache->tdb, key, data, 0);
5021 TALLOC_FREE(key.dptr);