2 Unix SMB/CIFS implementation.
4 Winbind cache backend functions
6 Copyright (C) Andrew Tridgell 2001
7 Copyright (C) Gerald Carter 2003-2007
8 Copyright (C) Volker Lendecke 2005
9 Copyright (C) Guenther Deschner 2005
10 Copyright (C) Michael Adam 2007
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 #include "tdb_validate.h"
29 #include "../libcli/auth/libcli_auth.h"
30 #include "../librpc/gen_ndr/ndr_wbint.h"
34 #define DBGC_CLASS DBGC_WINBIND
36 #define WINBINDD_CACHE_VERSION 1
37 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
39 extern struct winbindd_methods reconnect_methods;
41 extern struct winbindd_methods ads_methods;
43 extern struct winbindd_methods builtin_passdb_methods;
46 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
47 * Here are the list of entry types that are *not* stored
48 * as form struct cache_entry in the cache.
51 static const char *non_centry_keys[] = {
56 WINBINDD_CACHE_VERSION_KEYSTR,
60 /************************************************************************
61 Is this key a non-centry type ?
62 ************************************************************************/
64 static bool is_non_centry_key(TDB_DATA kbuf)
68 if (kbuf.dptr == NULL || kbuf.dsize == 0) {
71 for (i = 0; non_centry_keys[i] != NULL; i++) {
72 size_t namelen = strlen(non_centry_keys[i]);
73 if (kbuf.dsize < namelen) {
76 if (strncmp(non_centry_keys[i], (const char *)kbuf.dptr, namelen) == 0) {
83 /* Global online/offline state - False when online. winbindd starts up online
84 and sets this to true if the first query fails and there's an entry in
85 the cache tdb telling us to stay offline. */
87 static bool global_winbindd_offline_state;
89 struct winbind_cache {
95 uint32 sequence_number;
100 void (*smb_panic_fn)(const char *const why) = smb_panic;
102 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
104 static struct winbind_cache *wcache;
106 void winbindd_check_cache_size(time_t t)
108 static time_t last_check_time;
111 if (last_check_time == (time_t)0)
114 if (t - last_check_time < 60 && t - last_check_time > 0)
117 if (wcache == NULL || wcache->tdb == NULL) {
118 DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
122 if (fstat(tdb_fd(wcache->tdb), &st) == -1) {
123 DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno) ));
127 if (st.st_size > WINBINDD_MAX_CACHE_SIZE) {
128 DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
129 (unsigned long)st.st_size,
130 (unsigned long)WINBINDD_MAX_CACHE_SIZE));
131 wcache_flush_cache();
135 /* get the winbind_cache structure */
136 static struct winbind_cache *get_cache(struct winbindd_domain *domain)
138 struct winbind_cache *ret = wcache;
140 /* We have to know what type of domain we are dealing with first. */
142 if (domain->internal) {
143 domain->backend = &builtin_passdb_methods;
144 domain->initialized = True;
146 if ( !domain->initialized ) {
147 init_dc_connection( domain );
151 OK. listen up becasue I'm only going to say this once.
152 We have the following scenarios to consider
153 (a) trusted AD domains on a Samba DC,
154 (b) trusted AD domains and we are joined to a non-kerberos domain
155 (c) trusted AD domains and we are joined to a kerberos (AD) domain
157 For (a) we can always contact the trusted domain using krb5
158 since we have the domain trust account password
160 For (b) we can only use RPC since we have no way of
161 getting a krb5 ticket in our own domain
163 For (c) we can always use krb5 since we have a kerberos trust
168 if (!domain->backend) {
170 struct winbindd_domain *our_domain = domain;
172 /* find our domain first so we can figure out if we
173 are joined to a kerberized domain */
175 if ( !domain->primary )
176 our_domain = find_our_domain();
178 if ((our_domain->active_directory || IS_DC)
179 && domain->active_directory
180 && !lp_winbind_rpc_only()) {
181 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain->name));
182 domain->backend = &ads_methods;
184 #endif /* HAVE_ADS */
185 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain->name));
186 domain->backend = &reconnect_methods;
189 #endif /* HAVE_ADS */
195 ret = SMB_XMALLOC_P(struct winbind_cache);
199 wcache_flush_cache();
205 free a centry structure
207 static void centry_free(struct cache_entry *centry)
211 SAFE_FREE(centry->data);
215 static bool centry_check_bytes(struct cache_entry *centry, size_t nbytes)
217 if (centry->len - centry->ofs < nbytes) {
218 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
219 (unsigned int)nbytes,
220 centry->len - centry->ofs));
227 pull a uint32 from a cache entry
229 static uint32 centry_uint32(struct cache_entry *centry)
233 if (!centry_check_bytes(centry, 4)) {
234 smb_panic_fn("centry_uint32");
236 ret = IVAL(centry->data, centry->ofs);
242 pull a uint16 from a cache entry
244 static uint16 centry_uint16(struct cache_entry *centry)
247 if (!centry_check_bytes(centry, 2)) {
248 smb_panic_fn("centry_uint16");
250 ret = CVAL(centry->data, centry->ofs);
256 pull a uint8 from a cache entry
258 static uint8 centry_uint8(struct cache_entry *centry)
261 if (!centry_check_bytes(centry, 1)) {
262 smb_panic_fn("centry_uint8");
264 ret = CVAL(centry->data, centry->ofs);
270 pull a NTTIME from a cache entry
272 static NTTIME centry_nttime(struct cache_entry *centry)
275 if (!centry_check_bytes(centry, 8)) {
276 smb_panic_fn("centry_nttime");
278 ret = IVAL(centry->data, centry->ofs);
280 ret += (uint64_t)IVAL(centry->data, centry->ofs) << 32;
286 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
288 static time_t centry_time(struct cache_entry *centry)
290 return (time_t)centry_nttime(centry);
293 /* pull a string from a cache entry, using the supplied
296 static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
301 len = centry_uint8(centry);
304 /* a deliberate NULL string */
308 if (!centry_check_bytes(centry, (size_t)len)) {
309 smb_panic_fn("centry_string");
312 ret = TALLOC_ARRAY(mem_ctx, char, len+1);
314 smb_panic_fn("centry_string out of memory\n");
316 memcpy(ret,centry->data + centry->ofs, len);
322 /* pull a hash16 from a cache entry, using the supplied
325 static char *centry_hash16(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
330 len = centry_uint8(centry);
333 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
338 if (!centry_check_bytes(centry, 16)) {
342 ret = TALLOC_ARRAY(mem_ctx, char, 16);
344 smb_panic_fn("centry_hash out of memory\n");
346 memcpy(ret,centry->data + centry->ofs, 16);
351 /* pull a sid from a cache entry, using the supplied
354 static bool centry_sid(struct cache_entry *centry, struct dom_sid *sid)
359 sid_string = centry_string(centry, talloc_tos());
360 if (sid_string == NULL) {
363 ret = string_to_sid(sid, sid_string);
364 TALLOC_FREE(sid_string);
370 pull a NTSTATUS from a cache entry
372 static NTSTATUS centry_ntstatus(struct cache_entry *centry)
376 status = NT_STATUS(centry_uint32(centry));
381 /* the server is considered down if it can't give us a sequence number */
382 static bool wcache_server_down(struct winbindd_domain *domain)
389 ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
392 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
397 static bool wcache_fetch_seqnum(const char *domain_name, uint32_t *seqnum,
398 uint32_t *last_seq_check)
403 if (wcache->tdb == NULL) {
404 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
408 key = talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name);
410 DEBUG(10, ("talloc failed\n"));
414 data = tdb_fetch_bystring(wcache->tdb, key);
417 if (data.dptr == NULL) {
418 DEBUG(10, ("wcache_fetch_seqnum: %s not found\n",
422 if (data.dsize != 8) {
423 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
425 SAFE_FREE(data.dptr);
429 *seqnum = IVAL(data.dptr, 0);
430 *last_seq_check = IVAL(data.dptr, 4);
431 SAFE_FREE(data.dptr);
436 static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
438 uint32 last_check, time_diff;
440 if (!wcache_fetch_seqnum(domain->name, &domain->sequence_number,
442 return NT_STATUS_UNSUCCESSFUL;
444 domain->last_seq_check = last_check;
446 /* have we expired? */
448 time_diff = now - domain->last_seq_check;
449 if ( time_diff > lp_winbind_cache_time() ) {
450 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
451 domain->name, domain->sequence_number,
452 (uint32)domain->last_seq_check));
453 return NT_STATUS_UNSUCCESSFUL;
456 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
457 domain->name, domain->sequence_number,
458 (uint32)domain->last_seq_check));
463 bool wcache_store_seqnum(const char *domain_name, uint32_t seqnum,
464 time_t last_seq_check)
470 if (wcache->tdb == NULL) {
471 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
475 key_str = talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name);
476 if (key_str == NULL) {
477 DEBUG(10, ("talloc_asprintf failed\n"));
481 SIVAL(buf, 0, seqnum);
482 SIVAL(buf, 4, last_seq_check);
484 ret = tdb_store_bystring(wcache->tdb, key_str,
485 make_tdb_data(buf, sizeof(buf)), TDB_REPLACE);
486 TALLOC_FREE(key_str);
488 DEBUG(10, ("tdb_store_bystring failed: %s\n",
489 tdb_errorstr(wcache->tdb)));
490 TALLOC_FREE(key_str);
494 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
495 domain_name, seqnum, (unsigned)last_seq_check));
500 static bool store_cache_seqnum( struct winbindd_domain *domain )
502 return wcache_store_seqnum(domain->name, domain->sequence_number,
503 domain->last_seq_check);
507 refresh the domain sequence number. If force is true
508 then always refresh it, no matter how recently we fetched it
511 static void refresh_sequence_number(struct winbindd_domain *domain, bool force)
515 time_t t = time(NULL);
516 unsigned cache_time = lp_winbind_cache_time();
518 if (is_domain_offline(domain)) {
524 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
525 /* trying to reconnect is expensive, don't do it too often */
526 if (domain->sequence_number == DOM_SEQUENCE_NONE) {
531 time_diff = t - domain->last_seq_check;
533 /* see if we have to refetch the domain sequence number */
534 if (!force && (time_diff < cache_time) &&
535 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
536 NT_STATUS_IS_OK(domain->last_status)) {
537 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
541 /* try to get the sequence number from the tdb cache first */
542 /* this will update the timestamp as well */
544 status = fetch_cache_seqnum( domain, t );
545 if (NT_STATUS_IS_OK(status) &&
546 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
547 NT_STATUS_IS_OK(domain->last_status)) {
551 /* important! make sure that we know if this is a native
552 mode domain or not. And that we can contact it. */
554 if ( winbindd_can_contact_domain( domain ) ) {
555 status = domain->backend->sequence_number(domain,
556 &domain->sequence_number);
558 /* just use the current time */
559 status = NT_STATUS_OK;
560 domain->sequence_number = time(NULL);
564 /* the above call could have set our domain->backend to NULL when
565 * coming from offline to online mode, make sure to reinitialize the
566 * backend - Guenther */
569 if (!NT_STATUS_IS_OK(status)) {
570 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status)));
571 domain->sequence_number = DOM_SEQUENCE_NONE;
574 domain->last_status = status;
575 domain->last_seq_check = time(NULL);
577 /* save the new sequence number in the cache */
578 store_cache_seqnum( domain );
581 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
582 domain->name, domain->sequence_number));
588 decide if a cache entry has expired
590 static bool centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
592 /* If we've been told to be offline - stay in that state... */
593 if (lp_winbind_offline_logon() && global_winbindd_offline_state) {
594 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
595 keystr, domain->name ));
599 /* when the domain is offline return the cached entry.
600 * This deals with transient offline states... */
602 if (!domain->online) {
603 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
604 keystr, domain->name ));
608 /* if the server is OK and our cache entry came from when it was down then
609 the entry is invalid */
610 if ((domain->sequence_number != DOM_SEQUENCE_NONE) &&
611 (centry->sequence_number == DOM_SEQUENCE_NONE)) {
612 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
613 keystr, domain->name ));
617 /* if the server is down or the cache entry is not older than the
618 current sequence number then it is OK */
619 if (wcache_server_down(domain) ||
620 centry->sequence_number == domain->sequence_number) {
621 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
622 keystr, domain->name ));
626 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
627 keystr, domain->name ));
633 static struct cache_entry *wcache_fetch_raw(char *kstr)
636 struct cache_entry *centry;
639 key = string_tdb_data(kstr);
640 data = tdb_fetch(wcache->tdb, key);
646 centry = SMB_XMALLOC_P(struct cache_entry);
647 centry->data = (unsigned char *)data.dptr;
648 centry->len = data.dsize;
651 if (centry->len < 8) {
652 /* huh? corrupt cache? */
653 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr));
658 centry->status = centry_ntstatus(centry);
659 centry->sequence_number = centry_uint32(centry);
665 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
666 number and return status
668 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
669 struct winbindd_domain *domain,
670 const char *format, ...) PRINTF_ATTRIBUTE(3,4);
671 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
672 struct winbindd_domain *domain,
673 const char *format, ...)
677 struct cache_entry *centry;
679 if (!winbindd_use_cache()) {
683 refresh_sequence_number(domain, false);
685 va_start(ap, format);
686 smb_xvasprintf(&kstr, format, ap);
689 centry = wcache_fetch_raw(kstr);
690 if (centry == NULL) {
695 if (centry_expired(domain, kstr, centry)) {
697 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
698 kstr, domain->name ));
705 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
706 kstr, domain->name ));
712 static void wcache_delete(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
713 static void wcache_delete(const char *format, ...)
719 va_start(ap, format);
720 smb_xvasprintf(&kstr, format, ap);
723 key = string_tdb_data(kstr);
725 tdb_delete(wcache->tdb, key);
730 make sure we have at least len bytes available in a centry
732 static void centry_expand(struct cache_entry *centry, uint32 len)
734 if (centry->len - centry->ofs >= len)
737 centry->data = SMB_REALLOC_ARRAY(centry->data, unsigned char,
740 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
741 smb_panic_fn("out of memory in centry_expand");
746 push a uint32 into a centry
748 static void centry_put_uint32(struct cache_entry *centry, uint32 v)
750 centry_expand(centry, 4);
751 SIVAL(centry->data, centry->ofs, v);
756 push a uint16 into a centry
758 static void centry_put_uint16(struct cache_entry *centry, uint16 v)
760 centry_expand(centry, 2);
761 SIVAL(centry->data, centry->ofs, v);
766 push a uint8 into a centry
768 static void centry_put_uint8(struct cache_entry *centry, uint8 v)
770 centry_expand(centry, 1);
771 SCVAL(centry->data, centry->ofs, v);
776 push a string into a centry
778 static void centry_put_string(struct cache_entry *centry, const char *s)
783 /* null strings are marked as len 0xFFFF */
784 centry_put_uint8(centry, 0xFF);
789 /* can't handle more than 254 char strings. Truncating is probably best */
791 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len));
794 centry_put_uint8(centry, len);
795 centry_expand(centry, len);
796 memcpy(centry->data + centry->ofs, s, len);
801 push a 16 byte hash into a centry - treat as 16 byte string.
803 static void centry_put_hash16(struct cache_entry *centry, const uint8 val[16])
805 centry_put_uint8(centry, 16);
806 centry_expand(centry, 16);
807 memcpy(centry->data + centry->ofs, val, 16);
811 static void centry_put_sid(struct cache_entry *centry, const struct dom_sid *sid)
814 centry_put_string(centry, sid_to_fstring(sid_string, sid));
819 put NTSTATUS into a centry
821 static void centry_put_ntstatus(struct cache_entry *centry, NTSTATUS status)
823 uint32 status_value = NT_STATUS_V(status);
824 centry_put_uint32(centry, status_value);
829 push a NTTIME into a centry
831 static void centry_put_nttime(struct cache_entry *centry, NTTIME nt)
833 centry_expand(centry, 8);
834 SIVAL(centry->data, centry->ofs, nt & 0xFFFFFFFF);
836 SIVAL(centry->data, centry->ofs, nt >> 32);
841 push a time_t into a centry - use a 64 bit size.
842 NTTIME here is being used as a convenient 64-bit size.
844 static void centry_put_time(struct cache_entry *centry, time_t t)
846 NTTIME nt = (NTTIME)t;
847 centry_put_nttime(centry, nt);
851 start a centry for output. When finished, call centry_end()
853 struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status)
855 struct cache_entry *centry;
860 centry = SMB_XMALLOC_P(struct cache_entry);
862 centry->len = 8192; /* reasonable default */
863 centry->data = SMB_XMALLOC_ARRAY(uint8, centry->len);
865 centry->sequence_number = domain->sequence_number;
866 centry_put_ntstatus(centry, status);
867 centry_put_uint32(centry, centry->sequence_number);
872 finish a centry and write it to the tdb
874 static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
875 static void centry_end(struct cache_entry *centry, const char *format, ...)
881 if (!winbindd_use_cache()) {
885 va_start(ap, format);
886 smb_xvasprintf(&kstr, format, ap);
889 key = string_tdb_data(kstr);
890 data.dptr = centry->data;
891 data.dsize = centry->ofs;
893 tdb_store(wcache->tdb, key, data, TDB_REPLACE);
897 static void wcache_save_name_to_sid(struct winbindd_domain *domain,
898 NTSTATUS status, const char *domain_name,
899 const char *name, const struct dom_sid *sid,
900 enum lsa_SidType type)
902 struct cache_entry *centry;
905 centry = centry_start(domain, status);
908 centry_put_uint32(centry, type);
909 centry_put_sid(centry, sid);
910 fstrcpy(uname, name);
912 centry_end(centry, "NS/%s/%s", domain_name, uname);
913 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name,
914 uname, sid_string_dbg(sid), nt_errstr(status)));
918 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
919 const struct dom_sid *sid, const char *domain_name, const char *name, enum lsa_SidType type)
921 struct cache_entry *centry;
924 centry = centry_start(domain, status);
928 if (NT_STATUS_IS_OK(status)) {
929 centry_put_uint32(centry, type);
930 centry_put_string(centry, domain_name);
931 centry_put_string(centry, name);
934 centry_end(centry, "SN/%s", sid_to_fstring(sid_string, sid));
935 DEBUG(10,("wcache_save_sid_to_name: %s -> %s (%s)\n", sid_string,
936 name, nt_errstr(status)));
941 static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status,
942 struct wbint_userinfo *info)
944 struct cache_entry *centry;
947 if (is_null_sid(&info->user_sid)) {
951 centry = centry_start(domain, status);
954 centry_put_string(centry, info->acct_name);
955 centry_put_string(centry, info->full_name);
956 centry_put_string(centry, info->homedir);
957 centry_put_string(centry, info->shell);
958 centry_put_uint32(centry, info->primary_gid);
959 centry_put_sid(centry, &info->user_sid);
960 centry_put_sid(centry, &info->group_sid);
961 centry_end(centry, "U/%s", sid_to_fstring(sid_string,
963 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
967 static void wcache_save_lockout_policy(struct winbindd_domain *domain,
969 struct samr_DomInfo12 *lockout_policy)
971 struct cache_entry *centry;
973 centry = centry_start(domain, status);
977 centry_put_nttime(centry, lockout_policy->lockout_duration);
978 centry_put_nttime(centry, lockout_policy->lockout_window);
979 centry_put_uint16(centry, lockout_policy->lockout_threshold);
981 centry_end(centry, "LOC_POL/%s", domain->name);
983 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
990 static void wcache_save_password_policy(struct winbindd_domain *domain,
992 struct samr_DomInfo1 *policy)
994 struct cache_entry *centry;
996 centry = centry_start(domain, status);
1000 centry_put_uint16(centry, policy->min_password_length);
1001 centry_put_uint16(centry, policy->password_history_length);
1002 centry_put_uint32(centry, policy->password_properties);
1003 centry_put_nttime(centry, policy->max_password_age);
1004 centry_put_nttime(centry, policy->min_password_age);
1006 centry_end(centry, "PWD_POL/%s", domain->name);
1008 DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
1010 centry_free(centry);
1013 /***************************************************************************
1014 ***************************************************************************/
1016 static void wcache_save_username_alias(struct winbindd_domain *domain,
1018 const char *name, const char *alias)
1020 struct cache_entry *centry;
1023 if ( (centry = centry_start(domain, status)) == NULL )
1026 centry_put_string( centry, alias );
1028 fstrcpy(uname, name);
1030 centry_end(centry, "NSS/NA/%s", uname);
1032 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name, alias ));
1034 centry_free(centry);
1037 static void wcache_save_alias_username(struct winbindd_domain *domain,
1039 const char *alias, const char *name)
1041 struct cache_entry *centry;
1044 if ( (centry = centry_start(domain, status)) == NULL )
1047 centry_put_string( centry, name );
1049 fstrcpy(uname, alias);
1051 centry_end(centry, "NSS/AN/%s", uname);
1053 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias, name ));
1055 centry_free(centry);
1058 /***************************************************************************
1059 ***************************************************************************/
1061 NTSTATUS resolve_username_to_alias( TALLOC_CTX *mem_ctx,
1062 struct winbindd_domain *domain,
1063 const char *name, char **alias )
1065 struct winbind_cache *cache = get_cache(domain);
1066 struct cache_entry *centry = NULL;
1070 if ( domain->internal )
1071 return NT_STATUS_NOT_SUPPORTED;
1076 if ( (upper_name = SMB_STRDUP(name)) == NULL )
1077 return NT_STATUS_NO_MEMORY;
1078 strupper_m(upper_name);
1080 centry = wcache_fetch(cache, domain, "NSS/NA/%s", upper_name);
1082 SAFE_FREE( upper_name );
1087 status = centry->status;
1089 if (!NT_STATUS_IS_OK(status)) {
1090 centry_free(centry);
1094 *alias = centry_string( centry, mem_ctx );
1096 centry_free(centry);
1098 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1099 name, *alias ? *alias : "(none)"));
1101 return (*alias) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1105 /* If its not in cache and we are offline, then fail */
1107 if ( get_global_winbindd_state_offline() || !domain->online ) {
1108 DEBUG(8,("resolve_username_to_alias: rejecting query "
1109 "in offline mode\n"));
1110 return NT_STATUS_NOT_FOUND;
1113 status = nss_map_to_alias( mem_ctx, domain->name, name, alias );
1115 if ( NT_STATUS_IS_OK( status ) ) {
1116 wcache_save_username_alias(domain, status, name, *alias);
1119 if ( NT_STATUS_EQUAL( status, NT_STATUS_NONE_MAPPED ) ) {
1120 wcache_save_username_alias(domain, status, name, "(NULL)");
1123 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1124 nt_errstr(status)));
1126 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1127 set_domain_offline( domain );
1133 /***************************************************************************
1134 ***************************************************************************/
1136 NTSTATUS resolve_alias_to_username( TALLOC_CTX *mem_ctx,
1137 struct winbindd_domain *domain,
1138 const char *alias, char **name )
1140 struct winbind_cache *cache = get_cache(domain);
1141 struct cache_entry *centry = NULL;
1145 if ( domain->internal )
1146 return NT_STATUS_NOT_SUPPORTED;
1151 if ( (upper_name = SMB_STRDUP(alias)) == NULL )
1152 return NT_STATUS_NO_MEMORY;
1153 strupper_m(upper_name);
1155 centry = wcache_fetch(cache, domain, "NSS/AN/%s", upper_name);
1157 SAFE_FREE( upper_name );
1162 status = centry->status;
1164 if (!NT_STATUS_IS_OK(status)) {
1165 centry_free(centry);
1169 *name = centry_string( centry, mem_ctx );
1171 centry_free(centry);
1173 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1174 alias, *name ? *name : "(none)"));
1176 return (*name) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1180 /* If its not in cache and we are offline, then fail */
1182 if ( get_global_winbindd_state_offline() || !domain->online ) {
1183 DEBUG(8,("resolve_alias_to_username: rejecting query "
1184 "in offline mode\n"));
1185 return NT_STATUS_NOT_FOUND;
1188 /* an alias cannot contain a domain prefix or '@' */
1190 if (strchr(alias, '\\') || strchr(alias, '@')) {
1191 DEBUG(10,("resolve_alias_to_username: skipping fully "
1192 "qualified name %s\n", alias));
1193 return NT_STATUS_OBJECT_NAME_INVALID;
1196 status = nss_map_from_alias( mem_ctx, domain->name, alias, name );
1198 if ( NT_STATUS_IS_OK( status ) ) {
1199 wcache_save_alias_username( domain, status, alias, *name );
1202 if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1203 wcache_save_alias_username(domain, status, alias, "(NULL)");
1206 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1207 nt_errstr(status)));
1209 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1210 set_domain_offline( domain );
1216 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const struct dom_sid *sid)
1218 struct winbind_cache *cache = get_cache(domain);
1220 fstring key_str, tmp;
1224 return NT_STATUS_INTERNAL_DB_ERROR;
1227 if (is_null_sid(sid)) {
1228 return NT_STATUS_INVALID_SID;
1231 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1232 return NT_STATUS_INVALID_SID;
1235 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
1237 data = tdb_fetch(cache->tdb, string_tdb_data(key_str));
1239 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1242 SAFE_FREE(data.dptr);
1243 return NT_STATUS_OK;
1246 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1247 as new salted ones. */
1249 NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
1250 TALLOC_CTX *mem_ctx,
1251 const struct dom_sid *sid,
1252 const uint8 **cached_nt_pass,
1253 const uint8 **cached_salt)
1255 struct winbind_cache *cache = get_cache(domain);
1256 struct cache_entry *centry = NULL;
1263 return NT_STATUS_INTERNAL_DB_ERROR;
1266 if (is_null_sid(sid)) {
1267 return NT_STATUS_INVALID_SID;
1270 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1271 return NT_STATUS_INVALID_SID;
1274 /* Try and get a salted cred first. If we can't
1275 fall back to an unsalted cred. */
1277 centry = wcache_fetch(cache, domain, "CRED/%s",
1278 sid_to_fstring(tmp, sid));
1280 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1281 sid_string_dbg(sid)));
1282 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1285 t = centry_time(centry);
1287 /* In the salted case this isn't actually the nt_hash itself,
1288 but the MD5 of the salt + nt_hash. Let the caller
1289 sort this out. It can tell as we only return the cached_salt
1290 if we are returning a salted cred. */
1292 *cached_nt_pass = (const uint8 *)centry_hash16(centry, mem_ctx);
1293 if (*cached_nt_pass == NULL) {
1296 sid_to_fstring(sidstr, sid);
1298 /* Bad (old) cred cache. Delete and pretend we
1300 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1302 wcache_delete("CRED/%s", sidstr);
1303 centry_free(centry);
1304 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1307 /* We only have 17 bytes more data in the salted cred case. */
1308 if (centry->len - centry->ofs == 17) {
1309 *cached_salt = (const uint8 *)centry_hash16(centry, mem_ctx);
1311 *cached_salt = NULL;
1314 dump_data_pw("cached_nt_pass", *cached_nt_pass, NT_HASH_LEN);
1316 dump_data_pw("cached_salt", *cached_salt, NT_HASH_LEN);
1319 status = centry->status;
1321 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1322 sid_string_dbg(sid), nt_errstr(status) ));
1324 centry_free(centry);
1328 /* Store creds for a SID - only writes out new salted ones. */
1330 NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
1331 TALLOC_CTX *mem_ctx,
1332 const struct dom_sid *sid,
1333 const uint8 nt_pass[NT_HASH_LEN])
1335 struct cache_entry *centry;
1338 uint8 cred_salt[NT_HASH_LEN];
1339 uint8 salted_hash[NT_HASH_LEN];
1341 if (is_null_sid(sid)) {
1342 return NT_STATUS_INVALID_SID;
1345 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1346 return NT_STATUS_INVALID_SID;
1349 centry = centry_start(domain, NT_STATUS_OK);
1351 return NT_STATUS_INTERNAL_DB_ERROR;
1354 dump_data_pw("nt_pass", nt_pass, NT_HASH_LEN);
1356 centry_put_time(centry, time(NULL));
1358 /* Create a salt and then salt the hash. */
1359 generate_random_buffer(cred_salt, NT_HASH_LEN);
1360 E_md5hash(cred_salt, nt_pass, salted_hash);
1362 centry_put_hash16(centry, salted_hash);
1363 centry_put_hash16(centry, cred_salt);
1364 centry_end(centry, "CRED/%s", sid_to_fstring(sid_string, sid));
1366 DEBUG(10,("wcache_save_creds: %s\n", sid_string));
1368 centry_free(centry);
1370 return NT_STATUS_OK;
1374 /* Query display info. This is the basic user list fn */
1375 static NTSTATUS query_user_list(struct winbindd_domain *domain,
1376 TALLOC_CTX *mem_ctx,
1377 uint32 *num_entries,
1378 struct wbint_userinfo **info)
1380 struct winbind_cache *cache = get_cache(domain);
1381 struct cache_entry *centry = NULL;
1383 unsigned int i, retry;
1384 bool old_status = domain->online;
1389 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1394 *num_entries = centry_uint32(centry);
1396 if (*num_entries == 0)
1399 (*info) = TALLOC_ARRAY(mem_ctx, struct wbint_userinfo, *num_entries);
1401 smb_panic_fn("query_user_list out of memory");
1403 for (i=0; i<(*num_entries); i++) {
1404 (*info)[i].acct_name = centry_string(centry, mem_ctx);
1405 (*info)[i].full_name = centry_string(centry, mem_ctx);
1406 (*info)[i].homedir = centry_string(centry, mem_ctx);
1407 (*info)[i].shell = centry_string(centry, mem_ctx);
1408 centry_sid(centry, &(*info)[i].user_sid);
1409 centry_sid(centry, &(*info)[i].group_sid);
1413 status = centry->status;
1415 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1416 domain->name, nt_errstr(status) ));
1418 centry_free(centry);
1425 /* Return status value returned by seq number check */
1427 if (!NT_STATUS_IS_OK(domain->last_status))
1428 return domain->last_status;
1430 /* Put the query_user_list() in a retry loop. There appears to be
1431 * some bug either with Windows 2000 or Samba's handling of large
1432 * rpc replies. This manifests itself as sudden disconnection
1433 * at a random point in the enumeration of a large (60k) user list.
1434 * The retry loop simply tries the operation again. )-: It's not
1435 * pretty but an acceptable workaround until we work out what the
1436 * real problem is. */
1441 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1444 status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
1445 if (!NT_STATUS_IS_OK(status)) {
1446 DEBUG(3, ("query_user_list: returned 0x%08x, "
1447 "retrying\n", NT_STATUS_V(status)));
1449 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1450 DEBUG(3, ("query_user_list: flushing "
1451 "connection cache\n"));
1452 invalidate_cm_connection(&domain->conn);
1454 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1455 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1456 if (!domain->internal && old_status) {
1457 set_domain_offline(domain);
1459 /* store partial response. */
1460 if (*num_entries > 0) {
1462 * humm, what about the status used for cache?
1463 * Should it be NT_STATUS_OK?
1468 * domain is offline now, and there is no user entries,
1469 * try to fetch from cache again.
1471 if (cache->tdb && !domain->online && !domain->internal && old_status) {
1472 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1473 /* partial response... */
1477 goto do_fetch_cache;
1484 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
1488 refresh_sequence_number(domain, false);
1489 if (!NT_STATUS_IS_OK(status)) {
1492 centry = centry_start(domain, status);
1495 centry_put_uint32(centry, *num_entries);
1496 for (i=0; i<(*num_entries); i++) {
1497 centry_put_string(centry, (*info)[i].acct_name);
1498 centry_put_string(centry, (*info)[i].full_name);
1499 centry_put_string(centry, (*info)[i].homedir);
1500 centry_put_string(centry, (*info)[i].shell);
1501 centry_put_sid(centry, &(*info)[i].user_sid);
1502 centry_put_sid(centry, &(*info)[i].group_sid);
1503 if (domain->backend && domain->backend->consistent) {
1504 /* when the backend is consistent we can pre-prime some mappings */
1505 wcache_save_name_to_sid(domain, NT_STATUS_OK,
1507 (*info)[i].acct_name,
1508 &(*info)[i].user_sid,
1510 wcache_save_sid_to_name(domain, NT_STATUS_OK,
1511 &(*info)[i].user_sid,
1513 (*info)[i].acct_name,
1515 wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
1518 centry_end(centry, "UL/%s", domain->name);
1519 centry_free(centry);
1525 /* list all domain groups */
1526 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
1527 TALLOC_CTX *mem_ctx,
1528 uint32 *num_entries,
1529 struct acct_info **info)
1531 struct winbind_cache *cache = get_cache(domain);
1532 struct cache_entry *centry = NULL;
1537 old_status = domain->online;
1541 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1546 *num_entries = centry_uint32(centry);
1548 if (*num_entries == 0)
1551 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1553 smb_panic_fn("enum_dom_groups out of memory");
1555 for (i=0; i<(*num_entries); i++) {
1556 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1557 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1558 (*info)[i].rid = centry_uint32(centry);
1562 status = centry->status;
1564 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1565 domain->name, nt_errstr(status) ));
1567 centry_free(centry);
1574 /* Return status value returned by seq number check */
1576 if (!NT_STATUS_IS_OK(domain->last_status))
1577 return domain->last_status;
1579 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1582 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1584 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1585 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1586 if (!domain->internal && old_status) {
1587 set_domain_offline(domain);
1591 !domain->internal &&
1593 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1595 goto do_fetch_cache;
1600 refresh_sequence_number(domain, false);
1601 if (!NT_STATUS_IS_OK(status)) {
1604 centry = centry_start(domain, status);
1607 centry_put_uint32(centry, *num_entries);
1608 for (i=0; i<(*num_entries); i++) {
1609 centry_put_string(centry, (*info)[i].acct_name);
1610 centry_put_string(centry, (*info)[i].acct_desc);
1611 centry_put_uint32(centry, (*info)[i].rid);
1613 centry_end(centry, "GL/%s/domain", domain->name);
1614 centry_free(centry);
1620 /* list all domain groups */
1621 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
1622 TALLOC_CTX *mem_ctx,
1623 uint32 *num_entries,
1624 struct acct_info **info)
1626 struct winbind_cache *cache = get_cache(domain);
1627 struct cache_entry *centry = NULL;
1632 old_status = domain->online;
1636 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1641 *num_entries = centry_uint32(centry);
1643 if (*num_entries == 0)
1646 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1648 smb_panic_fn("enum_dom_groups out of memory");
1650 for (i=0; i<(*num_entries); i++) {
1651 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1652 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1653 (*info)[i].rid = centry_uint32(centry);
1658 /* If we are returning cached data and the domain controller
1659 is down then we don't know whether the data is up to date
1660 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1663 if (wcache_server_down(domain)) {
1664 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1665 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1667 status = centry->status;
1669 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1670 domain->name, nt_errstr(status) ));
1672 centry_free(centry);
1679 /* Return status value returned by seq number check */
1681 if (!NT_STATUS_IS_OK(domain->last_status))
1682 return domain->last_status;
1684 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1687 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1689 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1690 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1691 if (!domain->internal && old_status) {
1692 set_domain_offline(domain);
1695 !domain->internal &&
1698 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1700 goto do_fetch_cache;
1705 refresh_sequence_number(domain, false);
1706 if (!NT_STATUS_IS_OK(status)) {
1709 centry = centry_start(domain, status);
1712 centry_put_uint32(centry, *num_entries);
1713 for (i=0; i<(*num_entries); i++) {
1714 centry_put_string(centry, (*info)[i].acct_name);
1715 centry_put_string(centry, (*info)[i].acct_desc);
1716 centry_put_uint32(centry, (*info)[i].rid);
1718 centry_end(centry, "GL/%s/local", domain->name);
1719 centry_free(centry);
1725 NTSTATUS wcache_name_to_sid(struct winbindd_domain *domain,
1726 const char *domain_name,
1728 struct dom_sid *sid,
1729 enum lsa_SidType *type)
1731 struct winbind_cache *cache = get_cache(domain);
1732 struct cache_entry *centry;
1736 if (cache->tdb == NULL) {
1737 return NT_STATUS_NOT_FOUND;
1740 uname = talloc_strdup_upper(talloc_tos(), name);
1741 if (uname == NULL) {
1742 return NT_STATUS_NO_MEMORY;
1745 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1747 if (centry == NULL) {
1748 return NT_STATUS_NOT_FOUND;
1751 status = centry->status;
1752 if (NT_STATUS_IS_OK(status)) {
1753 *type = (enum lsa_SidType)centry_uint32(centry);
1754 centry_sid(centry, sid);
1757 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1758 "%s\n", domain->name, nt_errstr(status) ));
1760 centry_free(centry);
1764 /* convert a single name to a sid in a domain */
1765 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
1766 TALLOC_CTX *mem_ctx,
1767 const char *domain_name,
1770 struct dom_sid *sid,
1771 enum lsa_SidType *type)
1776 old_status = domain->online;
1778 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1779 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1785 /* If the seq number check indicated that there is a problem
1786 * with this DC, then return that status... except for
1787 * access_denied. This is special because the dc may be in
1788 * "restrict anonymous = 1" mode, in which case it will deny
1789 * most unauthenticated operations, but *will* allow the LSA
1790 * name-to-sid that we try as a fallback. */
1792 if (!(NT_STATUS_IS_OK(domain->last_status)
1793 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1794 return domain->last_status;
1796 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1799 status = domain->backend->name_to_sid(domain, mem_ctx, domain_name,
1800 name, flags, sid, type);
1802 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1803 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1804 if (!domain->internal && old_status) {
1805 set_domain_offline(domain);
1807 if (!domain->internal &&
1810 NTSTATUS cache_status;
1811 cache_status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1812 return cache_status;
1816 refresh_sequence_number(domain, false);
1818 if (domain->online &&
1819 (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
1820 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1822 /* Only save the reverse mapping if this was not a UPN */
1823 if (!strchr(name, '@')) {
1824 strupper_m(CONST_DISCARD(char *,domain_name));
1825 strlower_m(CONST_DISCARD(char *,name));
1826 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1833 NTSTATUS wcache_sid_to_name(struct winbindd_domain *domain,
1834 const struct dom_sid *sid,
1835 TALLOC_CTX *mem_ctx,
1838 enum lsa_SidType *type)
1840 struct winbind_cache *cache = get_cache(domain);
1841 struct cache_entry *centry;
1845 if (cache->tdb == NULL) {
1846 return NT_STATUS_NOT_FOUND;
1849 sid_string = sid_string_tos(sid);
1850 if (sid_string == NULL) {
1851 return NT_STATUS_NO_MEMORY;
1854 centry = wcache_fetch(cache, domain, "SN/%s", sid_string);
1855 TALLOC_FREE(sid_string);
1856 if (centry == NULL) {
1857 return NT_STATUS_NOT_FOUND;
1860 if (NT_STATUS_IS_OK(centry->status)) {
1861 *type = (enum lsa_SidType)centry_uint32(centry);
1862 *domain_name = centry_string(centry, mem_ctx);
1863 *name = centry_string(centry, mem_ctx);
1866 status = centry->status;
1867 centry_free(centry);
1869 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1870 "%s\n", domain->name, nt_errstr(status) ));
1875 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1877 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
1878 TALLOC_CTX *mem_ctx,
1879 const struct dom_sid *sid,
1882 enum lsa_SidType *type)
1887 old_status = domain->online;
1888 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
1890 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1895 *domain_name = NULL;
1897 /* If the seq number check indicated that there is a problem
1898 * with this DC, then return that status... except for
1899 * access_denied. This is special because the dc may be in
1900 * "restrict anonymous = 1" mode, in which case it will deny
1901 * most unauthenticated operations, but *will* allow the LSA
1902 * sid-to-name that we try as a fallback. */
1904 if (!(NT_STATUS_IS_OK(domain->last_status)
1905 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1906 return domain->last_status;
1908 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1911 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1913 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1914 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1915 if (!domain->internal && old_status) {
1916 set_domain_offline(domain);
1918 if (!domain->internal &&
1921 NTSTATUS cache_status;
1922 cache_status = wcache_sid_to_name(domain, sid, mem_ctx,
1923 domain_name, name, type);
1924 return cache_status;
1928 refresh_sequence_number(domain, false);
1929 if (!NT_STATUS_IS_OK(status)) {
1932 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1934 /* We can't save the name to sid mapping here, as with sid history a
1935 * later name2sid would give the wrong sid. */
1940 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
1941 TALLOC_CTX *mem_ctx,
1942 const struct dom_sid *domain_sid,
1947 enum lsa_SidType **types)
1949 struct winbind_cache *cache = get_cache(domain);
1951 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1956 old_status = domain->online;
1957 *domain_name = NULL;
1965 if (num_rids == 0) {
1966 return NT_STATUS_OK;
1969 *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
1970 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
1972 if ((*names == NULL) || (*types == NULL)) {
1973 result = NT_STATUS_NO_MEMORY;
1977 have_mapped = have_unmapped = false;
1979 for (i=0; i<num_rids; i++) {
1981 struct cache_entry *centry;
1984 if (!sid_compose(&sid, domain_sid, rids[i])) {
1985 result = NT_STATUS_INTERNAL_ERROR;
1989 centry = wcache_fetch(cache, domain, "SN/%s",
1990 sid_to_fstring(tmp, &sid));
1995 (*types)[i] = SID_NAME_UNKNOWN;
1996 (*names)[i] = talloc_strdup(*names, "");
1998 if (NT_STATUS_IS_OK(centry->status)) {
2001 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
2003 dom = centry_string(centry, mem_ctx);
2004 if (*domain_name == NULL) {
2010 (*names)[i] = centry_string(centry, *names);
2012 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
2013 have_unmapped = true;
2016 /* something's definitely wrong */
2017 result = centry->status;
2021 centry_free(centry);
2025 return NT_STATUS_NONE_MAPPED;
2027 if (!have_unmapped) {
2028 return NT_STATUS_OK;
2030 return STATUS_SOME_UNMAPPED;
2034 TALLOC_FREE(*names);
2035 TALLOC_FREE(*types);
2037 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
2038 rids, num_rids, domain_name,
2041 if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
2042 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2043 if (!domain->internal && old_status) {
2044 set_domain_offline(domain);
2047 !domain->internal &&
2050 have_mapped = have_unmapped = false;
2052 for (i=0; i<num_rids; i++) {
2054 struct cache_entry *centry;
2057 if (!sid_compose(&sid, domain_sid, rids[i])) {
2058 result = NT_STATUS_INTERNAL_ERROR;
2062 centry = wcache_fetch(cache, domain, "SN/%s",
2063 sid_to_fstring(tmp, &sid));
2065 (*types)[i] = SID_NAME_UNKNOWN;
2066 (*names)[i] = talloc_strdup(*names, "");
2070 (*types)[i] = SID_NAME_UNKNOWN;
2071 (*names)[i] = talloc_strdup(*names, "");
2073 if (NT_STATUS_IS_OK(centry->status)) {
2076 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
2078 dom = centry_string(centry, mem_ctx);
2079 if (*domain_name == NULL) {
2085 (*names)[i] = centry_string(centry, *names);
2087 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
2088 have_unmapped = true;
2091 /* something's definitely wrong */
2092 result = centry->status;
2096 centry_free(centry);
2100 return NT_STATUS_NONE_MAPPED;
2102 if (!have_unmapped) {
2103 return NT_STATUS_OK;
2105 return STATUS_SOME_UNMAPPED;
2109 None of the queried rids has been found so save all negative entries
2111 if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
2112 for (i = 0; i < num_rids; i++) {
2114 const char *name = "";
2115 const enum lsa_SidType type = SID_NAME_UNKNOWN;
2116 NTSTATUS status = NT_STATUS_NONE_MAPPED;
2118 if (!sid_compose(&sid, domain_sid, rids[i])) {
2119 return NT_STATUS_INTERNAL_ERROR;
2122 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2130 Some or all of the queried rids have been found.
2132 if (!NT_STATUS_IS_OK(result) &&
2133 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
2137 refresh_sequence_number(domain, false);
2139 for (i=0; i<num_rids; i++) {
2143 if (!sid_compose(&sid, domain_sid, rids[i])) {
2144 result = NT_STATUS_INTERNAL_ERROR;
2148 status = (*types)[i] == SID_NAME_UNKNOWN ?
2149 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
2151 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2152 (*names)[i], (*types)[i]);
2158 TALLOC_FREE(*names);
2159 TALLOC_FREE(*types);
2163 NTSTATUS wcache_query_user(struct winbindd_domain *domain,
2164 TALLOC_CTX *mem_ctx,
2165 const struct dom_sid *user_sid,
2166 struct wbint_userinfo *info)
2168 struct winbind_cache *cache = get_cache(domain);
2169 struct cache_entry *centry = NULL;
2173 if (cache->tdb == NULL) {
2174 return NT_STATUS_NOT_FOUND;
2177 sid_string = sid_string_tos(user_sid);
2178 if (sid_string == NULL) {
2179 return NT_STATUS_NO_MEMORY;
2182 centry = wcache_fetch(cache, domain, "U/%s", sid_string);
2183 TALLOC_FREE(sid_string);
2184 if (centry == NULL) {
2185 return NT_STATUS_NOT_FOUND;
2189 * If we have an access denied cache entry and a cached info3
2190 * in the samlogon cache then do a query. This will force the
2191 * rpc back end to return the info3 data.
2194 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED) &&
2195 netsamlogon_cache_have(user_sid)) {
2196 DEBUG(10, ("query_user: cached access denied and have cached "
2198 domain->last_status = NT_STATUS_OK;
2199 centry_free(centry);
2200 return NT_STATUS_NOT_FOUND;
2203 /* if status is not ok then this is a negative hit
2204 and the rest of the data doesn't matter */
2205 status = centry->status;
2206 if (NT_STATUS_IS_OK(status)) {
2207 info->acct_name = centry_string(centry, mem_ctx);
2208 info->full_name = centry_string(centry, mem_ctx);
2209 info->homedir = centry_string(centry, mem_ctx);
2210 info->shell = centry_string(centry, mem_ctx);
2211 info->primary_gid = centry_uint32(centry);
2212 centry_sid(centry, &info->user_sid);
2213 centry_sid(centry, &info->group_sid);
2216 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2217 "%s\n", domain->name, nt_errstr(status) ));
2219 centry_free(centry);
2223 /* Lookup user information from a rid */
2224 static NTSTATUS query_user(struct winbindd_domain *domain,
2225 TALLOC_CTX *mem_ctx,
2226 const struct dom_sid *user_sid,
2227 struct wbint_userinfo *info)
2232 old_status = domain->online;
2233 status = wcache_query_user(domain, mem_ctx, user_sid, info);
2234 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2240 /* Return status value returned by seq number check */
2242 if (!NT_STATUS_IS_OK(domain->last_status))
2243 return domain->last_status;
2245 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2248 status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
2250 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2251 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2252 if (!domain->internal && old_status) {
2253 set_domain_offline(domain);
2255 if (!domain->internal &&
2258 NTSTATUS cache_status;
2259 cache_status = wcache_query_user(domain, mem_ctx, user_sid, info);
2260 return cache_status;
2264 refresh_sequence_number(domain, false);
2265 if (!NT_STATUS_IS_OK(status)) {
2268 wcache_save_user(domain, status, info);
2273 NTSTATUS wcache_lookup_usergroups(struct winbindd_domain *domain,
2274 TALLOC_CTX *mem_ctx,
2275 const struct dom_sid *user_sid,
2276 uint32_t *pnum_sids,
2277 struct dom_sid **psids)
2279 struct winbind_cache *cache = get_cache(domain);
2280 struct cache_entry *centry = NULL;
2282 uint32_t i, num_sids;
2283 struct dom_sid *sids;
2286 if (cache->tdb == NULL) {
2287 return NT_STATUS_NOT_FOUND;
2290 centry = wcache_fetch(cache, domain, "UG/%s",
2291 sid_to_fstring(sid_string, user_sid));
2292 if (centry == NULL) {
2293 return NT_STATUS_NOT_FOUND;
2296 /* If we have an access denied cache entry and a cached info3 in the
2297 samlogon cache then do a query. This will force the rpc back end
2298 to return the info3 data. */
2300 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)
2301 && netsamlogon_cache_have(user_sid)) {
2302 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2304 domain->last_status = NT_STATUS_OK;
2305 centry_free(centry);
2306 return NT_STATUS_NOT_FOUND;
2309 num_sids = centry_uint32(centry);
2310 sids = talloc_array(mem_ctx, struct dom_sid, num_sids);
2312 centry_free(centry);
2313 return NT_STATUS_NO_MEMORY;
2316 for (i=0; i<num_sids; i++) {
2317 centry_sid(centry, &sids[i]);
2320 status = centry->status;
2322 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2323 "status: %s\n", domain->name, nt_errstr(status)));
2325 centry_free(centry);
2327 *pnum_sids = num_sids;
2332 /* Lookup groups a user is a member of. */
2333 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
2334 TALLOC_CTX *mem_ctx,
2335 const struct dom_sid *user_sid,
2336 uint32 *num_groups, struct dom_sid **user_gids)
2338 struct cache_entry *centry = NULL;
2344 old_status = domain->online;
2345 status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2346 num_groups, user_gids);
2347 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2352 (*user_gids) = NULL;
2354 /* Return status value returned by seq number check */
2356 if (!NT_STATUS_IS_OK(domain->last_status))
2357 return domain->last_status;
2359 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2362 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
2364 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2365 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2366 if (!domain->internal && old_status) {
2367 set_domain_offline(domain);
2369 if (!domain->internal &&
2372 NTSTATUS cache_status;
2373 cache_status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2374 num_groups, user_gids);
2375 return cache_status;
2378 if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
2382 refresh_sequence_number(domain, false);
2383 if (!NT_STATUS_IS_OK(status)) {
2386 centry = centry_start(domain, status);
2390 centry_put_uint32(centry, *num_groups);
2391 for (i=0; i<(*num_groups); i++) {
2392 centry_put_sid(centry, &(*user_gids)[i]);
2395 centry_end(centry, "UG/%s", sid_to_fstring(sid_string, user_sid));
2396 centry_free(centry);
2402 static char *wcache_make_sidlist(TALLOC_CTX *mem_ctx, uint32_t num_sids,
2403 const struct dom_sid *sids)
2408 sidlist = talloc_strdup(mem_ctx, "");
2409 if (sidlist == NULL) {
2412 for (i=0; i<num_sids; i++) {
2414 sidlist = talloc_asprintf_append_buffer(
2415 sidlist, "/%s", sid_to_fstring(tmp, &sids[i]));
2416 if (sidlist == NULL) {
2423 NTSTATUS wcache_lookup_useraliases(struct winbindd_domain *domain,
2424 TALLOC_CTX *mem_ctx, uint32_t num_sids,
2425 const struct dom_sid *sids,
2426 uint32_t *pnum_aliases, uint32_t **paliases)
2428 struct winbind_cache *cache = get_cache(domain);
2429 struct cache_entry *centry = NULL;
2430 uint32_t num_aliases;
2436 if (cache->tdb == NULL) {
2437 return NT_STATUS_NOT_FOUND;
2440 if (num_sids == 0) {
2443 return NT_STATUS_OK;
2446 /* We need to cache indexed by the whole list of SIDs, the aliases
2447 * resulting might come from any of the SIDs. */
2449 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2450 if (sidlist == NULL) {
2451 return NT_STATUS_NO_MEMORY;
2454 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
2455 TALLOC_FREE(sidlist);
2456 if (centry == NULL) {
2457 return NT_STATUS_NOT_FOUND;
2460 num_aliases = centry_uint32(centry);
2461 aliases = talloc_array(mem_ctx, uint32_t, num_aliases);
2462 if (aliases == NULL) {
2463 centry_free(centry);
2464 return NT_STATUS_NO_MEMORY;
2467 for (i=0; i<num_aliases; i++) {
2468 aliases[i] = centry_uint32(centry);
2471 status = centry->status;
2473 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2474 "status %s\n", domain->name, nt_errstr(status)));
2476 centry_free(centry);
2478 *pnum_aliases = num_aliases;
2479 *paliases = aliases;
2484 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
2485 TALLOC_CTX *mem_ctx,
2486 uint32 num_sids, const struct dom_sid *sids,
2487 uint32 *num_aliases, uint32 **alias_rids)
2489 struct cache_entry *centry = NULL;
2495 old_status = domain->online;
2496 status = wcache_lookup_useraliases(domain, mem_ctx, num_sids, sids,
2497 num_aliases, alias_rids);
2498 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2503 (*alias_rids) = NULL;
2505 if (!NT_STATUS_IS_OK(domain->last_status))
2506 return domain->last_status;
2508 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2509 "for domain %s\n", domain->name ));
2511 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2512 if (sidlist == NULL) {
2513 return NT_STATUS_NO_MEMORY;
2516 status = domain->backend->lookup_useraliases(domain, mem_ctx,
2518 num_aliases, alias_rids);
2520 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2521 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2522 if (!domain->internal && old_status) {
2523 set_domain_offline(domain);
2525 if (!domain->internal &&
2528 NTSTATUS cache_status;
2529 cache_status = wcache_lookup_useraliases(domain, mem_ctx, num_sids,
2530 sids, num_aliases, alias_rids);
2531 return cache_status;
2535 refresh_sequence_number(domain, false);
2536 if (!NT_STATUS_IS_OK(status)) {
2539 centry = centry_start(domain, status);
2542 centry_put_uint32(centry, *num_aliases);
2543 for (i=0; i<(*num_aliases); i++)
2544 centry_put_uint32(centry, (*alias_rids)[i]);
2545 centry_end(centry, "UA%s", sidlist);
2546 centry_free(centry);
2552 NTSTATUS wcache_lookup_groupmem(struct winbindd_domain *domain,
2553 TALLOC_CTX *mem_ctx,
2554 const struct dom_sid *group_sid,
2555 uint32_t *num_names,
2556 struct dom_sid **sid_mem, char ***names,
2557 uint32_t **name_types)
2559 struct winbind_cache *cache = get_cache(domain);
2560 struct cache_entry *centry = NULL;
2565 if (cache->tdb == NULL) {
2566 return NT_STATUS_NOT_FOUND;
2569 sid_string = sid_string_tos(group_sid);
2570 if (sid_string == NULL) {
2571 return NT_STATUS_NO_MEMORY;
2574 centry = wcache_fetch(cache, domain, "GM/%s", sid_string);
2575 TALLOC_FREE(sid_string);
2576 if (centry == NULL) {
2577 return NT_STATUS_NOT_FOUND;
2584 *num_names = centry_uint32(centry);
2585 if (*num_names == 0) {
2586 centry_free(centry);
2587 return NT_STATUS_OK;
2590 *sid_mem = talloc_array(mem_ctx, struct dom_sid, *num_names);
2591 *names = talloc_array(mem_ctx, char *, *num_names);
2592 *name_types = talloc_array(mem_ctx, uint32, *num_names);
2594 if ((*sid_mem == NULL) || (*names == NULL) || (*name_types == NULL)) {
2595 TALLOC_FREE(*sid_mem);
2596 TALLOC_FREE(*names);
2597 TALLOC_FREE(*name_types);
2598 centry_free(centry);
2599 return NT_STATUS_NO_MEMORY;
2602 for (i=0; i<(*num_names); i++) {
2603 centry_sid(centry, &(*sid_mem)[i]);
2604 (*names)[i] = centry_string(centry, mem_ctx);
2605 (*name_types)[i] = centry_uint32(centry);
2608 status = centry->status;
2610 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2611 "status: %s\n", domain->name, nt_errstr(status)));
2613 centry_free(centry);
2617 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
2618 TALLOC_CTX *mem_ctx,
2619 const struct dom_sid *group_sid,
2620 enum lsa_SidType type,
2622 struct dom_sid **sid_mem, char ***names,
2623 uint32 **name_types)
2625 struct cache_entry *centry = NULL;
2631 old_status = domain->online;
2632 status = wcache_lookup_groupmem(domain, mem_ctx, group_sid, num_names,
2633 sid_mem, names, name_types);
2634 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2641 (*name_types) = NULL;
2643 /* Return status value returned by seq number check */
2645 if (!NT_STATUS_IS_OK(domain->last_status))
2646 return domain->last_status;
2648 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2651 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid,
2653 sid_mem, names, name_types);
2655 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2656 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2657 if (!domain->internal && old_status) {
2658 set_domain_offline(domain);
2660 if (!domain->internal &&
2663 NTSTATUS cache_status;
2664 cache_status = wcache_lookup_groupmem(domain, mem_ctx, group_sid,
2665 num_names, sid_mem, names,
2667 return cache_status;
2671 refresh_sequence_number(domain, false);
2672 if (!NT_STATUS_IS_OK(status)) {
2675 centry = centry_start(domain, status);
2678 centry_put_uint32(centry, *num_names);
2679 for (i=0; i<(*num_names); i++) {
2680 centry_put_sid(centry, &(*sid_mem)[i]);
2681 centry_put_string(centry, (*names)[i]);
2682 centry_put_uint32(centry, (*name_types)[i]);
2684 centry_end(centry, "GM/%s", sid_to_fstring(sid_string, group_sid));
2685 centry_free(centry);
2691 /* find the sequence number for a domain */
2692 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
2694 refresh_sequence_number(domain, false);
2696 *seq = domain->sequence_number;
2698 return NT_STATUS_OK;
2701 /* enumerate trusted domains
2702 * (we need to have the list of trustdoms in the cache when we go offline) -
2704 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
2705 TALLOC_CTX *mem_ctx,
2706 struct netr_DomainTrustList *trusts)
2709 struct winbind_cache *cache;
2710 struct winbindd_tdc_domain *dom_list = NULL;
2711 size_t num_domains = 0;
2712 bool retval = false;
2716 old_status = domain->online;
2718 trusts->array = NULL;
2720 cache = get_cache(domain);
2721 if (!cache || !cache->tdb) {
2725 if (domain->online) {
2729 retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2730 if (!retval || !num_domains || !dom_list) {
2731 TALLOC_FREE(dom_list);
2736 trusts->array = TALLOC_ZERO_ARRAY(mem_ctx, struct netr_DomainTrust, num_domains);
2737 if (!trusts->array) {
2738 TALLOC_FREE(dom_list);
2739 return NT_STATUS_NO_MEMORY;
2742 for (i = 0; i < num_domains; i++) {
2743 struct netr_DomainTrust *trust;
2744 struct dom_sid *sid;
2745 struct winbindd_domain *dom;
2747 dom = find_domain_from_name_noinit(dom_list[i].domain_name);
2748 if (dom && dom->internal) {
2752 trust = &trusts->array[trusts->count];
2753 trust->netbios_name = talloc_strdup(trusts->array, dom_list[i].domain_name);
2754 trust->dns_name = talloc_strdup(trusts->array, dom_list[i].dns_name);
2755 sid = talloc(trusts->array, struct dom_sid);
2756 if (!trust->netbios_name || !trust->dns_name ||
2758 TALLOC_FREE(dom_list);
2759 TALLOC_FREE(trusts->array);
2760 return NT_STATUS_NO_MEMORY;
2763 trust->trust_flags = dom_list[i].trust_flags;
2764 trust->trust_attributes = dom_list[i].trust_attribs;
2765 trust->trust_type = dom_list[i].trust_type;
2766 sid_copy(sid, &dom_list[i].sid);
2771 TALLOC_FREE(dom_list);
2772 return NT_STATUS_OK;
2775 /* Return status value returned by seq number check */
2777 if (!NT_STATUS_IS_OK(domain->last_status))
2778 return domain->last_status;
2780 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2783 status = domain->backend->trusted_domains(domain, mem_ctx, trusts);
2785 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2786 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2787 if (!domain->internal && old_status) {
2788 set_domain_offline(domain);
2790 if (!domain->internal &&
2793 retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2794 if (retval && num_domains && dom_list) {
2795 TALLOC_FREE(trusts->array);
2797 goto do_fetch_cache;
2801 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2802 * so that the generic centry handling still applies correctly -
2805 if (!NT_STATUS_IS_ERR(status)) {
2806 status = NT_STATUS_OK;
2811 /* get lockout policy */
2812 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
2813 TALLOC_CTX *mem_ctx,
2814 struct samr_DomInfo12 *policy)
2816 struct winbind_cache *cache = get_cache(domain);
2817 struct cache_entry *centry = NULL;
2821 old_status = domain->online;
2825 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2831 policy->lockout_duration = centry_nttime(centry);
2832 policy->lockout_window = centry_nttime(centry);
2833 policy->lockout_threshold = centry_uint16(centry);
2835 status = centry->status;
2837 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2838 domain->name, nt_errstr(status) ));
2840 centry_free(centry);
2844 ZERO_STRUCTP(policy);
2846 /* Return status value returned by seq number check */
2848 if (!NT_STATUS_IS_OK(domain->last_status))
2849 return domain->last_status;
2851 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2854 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2856 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2857 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2858 if (!domain->internal && old_status) {
2859 set_domain_offline(domain);
2862 !domain->internal &&
2865 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2867 goto do_fetch_cache;
2872 refresh_sequence_number(domain, false);
2873 if (!NT_STATUS_IS_OK(status)) {
2876 wcache_save_lockout_policy(domain, status, policy);
2881 /* get password policy */
2882 static NTSTATUS password_policy(struct winbindd_domain *domain,
2883 TALLOC_CTX *mem_ctx,
2884 struct samr_DomInfo1 *policy)
2886 struct winbind_cache *cache = get_cache(domain);
2887 struct cache_entry *centry = NULL;
2891 old_status = domain->online;
2895 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2901 policy->min_password_length = centry_uint16(centry);
2902 policy->password_history_length = centry_uint16(centry);
2903 policy->password_properties = centry_uint32(centry);
2904 policy->max_password_age = centry_nttime(centry);
2905 policy->min_password_age = centry_nttime(centry);
2907 status = centry->status;
2909 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2910 domain->name, nt_errstr(status) ));
2912 centry_free(centry);
2916 ZERO_STRUCTP(policy);
2918 /* Return status value returned by seq number check */
2920 if (!NT_STATUS_IS_OK(domain->last_status))
2921 return domain->last_status;
2923 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2926 status = domain->backend->password_policy(domain, mem_ctx, policy);
2928 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2929 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2930 if (!domain->internal && old_status) {
2931 set_domain_offline(domain);
2934 !domain->internal &&
2937 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2939 goto do_fetch_cache;
2944 refresh_sequence_number(domain, false);
2945 if (!NT_STATUS_IS_OK(status)) {
2948 wcache_save_password_policy(domain, status, policy);
2954 /* Invalidate cached user and group lists coherently */
2956 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2959 if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
2960 strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
2961 tdb_delete(the_tdb, kbuf);
2966 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2968 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
2969 struct netr_SamInfo3 *info3)
2972 fstring key_str, sid_string;
2973 struct winbind_cache *cache;
2975 /* dont clear cached U/SID and UG/SID entries when we want to logon
2978 if (lp_winbind_offline_logon()) {
2985 cache = get_cache(domain);
2991 sid_compose(&sid, info3->base.domain_sid, info3->base.rid);
2993 /* Clear U/SID cache entry */
2994 fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, &sid));
2995 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
2996 tdb_delete(cache->tdb, string_tdb_data(key_str));
2998 /* Clear UG/SID cache entry */
2999 fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, &sid));
3000 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
3001 tdb_delete(cache->tdb, string_tdb_data(key_str));
3003 /* Samba/winbindd never needs this. */
3004 netsamlogon_clear_cached_user(info3);
3007 bool wcache_invalidate_cache(void)
3009 struct winbindd_domain *domain;
3011 for (domain = domain_list(); domain; domain = domain->next) {
3012 struct winbind_cache *cache = get_cache(domain);
3014 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3015 "entries for %s\n", domain->name));
3018 tdb_traverse(cache->tdb, traverse_fn, NULL);
3027 bool wcache_invalidate_cache_noinit(void)
3029 struct winbindd_domain *domain;
3031 for (domain = domain_list(); domain; domain = domain->next) {
3032 struct winbind_cache *cache;
3034 /* Skip uninitialized domains. */
3035 if (!domain->initialized && !domain->internal) {
3039 cache = get_cache(domain);
3041 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3042 "entries for %s\n", domain->name));
3045 tdb_traverse(cache->tdb, traverse_fn, NULL);
3047 * Flushing cache has nothing to with domains.
3048 * return here if we successfully flushed once.
3049 * To avoid unnecessary traversing the cache.
3060 bool init_wcache(void)
3062 if (wcache == NULL) {
3063 wcache = SMB_XMALLOC_P(struct winbind_cache);
3064 ZERO_STRUCTP(wcache);
3067 if (wcache->tdb != NULL)
3070 /* when working offline we must not clear the cache on restart */
3071 wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
3072 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3073 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
3074 O_RDWR|O_CREAT, 0600);
3076 if (wcache->tdb == NULL) {
3077 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3084 /************************************************************************
3085 This is called by the parent to initialize the cache file.
3086 We don't need sophisticated locking here as we know we're the
3088 ************************************************************************/
3090 bool initialize_winbindd_cache(void)
3092 bool cache_bad = true;
3095 if (!init_wcache()) {
3096 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3100 /* Check version number. */
3101 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
3102 vers == WINBINDD_CACHE_VERSION) {
3107 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3108 "and re-creating with version number %d\n",
3109 WINBINDD_CACHE_VERSION ));
3111 tdb_close(wcache->tdb);
3114 if (unlink(cache_path("winbindd_cache.tdb")) == -1) {
3115 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3116 cache_path("winbindd_cache.tdb"),
3120 if (!init_wcache()) {
3121 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3122 "init_wcache failed.\n"));
3126 /* Write the version. */
3127 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
3128 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3129 tdb_errorstr(wcache->tdb) ));
3134 tdb_close(wcache->tdb);
3139 void close_winbindd_cache(void)
3145 tdb_close(wcache->tdb);
3150 bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
3151 char **domain_name, char **name,
3152 enum lsa_SidType *type)
3154 struct winbindd_domain *domain;
3157 domain = find_lookup_domain_from_sid(sid);
3158 if (domain == NULL) {
3161 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
3163 return NT_STATUS_IS_OK(status);
3166 bool lookup_cached_name(TALLOC_CTX *mem_ctx,
3167 const char *domain_name,
3169 struct dom_sid *sid,
3170 enum lsa_SidType *type)
3172 struct winbindd_domain *domain;
3174 bool original_online_state;
3176 domain = find_lookup_domain_from_name(domain_name);
3177 if (domain == NULL) {
3181 /* If we are doing a cached logon, temporarily set the domain
3182 offline so the cache won't expire the entry */
3184 original_online_state = domain->online;
3185 domain->online = false;
3186 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
3187 domain->online = original_online_state;
3189 return NT_STATUS_IS_OK(status);
3192 void cache_name2sid(struct winbindd_domain *domain,
3193 const char *domain_name, const char *name,
3194 enum lsa_SidType type, const struct dom_sid *sid)
3196 refresh_sequence_number(domain, false);
3197 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
3202 * The original idea that this cache only contains centries has
3203 * been blurred - now other stuff gets put in here. Ensure we
3204 * ignore these things on cleanup.
3207 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
3208 TDB_DATA dbuf, void *state)
3210 struct cache_entry *centry;
3212 if (is_non_centry_key(kbuf)) {
3216 centry = wcache_fetch_raw((char *)kbuf.dptr);
3221 if (!NT_STATUS_IS_OK(centry->status)) {
3222 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
3223 tdb_delete(the_tdb, kbuf);
3226 centry_free(centry);
3230 /* flush the cache */
3231 void wcache_flush_cache(void)
3236 tdb_close(wcache->tdb);
3239 if (!winbindd_use_cache()) {
3243 /* when working offline we must not clear the cache on restart */
3244 wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
3245 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3246 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
3247 O_RDWR|O_CREAT, 0600);
3250 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3254 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
3256 DEBUG(10,("wcache_flush_cache success\n"));
3259 /* Count cached creds */
3261 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3264 int *cred_count = (int*)state;
3266 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3272 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
3274 struct winbind_cache *cache = get_cache(domain);
3279 return NT_STATUS_INTERNAL_DB_ERROR;
3282 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
3284 return NT_STATUS_OK;
3288 struct cred_list *prev, *next;
3293 static struct cred_list *wcache_cred_list;
3295 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3298 struct cred_list *cred;
3300 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3302 cred = SMB_MALLOC_P(struct cred_list);
3304 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3310 /* save a copy of the key */
3312 fstrcpy(cred->name, (const char *)kbuf.dptr);
3313 DLIST_ADD(wcache_cred_list, cred);
3319 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const struct dom_sid *sid)
3321 struct winbind_cache *cache = get_cache(domain);
3324 struct cred_list *cred, *oldest = NULL;
3327 return NT_STATUS_INTERNAL_DB_ERROR;
3330 /* we possibly already have an entry */
3331 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
3333 fstring key_str, tmp;
3335 DEBUG(11,("we already have an entry, deleting that\n"));
3337 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
3339 tdb_delete(cache->tdb, string_tdb_data(key_str));
3341 return NT_STATUS_OK;
3344 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
3346 return NT_STATUS_OK;
3347 } else if ((ret == -1) || (wcache_cred_list == NULL)) {
3348 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3351 ZERO_STRUCTP(oldest);
3353 for (cred = wcache_cred_list; cred; cred = cred->next) {
3358 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
3360 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3362 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
3366 t = IVAL(data.dptr, 0);
3367 SAFE_FREE(data.dptr);
3370 oldest = SMB_MALLOC_P(struct cred_list);
3371 if (oldest == NULL) {
3372 status = NT_STATUS_NO_MEMORY;
3376 fstrcpy(oldest->name, cred->name);
3377 oldest->created = t;
3381 if (t < oldest->created) {
3382 fstrcpy(oldest->name, cred->name);
3383 oldest->created = t;
3387 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
3388 status = NT_STATUS_OK;
3390 status = NT_STATUS_UNSUCCESSFUL;
3393 SAFE_FREE(wcache_cred_list);
3399 /* Change the global online/offline state. */
3400 bool set_global_winbindd_state_offline(void)
3404 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3406 /* Only go offline if someone has created
3407 the key "WINBINDD_OFFLINE" in the cache tdb. */
3409 if (wcache == NULL || wcache->tdb == NULL) {
3410 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3414 if (!lp_winbind_offline_logon()) {
3415 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3419 if (global_winbindd_offline_state) {
3420 /* Already offline. */
3424 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
3426 if (!data.dptr || data.dsize != 4) {
3427 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3428 SAFE_FREE(data.dptr);
3431 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3432 global_winbindd_offline_state = true;
3433 SAFE_FREE(data.dptr);
3438 void set_global_winbindd_state_online(void)
3440 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3442 if (!lp_winbind_offline_logon()) {
3443 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3447 if (!global_winbindd_offline_state) {
3448 /* Already online. */
3451 global_winbindd_offline_state = false;
3457 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3458 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
3461 bool get_global_winbindd_state_offline(void)
3463 return global_winbindd_offline_state;
3466 /***********************************************************************
3467 Validate functions for all possible cache tdb keys.
3468 ***********************************************************************/
3470 static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
3471 struct tdb_validation_status *state)
3473 struct cache_entry *centry;
3475 centry = SMB_XMALLOC_P(struct cache_entry);
3476 centry->data = (unsigned char *)memdup(data.dptr, data.dsize);
3477 if (!centry->data) {
3481 centry->len = data.dsize;
3484 if (centry->len < 8) {
3485 /* huh? corrupt cache? */
3486 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr));
3487 centry_free(centry);
3488 state->bad_entry = true;
3489 state->success = false;
3493 centry->status = NT_STATUS(centry_uint32(centry));
3494 centry->sequence_number = centry_uint32(centry);
3498 static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3499 struct tdb_validation_status *state)
3501 if (dbuf.dsize != 8) {
3502 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3503 keystr, (unsigned int)dbuf.dsize ));
3504 state->bad_entry = true;
3510 static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3511 struct tdb_validation_status *state)
3513 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3518 (void)centry_uint32(centry);
3519 if (NT_STATUS_IS_OK(centry->status)) {
3521 (void)centry_sid(centry, &sid);
3524 centry_free(centry);
3526 if (!(state->success)) {
3529 DEBUG(10,("validate_ns: %s ok\n", keystr));
3533 static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3534 struct tdb_validation_status *state)
3536 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3541 if (NT_STATUS_IS_OK(centry->status)) {
3542 (void)centry_uint32(centry);
3543 (void)centry_string(centry, mem_ctx);
3544 (void)centry_string(centry, mem_ctx);
3547 centry_free(centry);
3549 if (!(state->success)) {
3552 DEBUG(10,("validate_sn: %s ok\n", keystr));
3556 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3557 struct tdb_validation_status *state)
3559 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3566 (void)centry_string(centry, mem_ctx);
3567 (void)centry_string(centry, mem_ctx);
3568 (void)centry_string(centry, mem_ctx);
3569 (void)centry_string(centry, mem_ctx);
3570 (void)centry_uint32(centry);
3571 (void)centry_sid(centry, &sid);
3572 (void)centry_sid(centry, &sid);
3574 centry_free(centry);
3576 if (!(state->success)) {
3579 DEBUG(10,("validate_u: %s ok\n", keystr));
3583 static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3584 struct tdb_validation_status *state)
3586 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3592 (void)centry_nttime(centry);
3593 (void)centry_nttime(centry);
3594 (void)centry_uint16(centry);
3596 centry_free(centry);
3598 if (!(state->success)) {
3601 DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
3605 static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3606 struct tdb_validation_status *state)
3608 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3614 (void)centry_uint16(centry);
3615 (void)centry_uint16(centry);
3616 (void)centry_uint32(centry);
3617 (void)centry_nttime(centry);
3618 (void)centry_nttime(centry);
3620 centry_free(centry);
3622 if (!(state->success)) {
3625 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
3629 static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3630 struct tdb_validation_status *state)
3632 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3638 (void)centry_time(centry);
3639 (void)centry_hash16(centry, mem_ctx);
3641 /* We only have 17 bytes more data in the salted cred case. */
3642 if (centry->len - centry->ofs == 17) {
3643 (void)centry_hash16(centry, mem_ctx);
3646 centry_free(centry);
3648 if (!(state->success)) {
3651 DEBUG(10,("validate_cred: %s ok\n", keystr));
3655 static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3656 struct tdb_validation_status *state)
3658 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3659 int32 num_entries, i;
3665 num_entries = (int32)centry_uint32(centry);
3667 for (i=0; i< num_entries; i++) {
3669 (void)centry_string(centry, mem_ctx);
3670 (void)centry_string(centry, mem_ctx);
3671 (void)centry_string(centry, mem_ctx);
3672 (void)centry_string(centry, mem_ctx);
3673 (void)centry_sid(centry, &sid);
3674 (void)centry_sid(centry, &sid);
3677 centry_free(centry);
3679 if (!(state->success)) {
3682 DEBUG(10,("validate_ul: %s ok\n", keystr));
3686 static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3687 struct tdb_validation_status *state)
3689 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3690 int32 num_entries, i;
3696 num_entries = centry_uint32(centry);
3698 for (i=0; i< num_entries; i++) {
3699 (void)centry_string(centry, mem_ctx);
3700 (void)centry_string(centry, mem_ctx);
3701 (void)centry_uint32(centry);
3704 centry_free(centry);
3706 if (!(state->success)) {
3709 DEBUG(10,("validate_gl: %s ok\n", keystr));
3713 static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3714 struct tdb_validation_status *state)
3716 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3717 int32 num_groups, i;
3723 num_groups = centry_uint32(centry);
3725 for (i=0; i< num_groups; i++) {
3727 centry_sid(centry, &sid);
3730 centry_free(centry);
3732 if (!(state->success)) {
3735 DEBUG(10,("validate_ug: %s ok\n", keystr));
3739 static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3740 struct tdb_validation_status *state)
3742 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3743 int32 num_aliases, i;
3749 num_aliases = centry_uint32(centry);
3751 for (i=0; i < num_aliases; i++) {
3752 (void)centry_uint32(centry);
3755 centry_free(centry);
3757 if (!(state->success)) {
3760 DEBUG(10,("validate_ua: %s ok\n", keystr));
3764 static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3765 struct tdb_validation_status *state)
3767 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3774 num_names = centry_uint32(centry);
3776 for (i=0; i< num_names; i++) {
3778 centry_sid(centry, &sid);
3779 (void)centry_string(centry, mem_ctx);
3780 (void)centry_uint32(centry);
3783 centry_free(centry);
3785 if (!(state->success)) {
3788 DEBUG(10,("validate_gm: %s ok\n", keystr));
3792 static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3793 struct tdb_validation_status *state)
3795 /* Can't say anything about this other than must be nonzero. */
3796 if (dbuf.dsize == 0) {
3797 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3799 state->bad_entry = true;
3800 state->success = false;
3804 DEBUG(10,("validate_dr: %s ok\n", keystr));
3808 static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3809 struct tdb_validation_status *state)
3811 /* Can't say anything about this other than must be nonzero. */
3812 if (dbuf.dsize == 0) {
3813 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3815 state->bad_entry = true;
3816 state->success = false;
3820 DEBUG(10,("validate_de: %s ok\n", keystr));
3824 static int validate_pwinfo(TALLOC_CTX *mem_ctx, const char *keystr,
3825 TDB_DATA dbuf, struct tdb_validation_status *state)
3827 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3833 (void)centry_string(centry, mem_ctx);
3834 (void)centry_string(centry, mem_ctx);
3835 (void)centry_string(centry, mem_ctx);
3836 (void)centry_uint32(centry);
3838 centry_free(centry);
3840 if (!(state->success)) {
3843 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3847 static int validate_nss_an(TALLOC_CTX *mem_ctx, const char *keystr,
3849 struct tdb_validation_status *state)
3851 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3857 (void)centry_string( centry, mem_ctx );
3859 centry_free(centry);
3861 if (!(state->success)) {
3864 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3868 static int validate_nss_na(TALLOC_CTX *mem_ctx, const char *keystr,
3870 struct tdb_validation_status *state)
3872 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3878 (void)centry_string( centry, mem_ctx );
3880 centry_free(centry);
3882 if (!(state->success)) {
3885 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3889 static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
3891 struct tdb_validation_status *state)
3893 if (dbuf.dsize == 0) {
3894 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3895 "key %s (len ==0) ?\n", keystr));
3896 state->bad_entry = true;
3897 state->success = false;
3901 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
3902 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3906 static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3907 struct tdb_validation_status *state)
3909 if (dbuf.dsize != 4) {
3910 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3911 keystr, (unsigned int)dbuf.dsize ));
3912 state->bad_entry = true;
3913 state->success = false;
3916 DEBUG(10,("validate_offline: %s ok\n", keystr));
3920 static int validate_ndr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3921 struct tdb_validation_status *state)
3924 * Ignore validation for now. The proper way to do this is with a
3925 * checksum. Just pure parsing does not really catch much.
3930 static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3931 struct tdb_validation_status *state)
3933 if (dbuf.dsize != 4) {
3934 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3935 "key %s (len %u != 4) ?\n",
3936 keystr, (unsigned int)dbuf.dsize));
3937 state->bad_entry = true;
3938 state->success = false;
3942 DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
3946 /***********************************************************************
3947 A list of all possible cache tdb keys with associated validation
3949 ***********************************************************************/
3951 struct key_val_struct {
3952 const char *keyname;
3953 int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
3955 {"SEQNUM/", validate_seqnum},
3956 {"NS/", validate_ns},
3957 {"SN/", validate_sn},
3959 {"LOC_POL/", validate_loc_pol},
3960 {"PWD_POL/", validate_pwd_pol},
3961 {"CRED/", validate_cred},
3962 {"UL/", validate_ul},
3963 {"GL/", validate_gl},
3964 {"UG/", validate_ug},
3965 {"UA", validate_ua},
3966 {"GM/", validate_gm},
3967 {"DR/", validate_dr},
3968 {"DE/", validate_de},
3969 {"NSS/PWINFO/", validate_pwinfo},
3970 {"TRUSTDOMCACHE/", validate_trustdomcache},
3971 {"NSS/NA/", validate_nss_na},
3972 {"NSS/AN/", validate_nss_an},
3973 {"WINBINDD_OFFLINE", validate_offline},
3974 {"NDR/", validate_ndr},
3975 {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
3979 /***********************************************************************
3980 Function to look at every entry in the tdb and validate it as far as
3982 ***********************************************************************/
3984 static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
3987 unsigned int max_key_len = 1024;
3988 struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
3990 /* Paranoia check. */
3991 if (strncmp("UA/", (const char *)kbuf.dptr, 3) == 0) {
3992 max_key_len = 1024 * 1024;
3994 if (kbuf.dsize > max_key_len) {
3995 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
3997 (unsigned int)kbuf.dsize, (unsigned int)max_key_len));
4001 for (i = 0; key_val[i].keyname; i++) {
4002 size_t namelen = strlen(key_val[i].keyname);
4003 if (kbuf.dsize >= namelen && (
4004 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
4005 TALLOC_CTX *mem_ctx;
4009 keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
4013 memcpy(keystr, kbuf.dptr, kbuf.dsize);
4014 keystr[kbuf.dsize] = '\0';
4016 mem_ctx = talloc_init("validate_ctx");
4022 ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
4026 talloc_destroy(mem_ctx);
4031 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4032 dump_data(0, (uint8 *)kbuf.dptr, kbuf.dsize);
4033 DEBUG(0,("data :\n"));
4034 dump_data(0, (uint8 *)dbuf.dptr, dbuf.dsize);
4035 v_state->unknown_key = true;
4036 v_state->success = false;
4037 return 1; /* terminate. */
4040 static void validate_panic(const char *const why)
4042 DEBUG(0,("validating cache: would panic %s\n", why ));
4043 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4047 /***********************************************************************
4048 Try and validate every entry in the winbindd cache. If we fail here,
4049 delete the cache tdb and return non-zero.
4050 ***********************************************************************/
4052 int winbindd_validate_cache(void)
4055 const char *tdb_path = cache_path("winbindd_cache.tdb");
4056 TDB_CONTEXT *tdb = NULL;
4058 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4059 smb_panic_fn = validate_panic;
4062 tdb = tdb_open_log(tdb_path,
4063 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
4064 ( lp_winbind_offline_logon()
4066 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
4070 DEBUG(0, ("winbindd_validate_cache: "
4071 "error opening/initializing tdb\n"));
4076 ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
4079 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4080 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
4085 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4086 smb_panic_fn = smb_panic;
4090 /***********************************************************************
4091 Try and validate every entry in the winbindd cache.
4092 ***********************************************************************/
4094 int winbindd_validate_cache_nobackup(void)
4097 const char *tdb_path = cache_path("winbindd_cache.tdb");
4099 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4100 smb_panic_fn = validate_panic;
4103 if (wcache == NULL || wcache->tdb == NULL) {
4104 ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
4106 ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
4110 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4114 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4116 smb_panic_fn = smb_panic;
4120 bool winbindd_cache_validate_and_initialize(void)
4122 close_winbindd_cache();
4124 if (lp_winbind_offline_logon()) {
4125 if (winbindd_validate_cache() < 0) {
4126 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4127 "could be restored.\n"));
4131 return initialize_winbindd_cache();
4134 /*********************************************************************
4135 ********************************************************************/
4137 static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
4138 struct winbindd_tdc_domain **domains,
4139 size_t *num_domains )
4141 struct winbindd_tdc_domain *list = NULL;
4144 bool set_only = false;
4146 /* don't allow duplicates */
4151 for ( i=0; i< (*num_domains); i++ ) {
4152 if ( strequal( new_dom->name, list[i].domain_name ) ) {
4153 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4164 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, 1 );
4167 list = TALLOC_REALLOC_ARRAY( *domains, *domains,
4168 struct winbindd_tdc_domain,
4173 ZERO_STRUCT( list[idx] );
4179 list[idx].domain_name = talloc_strdup( list, new_dom->name );
4180 list[idx].dns_name = talloc_strdup( list, new_dom->alt_name );
4182 if ( !is_null_sid( &new_dom->sid ) ) {
4183 sid_copy( &list[idx].sid, &new_dom->sid );
4185 sid_copy(&list[idx].sid, &global_sid_NULL);
4188 if ( new_dom->domain_flags != 0x0 )
4189 list[idx].trust_flags = new_dom->domain_flags;
4191 if ( new_dom->domain_type != 0x0 )
4192 list[idx].trust_type = new_dom->domain_type;
4194 if ( new_dom->domain_trust_attribs != 0x0 )
4195 list[idx].trust_attribs = new_dom->domain_trust_attribs;
4199 *num_domains = idx + 1;
4205 /*********************************************************************
4206 ********************************************************************/
4208 static TDB_DATA make_tdc_key( const char *domain_name )
4210 char *keystr = NULL;
4211 TDB_DATA key = { NULL, 0 };
4213 if ( !domain_name ) {
4214 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4218 if (asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name ) == -1) {
4221 key = string_term_tdb_data(keystr);
4226 /*********************************************************************
4227 ********************************************************************/
4229 static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
4231 unsigned char **buf )
4233 unsigned char *buffer = NULL;
4238 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4246 /* Store the number of array items first */
4247 len += tdb_pack( buffer+len, buflen-len, "d",
4250 /* now pack each domain trust record */
4251 for ( i=0; i<num_domains; i++ ) {
4256 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4257 domains[i].domain_name,
4258 domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
4261 len += tdb_pack( buffer+len, buflen-len, "fffddd",
4262 domains[i].domain_name,
4263 domains[i].dns_name,
4264 sid_to_fstring(tmp, &domains[i].sid),
4265 domains[i].trust_flags,
4266 domains[i].trust_attribs,
4267 domains[i].trust_type );
4270 if ( buflen < len ) {
4272 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
4273 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4287 /*********************************************************************
4288 ********************************************************************/
4290 static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
4291 struct winbindd_tdc_domain **domains )
4293 fstring domain_name, dns_name, sid_string;
4294 uint32 type, attribs, flags;
4298 struct winbindd_tdc_domain *list = NULL;
4300 /* get the number of domains */
4301 len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
4303 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4307 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, num_domains );
4309 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4313 for ( i=0; i<num_domains; i++ ) {
4314 len += tdb_unpack( buf+len, buflen-len, "fffddd",
4323 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4324 TALLOC_FREE( list );
4328 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4329 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4330 domain_name, dns_name, sid_string,
4331 flags, attribs, type));
4333 list[i].domain_name = talloc_strdup( list, domain_name );
4334 list[i].dns_name = talloc_strdup( list, dns_name );
4335 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
4336 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4339 list[i].trust_flags = flags;
4340 list[i].trust_attribs = attribs;
4341 list[i].trust_type = type;
4349 /*********************************************************************
4350 ********************************************************************/
4352 static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
4354 TDB_DATA key = make_tdc_key( lp_workgroup() );
4355 TDB_DATA data = { NULL, 0 };
4361 /* See if we were asked to delete the cache entry */
4364 ret = tdb_delete( wcache->tdb, key );
4368 data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
4375 ret = tdb_store( wcache->tdb, key, data, 0 );
4378 SAFE_FREE( data.dptr );
4379 SAFE_FREE( key.dptr );
4381 return ( ret != -1 );
4384 /*********************************************************************
4385 ********************************************************************/
4387 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
4389 TDB_DATA key = make_tdc_key( lp_workgroup() );
4390 TDB_DATA data = { NULL, 0 };
4398 data = tdb_fetch( wcache->tdb, key );
4400 SAFE_FREE( key.dptr );
4405 *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
4407 SAFE_FREE( data.dptr );
4415 /*********************************************************************
4416 ********************************************************************/
4418 bool wcache_tdc_add_domain( struct winbindd_domain *domain )
4420 struct winbindd_tdc_domain *dom_list = NULL;
4421 size_t num_domains = 0;
4424 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4425 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4426 domain->name, domain->alt_name,
4427 sid_string_dbg(&domain->sid),
4428 domain->domain_flags,
4429 domain->domain_trust_attribs,
4430 domain->domain_type));
4432 if ( !init_wcache() ) {
4436 /* fetch the list */
4438 wcache_tdc_fetch_list( &dom_list, &num_domains );
4440 /* add the new domain */
4442 if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
4446 /* pack the domain */
4448 if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
4456 TALLOC_FREE( dom_list );
4461 /*********************************************************************
4462 ********************************************************************/
4464 struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
4466 struct winbindd_tdc_domain *dom_list = NULL;
4467 size_t num_domains = 0;
4469 struct winbindd_tdc_domain *d = NULL;
4471 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
4473 if ( !init_wcache() ) {
4477 /* fetch the list */
4479 wcache_tdc_fetch_list( &dom_list, &num_domains );
4481 for ( i=0; i<num_domains; i++ ) {
4482 if ( strequal(name, dom_list[i].domain_name) ||
4483 strequal(name, dom_list[i].dns_name) )
4485 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4488 d = TALLOC_P( ctx, struct winbindd_tdc_domain );
4492 d->domain_name = talloc_strdup( d, dom_list[i].domain_name );
4493 d->dns_name = talloc_strdup( d, dom_list[i].dns_name );
4494 sid_copy( &d->sid, &dom_list[i].sid );
4495 d->trust_flags = dom_list[i].trust_flags;
4496 d->trust_type = dom_list[i].trust_type;
4497 d->trust_attribs = dom_list[i].trust_attribs;
4503 TALLOC_FREE( dom_list );
4509 /*********************************************************************
4510 ********************************************************************/
4512 void wcache_tdc_clear( void )
4514 if ( !init_wcache() )
4517 wcache_tdc_store_list( NULL, 0 );
4523 /*********************************************************************
4524 ********************************************************************/
4526 static void wcache_save_user_pwinfo(struct winbindd_domain *domain,
4528 const struct dom_sid *user_sid,
4529 const char *homedir,
4534 struct cache_entry *centry;
4537 if ( (centry = centry_start(domain, status)) == NULL )
4540 centry_put_string( centry, homedir );
4541 centry_put_string( centry, shell );
4542 centry_put_string( centry, gecos );
4543 centry_put_uint32( centry, gid );
4545 centry_end(centry, "NSS/PWINFO/%s", sid_to_fstring(tmp, user_sid) );
4547 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid) ));
4549 centry_free(centry);
4552 NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
4553 const struct dom_sid *user_sid,
4555 ADS_STRUCT *ads, LDAPMessage *msg,
4556 const char **homedir, const char **shell,
4557 const char **gecos, gid_t *p_gid)
4559 struct winbind_cache *cache = get_cache(domain);
4560 struct cache_entry *centry = NULL;
4567 centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s",
4568 sid_to_fstring(tmp, user_sid));
4573 *homedir = centry_string( centry, ctx );
4574 *shell = centry_string( centry, ctx );
4575 *gecos = centry_string( centry, ctx );
4576 *p_gid = centry_uint32( centry );
4578 centry_free(centry);
4580 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4581 sid_string_dbg(user_sid)));
4583 return NT_STATUS_OK;
4587 nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg,
4588 homedir, shell, gecos, p_gid );
4590 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status)));
4592 if ( NT_STATUS_IS_OK(nt_status) ) {
4593 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir));
4594 DEBUGADD(10, ("\tshell = '%s'\n", *shell));
4595 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos));
4596 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid));
4598 wcache_save_user_pwinfo( domain, nt_status, user_sid,
4599 *homedir, *shell, *gecos, *p_gid );
4602 if ( NT_STATUS_EQUAL( nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
4603 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4605 set_domain_offline( domain );
4612 /* the cache backend methods are exposed via this structure */
4613 struct winbindd_methods cache_methods = {
4631 static bool wcache_ndr_key(TALLOC_CTX *mem_ctx, char *domain_name,
4632 uint32_t opnum, const DATA_BLOB *req,
4638 key = talloc_asprintf(mem_ctx, "NDR/%s/%d/", domain_name, (int)opnum);
4642 keylen = talloc_get_size(key) - 1;
4644 key = talloc_realloc(mem_ctx, key, char, keylen + req->length);
4648 memcpy(key + keylen, req->data, req->length);
4650 pkey->dptr = (uint8_t *)key;
4651 pkey->dsize = talloc_get_size(key);
4655 static bool wcache_opnum_cacheable(uint32_t opnum)
4658 case NDR_WBINT_PING:
4659 case NDR_WBINT_QUERYSEQUENCENUMBER:
4660 case NDR_WBINT_ALLOCATEUID:
4661 case NDR_WBINT_ALLOCATEGID:
4662 case NDR_WBINT_CHECKMACHINEACCOUNT:
4663 case NDR_WBINT_CHANGEMACHINEACCOUNT:
4664 case NDR_WBINT_PINGDC:
4670 bool wcache_fetch_ndr(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
4671 uint32_t opnum, const DATA_BLOB *req, DATA_BLOB *resp)
4676 if (!wcache_opnum_cacheable(opnum)) {
4680 if (wcache->tdb == NULL) {
4684 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4687 data = tdb_fetch(wcache->tdb, key);
4688 TALLOC_FREE(key.dptr);
4690 if (data.dptr == NULL) {
4693 if (data.dsize < 4) {
4697 if (!is_domain_offline(domain)) {
4698 uint32_t entry_seqnum, dom_seqnum, last_check;
4700 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum,
4704 entry_seqnum = IVAL(data.dptr, 0);
4705 if (entry_seqnum != dom_seqnum) {
4706 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4707 (int)entry_seqnum));
4712 resp->data = (uint8_t *)talloc_memdup(mem_ctx, data.dptr + 4,
4714 if (resp->data == NULL) {
4715 DEBUG(10, ("talloc failed\n"));
4718 resp->length = data.dsize - 4;
4722 SAFE_FREE(data.dptr);
4726 void wcache_store_ndr(struct winbindd_domain *domain, uint32_t opnum,
4727 const DATA_BLOB *req, const DATA_BLOB *resp)
4730 uint32_t dom_seqnum, last_check;
4732 if (!wcache_opnum_cacheable(opnum)) {
4736 if (wcache->tdb == NULL) {
4740 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum, &last_check)) {
4741 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4746 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4750 data.dsize = resp->length + 4;
4751 data.dptr = talloc_array(key.dptr, uint8_t, data.dsize);
4752 if (data.dptr == NULL) {
4756 SIVAL(data.dptr, 0, dom_seqnum);
4757 memcpy(data.dptr+4, resp->data, resp->length);
4759 tdb_store(wcache->tdb, key, data, 0);
4762 TALLOC_FREE(key.dptr);