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"
33 #include "../libcli/security/security.h"
36 #define DBGC_CLASS DBGC_WINBIND
38 #define WINBINDD_CACHE_VERSION 1
39 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
41 extern struct winbindd_methods reconnect_methods;
43 extern struct winbindd_methods ads_methods;
45 extern struct winbindd_methods builtin_passdb_methods;
46 extern struct winbindd_methods sam_passdb_methods;
49 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
50 * Here are the list of entry types that are *not* stored
51 * as form struct cache_entry in the cache.
54 static const char *non_centry_keys[] = {
59 WINBINDD_CACHE_VERSION_KEYSTR,
63 /************************************************************************
64 Is this key a non-centry type ?
65 ************************************************************************/
67 static bool is_non_centry_key(TDB_DATA kbuf)
71 if (kbuf.dptr == NULL || kbuf.dsize == 0) {
74 for (i = 0; non_centry_keys[i] != NULL; i++) {
75 size_t namelen = strlen(non_centry_keys[i]);
76 if (kbuf.dsize < namelen) {
79 if (strncmp(non_centry_keys[i], (const char *)kbuf.dptr, namelen) == 0) {
86 /* Global online/offline state - False when online. winbindd starts up online
87 and sets this to true if the first query fails and there's an entry in
88 the cache tdb telling us to stay offline. */
90 static bool global_winbindd_offline_state;
92 struct winbind_cache {
98 uint32 sequence_number;
103 void (*smb_panic_fn)(const char *const why) = smb_panic;
105 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
107 static struct winbind_cache *wcache;
109 /* get the winbind_cache structure */
110 static struct winbind_cache *get_cache(struct winbindd_domain *domain)
112 struct winbind_cache *ret = wcache;
114 /* We have to know what type of domain we are dealing with first. */
116 if (domain->internal) {
117 domain->backend = &builtin_passdb_methods;
118 domain->initialized = True;
121 if (strequal(domain->name, get_global_sam_name()) &&
122 dom_sid_equal(&domain->sid, get_global_sam_sid())) {
123 domain->backend = &sam_passdb_methods;
124 domain->initialized = True;
127 if ( !domain->initialized ) {
128 init_dc_connection( domain );
132 OK. listen up becasue I'm only going to say this once.
133 We have the following scenarios to consider
134 (a) trusted AD domains on a Samba DC,
135 (b) trusted AD domains and we are joined to a non-kerberos domain
136 (c) trusted AD domains and we are joined to a kerberos (AD) domain
138 For (a) we can always contact the trusted domain using krb5
139 since we have the domain trust account password
141 For (b) we can only use RPC since we have no way of
142 getting a krb5 ticket in our own domain
144 For (c) we can always use krb5 since we have a kerberos trust
149 if (!domain->backend) {
151 struct winbindd_domain *our_domain = domain;
153 /* find our domain first so we can figure out if we
154 are joined to a kerberized domain */
156 if ( !domain->primary )
157 our_domain = find_our_domain();
159 if ((our_domain->active_directory || IS_DC)
160 && domain->active_directory
161 && !lp_winbind_rpc_only()) {
162 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain->name));
163 domain->backend = &ads_methods;
165 #endif /* HAVE_ADS */
166 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain->name));
167 domain->backend = &reconnect_methods;
170 #endif /* HAVE_ADS */
176 ret = SMB_XMALLOC_P(struct winbind_cache);
180 wcache_flush_cache();
186 free a centry structure
188 static void centry_free(struct cache_entry *centry)
192 SAFE_FREE(centry->data);
196 static bool centry_check_bytes(struct cache_entry *centry, size_t nbytes)
198 if (centry->len - centry->ofs < nbytes) {
199 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
200 (unsigned int)nbytes,
201 centry->len - centry->ofs));
208 pull a uint32 from a cache entry
210 static uint32 centry_uint32(struct cache_entry *centry)
214 if (!centry_check_bytes(centry, 4)) {
215 smb_panic_fn("centry_uint32");
217 ret = IVAL(centry->data, centry->ofs);
223 pull a uint16 from a cache entry
225 static uint16 centry_uint16(struct cache_entry *centry)
228 if (!centry_check_bytes(centry, 2)) {
229 smb_panic_fn("centry_uint16");
231 ret = CVAL(centry->data, centry->ofs);
237 pull a uint8 from a cache entry
239 static uint8 centry_uint8(struct cache_entry *centry)
242 if (!centry_check_bytes(centry, 1)) {
243 smb_panic_fn("centry_uint8");
245 ret = CVAL(centry->data, centry->ofs);
251 pull a NTTIME from a cache entry
253 static NTTIME centry_nttime(struct cache_entry *centry)
256 if (!centry_check_bytes(centry, 8)) {
257 smb_panic_fn("centry_nttime");
259 ret = IVAL(centry->data, centry->ofs);
261 ret += (uint64_t)IVAL(centry->data, centry->ofs) << 32;
267 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
269 static time_t centry_time(struct cache_entry *centry)
271 return (time_t)centry_nttime(centry);
274 /* pull a string from a cache entry, using the supplied
277 static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
282 len = centry_uint8(centry);
285 /* a deliberate NULL string */
289 if (!centry_check_bytes(centry, (size_t)len)) {
290 smb_panic_fn("centry_string");
293 ret = TALLOC_ARRAY(mem_ctx, char, len+1);
295 smb_panic_fn("centry_string out of memory\n");
297 memcpy(ret,centry->data + centry->ofs, len);
303 /* pull a hash16 from a cache entry, using the supplied
306 static char *centry_hash16(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
311 len = centry_uint8(centry);
314 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
319 if (!centry_check_bytes(centry, 16)) {
323 ret = TALLOC_ARRAY(mem_ctx, char, 16);
325 smb_panic_fn("centry_hash out of memory\n");
327 memcpy(ret,centry->data + centry->ofs, 16);
332 /* pull a sid from a cache entry, using the supplied
335 static bool centry_sid(struct cache_entry *centry, struct dom_sid *sid)
340 sid_string = centry_string(centry, talloc_tos());
341 if (sid_string == NULL) {
344 ret = string_to_sid(sid, sid_string);
345 TALLOC_FREE(sid_string);
351 pull a NTSTATUS from a cache entry
353 static NTSTATUS centry_ntstatus(struct cache_entry *centry)
357 status = NT_STATUS(centry_uint32(centry));
362 /* the server is considered down if it can't give us a sequence number */
363 static bool wcache_server_down(struct winbindd_domain *domain)
370 ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
373 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
378 static bool wcache_fetch_seqnum(const char *domain_name, uint32_t *seqnum,
379 uint32_t *last_seq_check)
384 if (wcache->tdb == NULL) {
385 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
389 key = talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name);
391 DEBUG(10, ("talloc failed\n"));
395 data = tdb_fetch_bystring(wcache->tdb, key);
398 if (data.dptr == NULL) {
399 DEBUG(10, ("wcache_fetch_seqnum: %s not found\n",
403 if (data.dsize != 8) {
404 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
406 SAFE_FREE(data.dptr);
410 *seqnum = IVAL(data.dptr, 0);
411 *last_seq_check = IVAL(data.dptr, 4);
412 SAFE_FREE(data.dptr);
417 static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
419 uint32 last_check, time_diff;
421 if (!wcache_fetch_seqnum(domain->name, &domain->sequence_number,
423 return NT_STATUS_UNSUCCESSFUL;
425 domain->last_seq_check = last_check;
427 /* have we expired? */
429 time_diff = now - domain->last_seq_check;
430 if ( time_diff > lp_winbind_cache_time() ) {
431 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
432 domain->name, domain->sequence_number,
433 (uint32)domain->last_seq_check));
434 return NT_STATUS_UNSUCCESSFUL;
437 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
438 domain->name, domain->sequence_number,
439 (uint32)domain->last_seq_check));
444 bool wcache_store_seqnum(const char *domain_name, uint32_t seqnum,
445 time_t last_seq_check)
451 if (wcache->tdb == NULL) {
452 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
456 key_str = talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name);
457 if (key_str == NULL) {
458 DEBUG(10, ("talloc_asprintf failed\n"));
462 SIVAL(buf, 0, seqnum);
463 SIVAL(buf, 4, last_seq_check);
465 ret = tdb_store_bystring(wcache->tdb, key_str,
466 make_tdb_data(buf, sizeof(buf)), TDB_REPLACE);
467 TALLOC_FREE(key_str);
469 DEBUG(10, ("tdb_store_bystring failed: %s\n",
470 tdb_errorstr(wcache->tdb)));
471 TALLOC_FREE(key_str);
475 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
476 domain_name, seqnum, (unsigned)last_seq_check));
481 static bool store_cache_seqnum( struct winbindd_domain *domain )
483 return wcache_store_seqnum(domain->name, domain->sequence_number,
484 domain->last_seq_check);
488 refresh the domain sequence number. If force is true
489 then always refresh it, no matter how recently we fetched it
492 static void refresh_sequence_number(struct winbindd_domain *domain, bool force)
496 time_t t = time(NULL);
497 unsigned cache_time = lp_winbind_cache_time();
499 if (is_domain_offline(domain)) {
505 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
506 /* trying to reconnect is expensive, don't do it too often */
507 if (domain->sequence_number == DOM_SEQUENCE_NONE) {
512 time_diff = t - domain->last_seq_check;
514 /* see if we have to refetch the domain sequence number */
515 if (!force && (time_diff < cache_time) &&
516 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
517 NT_STATUS_IS_OK(domain->last_status)) {
518 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
522 /* try to get the sequence number from the tdb cache first */
523 /* this will update the timestamp as well */
525 status = fetch_cache_seqnum( domain, t );
526 if (NT_STATUS_IS_OK(status) &&
527 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
528 NT_STATUS_IS_OK(domain->last_status)) {
532 /* important! make sure that we know if this is a native
533 mode domain or not. And that we can contact it. */
535 if ( winbindd_can_contact_domain( domain ) ) {
536 status = domain->backend->sequence_number(domain,
537 &domain->sequence_number);
539 /* just use the current time */
540 status = NT_STATUS_OK;
541 domain->sequence_number = time(NULL);
545 /* the above call could have set our domain->backend to NULL when
546 * coming from offline to online mode, make sure to reinitialize the
547 * backend - Guenther */
550 if (!NT_STATUS_IS_OK(status)) {
551 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status)));
552 domain->sequence_number = DOM_SEQUENCE_NONE;
555 domain->last_status = status;
556 domain->last_seq_check = time(NULL);
558 /* save the new sequence number in the cache */
559 store_cache_seqnum( domain );
562 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
563 domain->name, domain->sequence_number));
569 decide if a cache entry has expired
571 static bool centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
573 /* If we've been told to be offline - stay in that state... */
574 if (lp_winbind_offline_logon() && global_winbindd_offline_state) {
575 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
576 keystr, domain->name ));
580 /* when the domain is offline return the cached entry.
581 * This deals with transient offline states... */
583 if (!domain->online) {
584 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
585 keystr, domain->name ));
589 /* if the server is OK and our cache entry came from when it was down then
590 the entry is invalid */
591 if ((domain->sequence_number != DOM_SEQUENCE_NONE) &&
592 (centry->sequence_number == DOM_SEQUENCE_NONE)) {
593 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
594 keystr, domain->name ));
598 /* if the server is down or the cache entry is not older than the
599 current sequence number then it is OK */
600 if (wcache_server_down(domain) ||
601 centry->sequence_number == domain->sequence_number) {
602 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
603 keystr, domain->name ));
607 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
608 keystr, domain->name ));
614 static struct cache_entry *wcache_fetch_raw(char *kstr)
617 struct cache_entry *centry;
620 key = string_tdb_data(kstr);
621 data = tdb_fetch(wcache->tdb, key);
627 centry = SMB_XMALLOC_P(struct cache_entry);
628 centry->data = (unsigned char *)data.dptr;
629 centry->len = data.dsize;
632 if (centry->len < 8) {
633 /* huh? corrupt cache? */
634 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr));
639 centry->status = centry_ntstatus(centry);
640 centry->sequence_number = centry_uint32(centry);
645 static bool is_my_own_sam_domain(struct winbindd_domain *domain)
647 if (strequal(domain->name, get_global_sam_name()) &&
648 dom_sid_equal(&domain->sid, get_global_sam_sid())) {
655 static bool is_builtin_domain(struct winbindd_domain *domain)
657 if (strequal(domain->name, "BUILTIN") &&
658 dom_sid_equal(&domain->sid, &global_sid_Builtin)) {
666 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
667 number and return status
669 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
670 struct winbindd_domain *domain,
671 const char *format, ...) PRINTF_ATTRIBUTE(3,4);
672 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
673 struct winbindd_domain *domain,
674 const char *format, ...)
678 struct cache_entry *centry;
680 if (!winbindd_use_cache() ||
681 is_my_own_sam_domain(domain) ||
682 is_builtin_domain(domain)) {
686 refresh_sequence_number(domain, false);
688 va_start(ap, format);
689 smb_xvasprintf(&kstr, format, ap);
692 centry = wcache_fetch_raw(kstr);
693 if (centry == NULL) {
698 if (centry_expired(domain, kstr, centry)) {
700 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
701 kstr, domain->name ));
708 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
709 kstr, domain->name ));
715 static void wcache_delete(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
716 static void wcache_delete(const char *format, ...)
722 va_start(ap, format);
723 smb_xvasprintf(&kstr, format, ap);
726 key = string_tdb_data(kstr);
728 tdb_delete(wcache->tdb, key);
733 make sure we have at least len bytes available in a centry
735 static void centry_expand(struct cache_entry *centry, uint32 len)
737 if (centry->len - centry->ofs >= len)
740 centry->data = SMB_REALLOC_ARRAY(centry->data, unsigned char,
743 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
744 smb_panic_fn("out of memory in centry_expand");
749 push a uint32 into a centry
751 static void centry_put_uint32(struct cache_entry *centry, uint32 v)
753 centry_expand(centry, 4);
754 SIVAL(centry->data, centry->ofs, v);
759 push a uint16 into a centry
761 static void centry_put_uint16(struct cache_entry *centry, uint16 v)
763 centry_expand(centry, 2);
764 SIVAL(centry->data, centry->ofs, v);
769 push a uint8 into a centry
771 static void centry_put_uint8(struct cache_entry *centry, uint8 v)
773 centry_expand(centry, 1);
774 SCVAL(centry->data, centry->ofs, v);
779 push a string into a centry
781 static void centry_put_string(struct cache_entry *centry, const char *s)
786 /* null strings are marked as len 0xFFFF */
787 centry_put_uint8(centry, 0xFF);
792 /* can't handle more than 254 char strings. Truncating is probably best */
794 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len));
797 centry_put_uint8(centry, len);
798 centry_expand(centry, len);
799 memcpy(centry->data + centry->ofs, s, len);
804 push a 16 byte hash into a centry - treat as 16 byte string.
806 static void centry_put_hash16(struct cache_entry *centry, const uint8 val[16])
808 centry_put_uint8(centry, 16);
809 centry_expand(centry, 16);
810 memcpy(centry->data + centry->ofs, val, 16);
814 static void centry_put_sid(struct cache_entry *centry, const struct dom_sid *sid)
817 centry_put_string(centry, sid_to_fstring(sid_string, sid));
822 put NTSTATUS into a centry
824 static void centry_put_ntstatus(struct cache_entry *centry, NTSTATUS status)
826 uint32 status_value = NT_STATUS_V(status);
827 centry_put_uint32(centry, status_value);
832 push a NTTIME into a centry
834 static void centry_put_nttime(struct cache_entry *centry, NTTIME nt)
836 centry_expand(centry, 8);
837 SIVAL(centry->data, centry->ofs, nt & 0xFFFFFFFF);
839 SIVAL(centry->data, centry->ofs, nt >> 32);
844 push a time_t into a centry - use a 64 bit size.
845 NTTIME here is being used as a convenient 64-bit size.
847 static void centry_put_time(struct cache_entry *centry, time_t t)
849 NTTIME nt = (NTTIME)t;
850 centry_put_nttime(centry, nt);
854 start a centry for output. When finished, call centry_end()
856 struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status)
858 struct cache_entry *centry;
863 centry = SMB_XMALLOC_P(struct cache_entry);
865 centry->len = 8192; /* reasonable default */
866 centry->data = SMB_XMALLOC_ARRAY(uint8, centry->len);
868 centry->sequence_number = domain->sequence_number;
869 centry_put_ntstatus(centry, status);
870 centry_put_uint32(centry, centry->sequence_number);
875 finish a centry and write it to the tdb
877 static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
878 static void centry_end(struct cache_entry *centry, const char *format, ...)
884 if (!winbindd_use_cache()) {
888 va_start(ap, format);
889 smb_xvasprintf(&kstr, format, ap);
892 key = string_tdb_data(kstr);
893 data.dptr = centry->data;
894 data.dsize = centry->ofs;
896 tdb_store(wcache->tdb, key, data, TDB_REPLACE);
900 static void wcache_save_name_to_sid(struct winbindd_domain *domain,
901 NTSTATUS status, const char *domain_name,
902 const char *name, const struct dom_sid *sid,
903 enum lsa_SidType type)
905 struct cache_entry *centry;
908 centry = centry_start(domain, status);
911 centry_put_uint32(centry, type);
912 centry_put_sid(centry, sid);
913 fstrcpy(uname, name);
915 centry_end(centry, "NS/%s/%s", domain_name, uname);
916 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name,
917 uname, sid_string_dbg(sid), nt_errstr(status)));
921 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
922 const struct dom_sid *sid, const char *domain_name, const char *name, enum lsa_SidType type)
924 struct cache_entry *centry;
927 centry = centry_start(domain, status);
931 if (NT_STATUS_IS_OK(status)) {
932 centry_put_uint32(centry, type);
933 centry_put_string(centry, domain_name);
934 centry_put_string(centry, name);
937 centry_end(centry, "SN/%s", sid_to_fstring(sid_string, sid));
938 DEBUG(10,("wcache_save_sid_to_name: %s -> %s (%s)\n", sid_string,
939 name, nt_errstr(status)));
944 static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status,
945 struct wbint_userinfo *info)
947 struct cache_entry *centry;
950 if (is_null_sid(&info->user_sid)) {
954 centry = centry_start(domain, status);
957 centry_put_string(centry, info->acct_name);
958 centry_put_string(centry, info->full_name);
959 centry_put_string(centry, info->homedir);
960 centry_put_string(centry, info->shell);
961 centry_put_uint32(centry, info->primary_gid);
962 centry_put_sid(centry, &info->user_sid);
963 centry_put_sid(centry, &info->group_sid);
964 centry_end(centry, "U/%s", sid_to_fstring(sid_string,
966 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
970 static void wcache_save_lockout_policy(struct winbindd_domain *domain,
972 struct samr_DomInfo12 *lockout_policy)
974 struct cache_entry *centry;
976 centry = centry_start(domain, status);
980 centry_put_nttime(centry, lockout_policy->lockout_duration);
981 centry_put_nttime(centry, lockout_policy->lockout_window);
982 centry_put_uint16(centry, lockout_policy->lockout_threshold);
984 centry_end(centry, "LOC_POL/%s", domain->name);
986 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
993 static void wcache_save_password_policy(struct winbindd_domain *domain,
995 struct samr_DomInfo1 *policy)
997 struct cache_entry *centry;
999 centry = centry_start(domain, status);
1003 centry_put_uint16(centry, policy->min_password_length);
1004 centry_put_uint16(centry, policy->password_history_length);
1005 centry_put_uint32(centry, policy->password_properties);
1006 centry_put_nttime(centry, policy->max_password_age);
1007 centry_put_nttime(centry, policy->min_password_age);
1009 centry_end(centry, "PWD_POL/%s", domain->name);
1011 DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
1013 centry_free(centry);
1016 /***************************************************************************
1017 ***************************************************************************/
1019 static void wcache_save_username_alias(struct winbindd_domain *domain,
1021 const char *name, const char *alias)
1023 struct cache_entry *centry;
1026 if ( (centry = centry_start(domain, status)) == NULL )
1029 centry_put_string( centry, alias );
1031 fstrcpy(uname, name);
1033 centry_end(centry, "NSS/NA/%s", uname);
1035 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name, alias ));
1037 centry_free(centry);
1040 static void wcache_save_alias_username(struct winbindd_domain *domain,
1042 const char *alias, const char *name)
1044 struct cache_entry *centry;
1047 if ( (centry = centry_start(domain, status)) == NULL )
1050 centry_put_string( centry, name );
1052 fstrcpy(uname, alias);
1054 centry_end(centry, "NSS/AN/%s", uname);
1056 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias, name ));
1058 centry_free(centry);
1061 /***************************************************************************
1062 ***************************************************************************/
1064 NTSTATUS resolve_username_to_alias( TALLOC_CTX *mem_ctx,
1065 struct winbindd_domain *domain,
1066 const char *name, char **alias )
1068 struct winbind_cache *cache = get_cache(domain);
1069 struct cache_entry *centry = NULL;
1073 if ( domain->internal )
1074 return NT_STATUS_NOT_SUPPORTED;
1079 if ( (upper_name = SMB_STRDUP(name)) == NULL )
1080 return NT_STATUS_NO_MEMORY;
1081 strupper_m(upper_name);
1083 centry = wcache_fetch(cache, domain, "NSS/NA/%s", upper_name);
1085 SAFE_FREE( upper_name );
1090 status = centry->status;
1092 if (!NT_STATUS_IS_OK(status)) {
1093 centry_free(centry);
1097 *alias = centry_string( centry, mem_ctx );
1099 centry_free(centry);
1101 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1102 name, *alias ? *alias : "(none)"));
1104 return (*alias) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1108 /* If its not in cache and we are offline, then fail */
1110 if ( get_global_winbindd_state_offline() || !domain->online ) {
1111 DEBUG(8,("resolve_username_to_alias: rejecting query "
1112 "in offline mode\n"));
1113 return NT_STATUS_NOT_FOUND;
1116 status = nss_map_to_alias( mem_ctx, domain->name, name, alias );
1118 if ( NT_STATUS_IS_OK( status ) ) {
1119 wcache_save_username_alias(domain, status, name, *alias);
1122 if ( NT_STATUS_EQUAL( status, NT_STATUS_NONE_MAPPED ) ) {
1123 wcache_save_username_alias(domain, status, name, "(NULL)");
1126 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1127 nt_errstr(status)));
1129 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1130 set_domain_offline( domain );
1136 /***************************************************************************
1137 ***************************************************************************/
1139 NTSTATUS resolve_alias_to_username( TALLOC_CTX *mem_ctx,
1140 struct winbindd_domain *domain,
1141 const char *alias, char **name )
1143 struct winbind_cache *cache = get_cache(domain);
1144 struct cache_entry *centry = NULL;
1148 if ( domain->internal )
1149 return NT_STATUS_NOT_SUPPORTED;
1154 if ( (upper_name = SMB_STRDUP(alias)) == NULL )
1155 return NT_STATUS_NO_MEMORY;
1156 strupper_m(upper_name);
1158 centry = wcache_fetch(cache, domain, "NSS/AN/%s", upper_name);
1160 SAFE_FREE( upper_name );
1165 status = centry->status;
1167 if (!NT_STATUS_IS_OK(status)) {
1168 centry_free(centry);
1172 *name = centry_string( centry, mem_ctx );
1174 centry_free(centry);
1176 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1177 alias, *name ? *name : "(none)"));
1179 return (*name) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1183 /* If its not in cache and we are offline, then fail */
1185 if ( get_global_winbindd_state_offline() || !domain->online ) {
1186 DEBUG(8,("resolve_alias_to_username: rejecting query "
1187 "in offline mode\n"));
1188 return NT_STATUS_NOT_FOUND;
1191 /* an alias cannot contain a domain prefix or '@' */
1193 if (strchr(alias, '\\') || strchr(alias, '@')) {
1194 DEBUG(10,("resolve_alias_to_username: skipping fully "
1195 "qualified name %s\n", alias));
1196 return NT_STATUS_OBJECT_NAME_INVALID;
1199 status = nss_map_from_alias( mem_ctx, domain->name, alias, name );
1201 if ( NT_STATUS_IS_OK( status ) ) {
1202 wcache_save_alias_username( domain, status, alias, *name );
1205 if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1206 wcache_save_alias_username(domain, status, alias, "(NULL)");
1209 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1210 nt_errstr(status)));
1212 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1213 set_domain_offline( domain );
1219 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const struct dom_sid *sid)
1221 struct winbind_cache *cache = get_cache(domain);
1223 fstring key_str, tmp;
1227 return NT_STATUS_INTERNAL_DB_ERROR;
1230 if (is_null_sid(sid)) {
1231 return NT_STATUS_INVALID_SID;
1234 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1235 return NT_STATUS_INVALID_SID;
1238 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
1240 data = tdb_fetch(cache->tdb, string_tdb_data(key_str));
1242 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1245 SAFE_FREE(data.dptr);
1246 return NT_STATUS_OK;
1249 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1250 as new salted ones. */
1252 NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
1253 TALLOC_CTX *mem_ctx,
1254 const struct dom_sid *sid,
1255 const uint8 **cached_nt_pass,
1256 const uint8 **cached_salt)
1258 struct winbind_cache *cache = get_cache(domain);
1259 struct cache_entry *centry = NULL;
1266 return NT_STATUS_INTERNAL_DB_ERROR;
1269 if (is_null_sid(sid)) {
1270 return NT_STATUS_INVALID_SID;
1273 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1274 return NT_STATUS_INVALID_SID;
1277 /* Try and get a salted cred first. If we can't
1278 fall back to an unsalted cred. */
1280 centry = wcache_fetch(cache, domain, "CRED/%s",
1281 sid_to_fstring(tmp, sid));
1283 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1284 sid_string_dbg(sid)));
1285 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1288 t = centry_time(centry);
1290 /* In the salted case this isn't actually the nt_hash itself,
1291 but the MD5 of the salt + nt_hash. Let the caller
1292 sort this out. It can tell as we only return the cached_salt
1293 if we are returning a salted cred. */
1295 *cached_nt_pass = (const uint8 *)centry_hash16(centry, mem_ctx);
1296 if (*cached_nt_pass == NULL) {
1299 sid_to_fstring(sidstr, sid);
1301 /* Bad (old) cred cache. Delete and pretend we
1303 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1305 wcache_delete("CRED/%s", sidstr);
1306 centry_free(centry);
1307 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1310 /* We only have 17 bytes more data in the salted cred case. */
1311 if (centry->len - centry->ofs == 17) {
1312 *cached_salt = (const uint8 *)centry_hash16(centry, mem_ctx);
1314 *cached_salt = NULL;
1317 dump_data_pw("cached_nt_pass", *cached_nt_pass, NT_HASH_LEN);
1319 dump_data_pw("cached_salt", *cached_salt, NT_HASH_LEN);
1322 status = centry->status;
1324 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1325 sid_string_dbg(sid), nt_errstr(status) ));
1327 centry_free(centry);
1331 /* Store creds for a SID - only writes out new salted ones. */
1333 NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
1334 const struct dom_sid *sid,
1335 const uint8 nt_pass[NT_HASH_LEN])
1337 struct cache_entry *centry;
1340 uint8 cred_salt[NT_HASH_LEN];
1341 uint8 salted_hash[NT_HASH_LEN];
1343 if (is_null_sid(sid)) {
1344 return NT_STATUS_INVALID_SID;
1347 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1348 return NT_STATUS_INVALID_SID;
1351 centry = centry_start(domain, NT_STATUS_OK);
1353 return NT_STATUS_INTERNAL_DB_ERROR;
1356 dump_data_pw("nt_pass", nt_pass, NT_HASH_LEN);
1358 centry_put_time(centry, time(NULL));
1360 /* Create a salt and then salt the hash. */
1361 generate_random_buffer(cred_salt, NT_HASH_LEN);
1362 E_md5hash(cred_salt, nt_pass, salted_hash);
1364 centry_put_hash16(centry, salted_hash);
1365 centry_put_hash16(centry, cred_salt);
1366 centry_end(centry, "CRED/%s", sid_to_fstring(sid_string, sid));
1368 DEBUG(10,("wcache_save_creds: %s\n", sid_string));
1370 centry_free(centry);
1372 return NT_STATUS_OK;
1376 /* Query display info. This is the basic user list fn */
1377 static NTSTATUS query_user_list(struct winbindd_domain *domain,
1378 TALLOC_CTX *mem_ctx,
1379 uint32 *num_entries,
1380 struct wbint_userinfo **info)
1382 struct winbind_cache *cache = get_cache(domain);
1383 struct cache_entry *centry = NULL;
1385 unsigned int i, retry;
1386 bool old_status = domain->online;
1391 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1396 *num_entries = centry_uint32(centry);
1398 if (*num_entries == 0)
1401 (*info) = TALLOC_ARRAY(mem_ctx, struct wbint_userinfo, *num_entries);
1403 smb_panic_fn("query_user_list out of memory");
1405 for (i=0; i<(*num_entries); i++) {
1406 (*info)[i].acct_name = centry_string(centry, mem_ctx);
1407 (*info)[i].full_name = centry_string(centry, mem_ctx);
1408 (*info)[i].homedir = centry_string(centry, mem_ctx);
1409 (*info)[i].shell = centry_string(centry, mem_ctx);
1410 centry_sid(centry, &(*info)[i].user_sid);
1411 centry_sid(centry, &(*info)[i].group_sid);
1415 status = centry->status;
1417 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1418 domain->name, nt_errstr(status) ));
1420 centry_free(centry);
1427 /* Return status value returned by seq number check */
1429 if (!NT_STATUS_IS_OK(domain->last_status))
1430 return domain->last_status;
1432 /* Put the query_user_list() in a retry loop. There appears to be
1433 * some bug either with Windows 2000 or Samba's handling of large
1434 * rpc replies. This manifests itself as sudden disconnection
1435 * at a random point in the enumeration of a large (60k) user list.
1436 * The retry loop simply tries the operation again. )-: It's not
1437 * pretty but an acceptable workaround until we work out what the
1438 * real problem is. */
1443 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1446 status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
1447 if (!NT_STATUS_IS_OK(status)) {
1448 DEBUG(3, ("query_user_list: returned 0x%08x, "
1449 "retrying\n", NT_STATUS_V(status)));
1451 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1452 DEBUG(3, ("query_user_list: flushing "
1453 "connection cache\n"));
1454 invalidate_cm_connection(&domain->conn);
1456 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1457 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1458 if (!domain->internal && old_status) {
1459 set_domain_offline(domain);
1461 /* store partial response. */
1462 if (*num_entries > 0) {
1464 * humm, what about the status used for cache?
1465 * Should it be NT_STATUS_OK?
1470 * domain is offline now, and there is no user entries,
1471 * try to fetch from cache again.
1473 if (cache->tdb && !domain->online && !domain->internal && old_status) {
1474 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1475 /* partial response... */
1479 goto do_fetch_cache;
1486 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
1490 refresh_sequence_number(domain, false);
1491 if (!NT_STATUS_IS_OK(status)) {
1494 centry = centry_start(domain, status);
1497 centry_put_uint32(centry, *num_entries);
1498 for (i=0; i<(*num_entries); i++) {
1499 centry_put_string(centry, (*info)[i].acct_name);
1500 centry_put_string(centry, (*info)[i].full_name);
1501 centry_put_string(centry, (*info)[i].homedir);
1502 centry_put_string(centry, (*info)[i].shell);
1503 centry_put_sid(centry, &(*info)[i].user_sid);
1504 centry_put_sid(centry, &(*info)[i].group_sid);
1505 if (domain->backend && domain->backend->consistent) {
1506 /* when the backend is consistent we can pre-prime some mappings */
1507 wcache_save_name_to_sid(domain, NT_STATUS_OK,
1509 (*info)[i].acct_name,
1510 &(*info)[i].user_sid,
1512 wcache_save_sid_to_name(domain, NT_STATUS_OK,
1513 &(*info)[i].user_sid,
1515 (*info)[i].acct_name,
1517 wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
1520 centry_end(centry, "UL/%s", domain->name);
1521 centry_free(centry);
1527 /* list all domain groups */
1528 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
1529 TALLOC_CTX *mem_ctx,
1530 uint32 *num_entries,
1531 struct acct_info **info)
1533 struct winbind_cache *cache = get_cache(domain);
1534 struct cache_entry *centry = NULL;
1539 old_status = domain->online;
1543 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1548 *num_entries = centry_uint32(centry);
1550 if (*num_entries == 0)
1553 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1555 smb_panic_fn("enum_dom_groups out of memory");
1557 for (i=0; i<(*num_entries); i++) {
1558 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1559 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1560 (*info)[i].rid = centry_uint32(centry);
1564 status = centry->status;
1566 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1567 domain->name, nt_errstr(status) ));
1569 centry_free(centry);
1576 /* Return status value returned by seq number check */
1578 if (!NT_STATUS_IS_OK(domain->last_status))
1579 return domain->last_status;
1581 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1584 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1586 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1587 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1588 if (!domain->internal && old_status) {
1589 set_domain_offline(domain);
1593 !domain->internal &&
1595 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1597 goto do_fetch_cache;
1602 refresh_sequence_number(domain, false);
1603 if (!NT_STATUS_IS_OK(status)) {
1606 centry = centry_start(domain, status);
1609 centry_put_uint32(centry, *num_entries);
1610 for (i=0; i<(*num_entries); i++) {
1611 centry_put_string(centry, (*info)[i].acct_name);
1612 centry_put_string(centry, (*info)[i].acct_desc);
1613 centry_put_uint32(centry, (*info)[i].rid);
1615 centry_end(centry, "GL/%s/domain", domain->name);
1616 centry_free(centry);
1622 /* list all domain groups */
1623 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
1624 TALLOC_CTX *mem_ctx,
1625 uint32 *num_entries,
1626 struct acct_info **info)
1628 struct winbind_cache *cache = get_cache(domain);
1629 struct cache_entry *centry = NULL;
1634 old_status = domain->online;
1638 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1643 *num_entries = centry_uint32(centry);
1645 if (*num_entries == 0)
1648 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1650 smb_panic_fn("enum_dom_groups out of memory");
1652 for (i=0; i<(*num_entries); i++) {
1653 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1654 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1655 (*info)[i].rid = centry_uint32(centry);
1660 /* If we are returning cached data and the domain controller
1661 is down then we don't know whether the data is up to date
1662 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1665 if (wcache_server_down(domain)) {
1666 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1667 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1669 status = centry->status;
1671 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1672 domain->name, nt_errstr(status) ));
1674 centry_free(centry);
1681 /* Return status value returned by seq number check */
1683 if (!NT_STATUS_IS_OK(domain->last_status))
1684 return domain->last_status;
1686 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1689 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1691 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1692 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1693 if (!domain->internal && old_status) {
1694 set_domain_offline(domain);
1697 !domain->internal &&
1700 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1702 goto do_fetch_cache;
1707 refresh_sequence_number(domain, false);
1708 if (!NT_STATUS_IS_OK(status)) {
1711 centry = centry_start(domain, status);
1714 centry_put_uint32(centry, *num_entries);
1715 for (i=0; i<(*num_entries); i++) {
1716 centry_put_string(centry, (*info)[i].acct_name);
1717 centry_put_string(centry, (*info)[i].acct_desc);
1718 centry_put_uint32(centry, (*info)[i].rid);
1720 centry_end(centry, "GL/%s/local", domain->name);
1721 centry_free(centry);
1727 NTSTATUS wcache_name_to_sid(struct winbindd_domain *domain,
1728 const char *domain_name,
1730 struct dom_sid *sid,
1731 enum lsa_SidType *type)
1733 struct winbind_cache *cache = get_cache(domain);
1734 struct cache_entry *centry;
1738 if (cache->tdb == NULL) {
1739 return NT_STATUS_NOT_FOUND;
1742 uname = talloc_strdup_upper(talloc_tos(), name);
1743 if (uname == NULL) {
1744 return NT_STATUS_NO_MEMORY;
1747 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1749 if (centry == NULL) {
1750 return NT_STATUS_NOT_FOUND;
1753 status = centry->status;
1754 if (NT_STATUS_IS_OK(status)) {
1755 *type = (enum lsa_SidType)centry_uint32(centry);
1756 centry_sid(centry, sid);
1759 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1760 "%s\n", domain->name, nt_errstr(status) ));
1762 centry_free(centry);
1766 /* convert a single name to a sid in a domain */
1767 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
1768 TALLOC_CTX *mem_ctx,
1769 const char *domain_name,
1772 struct dom_sid *sid,
1773 enum lsa_SidType *type)
1778 old_status = domain->online;
1780 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1781 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1787 /* If the seq number check indicated that there is a problem
1788 * with this DC, then return that status... except for
1789 * access_denied. This is special because the dc may be in
1790 * "restrict anonymous = 1" mode, in which case it will deny
1791 * most unauthenticated operations, but *will* allow the LSA
1792 * name-to-sid that we try as a fallback. */
1794 if (!(NT_STATUS_IS_OK(domain->last_status)
1795 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1796 return domain->last_status;
1798 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1801 status = domain->backend->name_to_sid(domain, mem_ctx, domain_name,
1802 name, flags, sid, type);
1804 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1805 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1806 if (!domain->internal && old_status) {
1807 set_domain_offline(domain);
1809 if (!domain->internal &&
1812 NTSTATUS cache_status;
1813 cache_status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1814 return cache_status;
1818 refresh_sequence_number(domain, false);
1820 if (domain->online &&
1821 (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
1822 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1824 /* Only save the reverse mapping if this was not a UPN */
1825 if (!strchr(name, '@')) {
1826 strupper_m(CONST_DISCARD(char *,domain_name));
1827 strlower_m(CONST_DISCARD(char *,name));
1828 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1835 NTSTATUS wcache_sid_to_name(struct winbindd_domain *domain,
1836 const struct dom_sid *sid,
1837 TALLOC_CTX *mem_ctx,
1840 enum lsa_SidType *type)
1842 struct winbind_cache *cache = get_cache(domain);
1843 struct cache_entry *centry;
1847 if (cache->tdb == NULL) {
1848 return NT_STATUS_NOT_FOUND;
1851 sid_string = sid_string_tos(sid);
1852 if (sid_string == NULL) {
1853 return NT_STATUS_NO_MEMORY;
1856 centry = wcache_fetch(cache, domain, "SN/%s", sid_string);
1857 TALLOC_FREE(sid_string);
1858 if (centry == NULL) {
1859 return NT_STATUS_NOT_FOUND;
1862 if (NT_STATUS_IS_OK(centry->status)) {
1863 *type = (enum lsa_SidType)centry_uint32(centry);
1864 *domain_name = centry_string(centry, mem_ctx);
1865 *name = centry_string(centry, mem_ctx);
1868 status = centry->status;
1869 centry_free(centry);
1871 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1872 "%s\n", domain->name, nt_errstr(status) ));
1877 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1879 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
1880 TALLOC_CTX *mem_ctx,
1881 const struct dom_sid *sid,
1884 enum lsa_SidType *type)
1889 old_status = domain->online;
1890 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
1892 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1897 *domain_name = NULL;
1899 /* If the seq number check indicated that there is a problem
1900 * with this DC, then return that status... except for
1901 * access_denied. This is special because the dc may be in
1902 * "restrict anonymous = 1" mode, in which case it will deny
1903 * most unauthenticated operations, but *will* allow the LSA
1904 * sid-to-name that we try as a fallback. */
1906 if (!(NT_STATUS_IS_OK(domain->last_status)
1907 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1908 return domain->last_status;
1910 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1913 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1915 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1916 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1917 if (!domain->internal && old_status) {
1918 set_domain_offline(domain);
1920 if (!domain->internal &&
1923 NTSTATUS cache_status;
1924 cache_status = wcache_sid_to_name(domain, sid, mem_ctx,
1925 domain_name, name, type);
1926 return cache_status;
1930 refresh_sequence_number(domain, false);
1931 if (!NT_STATUS_IS_OK(status)) {
1934 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1936 /* We can't save the name to sid mapping here, as with sid history a
1937 * later name2sid would give the wrong sid. */
1942 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
1943 TALLOC_CTX *mem_ctx,
1944 const struct dom_sid *domain_sid,
1949 enum lsa_SidType **types)
1951 struct winbind_cache *cache = get_cache(domain);
1953 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1958 old_status = domain->online;
1959 *domain_name = NULL;
1967 if (num_rids == 0) {
1968 return NT_STATUS_OK;
1971 *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
1972 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
1974 if ((*names == NULL) || (*types == NULL)) {
1975 result = NT_STATUS_NO_MEMORY;
1979 have_mapped = have_unmapped = false;
1981 for (i=0; i<num_rids; i++) {
1983 struct cache_entry *centry;
1986 if (!sid_compose(&sid, domain_sid, rids[i])) {
1987 result = NT_STATUS_INTERNAL_ERROR;
1991 centry = wcache_fetch(cache, domain, "SN/%s",
1992 sid_to_fstring(tmp, &sid));
1997 (*types)[i] = SID_NAME_UNKNOWN;
1998 (*names)[i] = talloc_strdup(*names, "");
2000 if (NT_STATUS_IS_OK(centry->status)) {
2003 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
2005 dom = centry_string(centry, mem_ctx);
2006 if (*domain_name == NULL) {
2012 (*names)[i] = centry_string(centry, *names);
2014 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
2015 have_unmapped = true;
2018 /* something's definitely wrong */
2019 result = centry->status;
2023 centry_free(centry);
2027 return NT_STATUS_NONE_MAPPED;
2029 if (!have_unmapped) {
2030 return NT_STATUS_OK;
2032 return STATUS_SOME_UNMAPPED;
2036 TALLOC_FREE(*names);
2037 TALLOC_FREE(*types);
2039 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
2040 rids, num_rids, domain_name,
2043 if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
2044 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2045 if (!domain->internal && old_status) {
2046 set_domain_offline(domain);
2049 !domain->internal &&
2052 have_mapped = have_unmapped = false;
2054 for (i=0; i<num_rids; i++) {
2056 struct cache_entry *centry;
2059 if (!sid_compose(&sid, domain_sid, rids[i])) {
2060 result = NT_STATUS_INTERNAL_ERROR;
2064 centry = wcache_fetch(cache, domain, "SN/%s",
2065 sid_to_fstring(tmp, &sid));
2067 (*types)[i] = SID_NAME_UNKNOWN;
2068 (*names)[i] = talloc_strdup(*names, "");
2072 (*types)[i] = SID_NAME_UNKNOWN;
2073 (*names)[i] = talloc_strdup(*names, "");
2075 if (NT_STATUS_IS_OK(centry->status)) {
2078 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
2080 dom = centry_string(centry, mem_ctx);
2081 if (*domain_name == NULL) {
2087 (*names)[i] = centry_string(centry, *names);
2089 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
2090 have_unmapped = true;
2093 /* something's definitely wrong */
2094 result = centry->status;
2098 centry_free(centry);
2102 return NT_STATUS_NONE_MAPPED;
2104 if (!have_unmapped) {
2105 return NT_STATUS_OK;
2107 return STATUS_SOME_UNMAPPED;
2111 None of the queried rids has been found so save all negative entries
2113 if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
2114 for (i = 0; i < num_rids; i++) {
2116 const char *name = "";
2117 const enum lsa_SidType type = SID_NAME_UNKNOWN;
2118 NTSTATUS status = NT_STATUS_NONE_MAPPED;
2120 if (!sid_compose(&sid, domain_sid, rids[i])) {
2121 return NT_STATUS_INTERNAL_ERROR;
2124 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2132 Some or all of the queried rids have been found.
2134 if (!NT_STATUS_IS_OK(result) &&
2135 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
2139 refresh_sequence_number(domain, false);
2141 for (i=0; i<num_rids; i++) {
2145 if (!sid_compose(&sid, domain_sid, rids[i])) {
2146 result = NT_STATUS_INTERNAL_ERROR;
2150 status = (*types)[i] == SID_NAME_UNKNOWN ?
2151 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
2153 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2154 (*names)[i], (*types)[i]);
2160 TALLOC_FREE(*names);
2161 TALLOC_FREE(*types);
2165 NTSTATUS wcache_query_user(struct winbindd_domain *domain,
2166 TALLOC_CTX *mem_ctx,
2167 const struct dom_sid *user_sid,
2168 struct wbint_userinfo *info)
2170 struct winbind_cache *cache = get_cache(domain);
2171 struct cache_entry *centry = NULL;
2175 if (cache->tdb == NULL) {
2176 return NT_STATUS_NOT_FOUND;
2179 sid_string = sid_string_tos(user_sid);
2180 if (sid_string == NULL) {
2181 return NT_STATUS_NO_MEMORY;
2184 centry = wcache_fetch(cache, domain, "U/%s", sid_string);
2185 TALLOC_FREE(sid_string);
2186 if (centry == NULL) {
2187 return NT_STATUS_NOT_FOUND;
2191 * If we have an access denied cache entry and a cached info3
2192 * in the samlogon cache then do a query. This will force the
2193 * rpc back end to return the info3 data.
2196 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED) &&
2197 netsamlogon_cache_have(user_sid)) {
2198 DEBUG(10, ("query_user: cached access denied and have cached "
2200 domain->last_status = NT_STATUS_OK;
2201 centry_free(centry);
2202 return NT_STATUS_NOT_FOUND;
2205 /* if status is not ok then this is a negative hit
2206 and the rest of the data doesn't matter */
2207 status = centry->status;
2208 if (NT_STATUS_IS_OK(status)) {
2209 info->acct_name = centry_string(centry, mem_ctx);
2210 info->full_name = centry_string(centry, mem_ctx);
2211 info->homedir = centry_string(centry, mem_ctx);
2212 info->shell = centry_string(centry, mem_ctx);
2213 info->primary_gid = centry_uint32(centry);
2214 centry_sid(centry, &info->user_sid);
2215 centry_sid(centry, &info->group_sid);
2218 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2219 "%s\n", domain->name, nt_errstr(status) ));
2221 centry_free(centry);
2225 /* Lookup user information from a rid */
2226 static NTSTATUS query_user(struct winbindd_domain *domain,
2227 TALLOC_CTX *mem_ctx,
2228 const struct dom_sid *user_sid,
2229 struct wbint_userinfo *info)
2234 old_status = domain->online;
2235 status = wcache_query_user(domain, mem_ctx, user_sid, info);
2236 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2242 /* Return status value returned by seq number check */
2244 if (!NT_STATUS_IS_OK(domain->last_status))
2245 return domain->last_status;
2247 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2250 status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
2252 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2253 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2254 if (!domain->internal && old_status) {
2255 set_domain_offline(domain);
2257 if (!domain->internal &&
2260 NTSTATUS cache_status;
2261 cache_status = wcache_query_user(domain, mem_ctx, user_sid, info);
2262 return cache_status;
2266 refresh_sequence_number(domain, false);
2267 if (!NT_STATUS_IS_OK(status)) {
2270 wcache_save_user(domain, status, info);
2275 NTSTATUS wcache_lookup_usergroups(struct winbindd_domain *domain,
2276 TALLOC_CTX *mem_ctx,
2277 const struct dom_sid *user_sid,
2278 uint32_t *pnum_sids,
2279 struct dom_sid **psids)
2281 struct winbind_cache *cache = get_cache(domain);
2282 struct cache_entry *centry = NULL;
2284 uint32_t i, num_sids;
2285 struct dom_sid *sids;
2288 if (cache->tdb == NULL) {
2289 return NT_STATUS_NOT_FOUND;
2292 centry = wcache_fetch(cache, domain, "UG/%s",
2293 sid_to_fstring(sid_string, user_sid));
2294 if (centry == NULL) {
2295 return NT_STATUS_NOT_FOUND;
2298 /* If we have an access denied cache entry and a cached info3 in the
2299 samlogon cache then do a query. This will force the rpc back end
2300 to return the info3 data. */
2302 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)
2303 && netsamlogon_cache_have(user_sid)) {
2304 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2306 domain->last_status = NT_STATUS_OK;
2307 centry_free(centry);
2308 return NT_STATUS_NOT_FOUND;
2311 num_sids = centry_uint32(centry);
2312 sids = talloc_array(mem_ctx, struct dom_sid, num_sids);
2314 centry_free(centry);
2315 return NT_STATUS_NO_MEMORY;
2318 for (i=0; i<num_sids; i++) {
2319 centry_sid(centry, &sids[i]);
2322 status = centry->status;
2324 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2325 "status: %s\n", domain->name, nt_errstr(status)));
2327 centry_free(centry);
2329 *pnum_sids = num_sids;
2334 /* Lookup groups a user is a member of. */
2335 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
2336 TALLOC_CTX *mem_ctx,
2337 const struct dom_sid *user_sid,
2338 uint32 *num_groups, struct dom_sid **user_gids)
2340 struct cache_entry *centry = NULL;
2346 old_status = domain->online;
2347 status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2348 num_groups, user_gids);
2349 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2354 (*user_gids) = NULL;
2356 /* Return status value returned by seq number check */
2358 if (!NT_STATUS_IS_OK(domain->last_status))
2359 return domain->last_status;
2361 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2364 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
2366 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2367 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2368 if (!domain->internal && old_status) {
2369 set_domain_offline(domain);
2371 if (!domain->internal &&
2374 NTSTATUS cache_status;
2375 cache_status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2376 num_groups, user_gids);
2377 return cache_status;
2380 if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
2384 refresh_sequence_number(domain, false);
2385 if (!NT_STATUS_IS_OK(status)) {
2388 centry = centry_start(domain, status);
2392 centry_put_uint32(centry, *num_groups);
2393 for (i=0; i<(*num_groups); i++) {
2394 centry_put_sid(centry, &(*user_gids)[i]);
2397 centry_end(centry, "UG/%s", sid_to_fstring(sid_string, user_sid));
2398 centry_free(centry);
2404 static char *wcache_make_sidlist(TALLOC_CTX *mem_ctx, uint32_t num_sids,
2405 const struct dom_sid *sids)
2410 sidlist = talloc_strdup(mem_ctx, "");
2411 if (sidlist == NULL) {
2414 for (i=0; i<num_sids; i++) {
2416 sidlist = talloc_asprintf_append_buffer(
2417 sidlist, "/%s", sid_to_fstring(tmp, &sids[i]));
2418 if (sidlist == NULL) {
2425 NTSTATUS wcache_lookup_useraliases(struct winbindd_domain *domain,
2426 TALLOC_CTX *mem_ctx, uint32_t num_sids,
2427 const struct dom_sid *sids,
2428 uint32_t *pnum_aliases, uint32_t **paliases)
2430 struct winbind_cache *cache = get_cache(domain);
2431 struct cache_entry *centry = NULL;
2432 uint32_t num_aliases;
2438 if (cache->tdb == NULL) {
2439 return NT_STATUS_NOT_FOUND;
2442 if (num_sids == 0) {
2445 return NT_STATUS_OK;
2448 /* We need to cache indexed by the whole list of SIDs, the aliases
2449 * resulting might come from any of the SIDs. */
2451 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2452 if (sidlist == NULL) {
2453 return NT_STATUS_NO_MEMORY;
2456 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
2457 TALLOC_FREE(sidlist);
2458 if (centry == NULL) {
2459 return NT_STATUS_NOT_FOUND;
2462 num_aliases = centry_uint32(centry);
2463 aliases = talloc_array(mem_ctx, uint32_t, num_aliases);
2464 if (aliases == NULL) {
2465 centry_free(centry);
2466 return NT_STATUS_NO_MEMORY;
2469 for (i=0; i<num_aliases; i++) {
2470 aliases[i] = centry_uint32(centry);
2473 status = centry->status;
2475 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2476 "status %s\n", domain->name, nt_errstr(status)));
2478 centry_free(centry);
2480 *pnum_aliases = num_aliases;
2481 *paliases = aliases;
2486 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
2487 TALLOC_CTX *mem_ctx,
2488 uint32 num_sids, const struct dom_sid *sids,
2489 uint32 *num_aliases, uint32 **alias_rids)
2491 struct cache_entry *centry = NULL;
2497 old_status = domain->online;
2498 status = wcache_lookup_useraliases(domain, mem_ctx, num_sids, sids,
2499 num_aliases, alias_rids);
2500 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2505 (*alias_rids) = NULL;
2507 if (!NT_STATUS_IS_OK(domain->last_status))
2508 return domain->last_status;
2510 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2511 "for domain %s\n", domain->name ));
2513 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2514 if (sidlist == NULL) {
2515 return NT_STATUS_NO_MEMORY;
2518 status = domain->backend->lookup_useraliases(domain, mem_ctx,
2520 num_aliases, alias_rids);
2522 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2523 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2524 if (!domain->internal && old_status) {
2525 set_domain_offline(domain);
2527 if (!domain->internal &&
2530 NTSTATUS cache_status;
2531 cache_status = wcache_lookup_useraliases(domain, mem_ctx, num_sids,
2532 sids, num_aliases, alias_rids);
2533 return cache_status;
2537 refresh_sequence_number(domain, false);
2538 if (!NT_STATUS_IS_OK(status)) {
2541 centry = centry_start(domain, status);
2544 centry_put_uint32(centry, *num_aliases);
2545 for (i=0; i<(*num_aliases); i++)
2546 centry_put_uint32(centry, (*alias_rids)[i]);
2547 centry_end(centry, "UA%s", sidlist);
2548 centry_free(centry);
2554 NTSTATUS wcache_lookup_groupmem(struct winbindd_domain *domain,
2555 TALLOC_CTX *mem_ctx,
2556 const struct dom_sid *group_sid,
2557 uint32_t *num_names,
2558 struct dom_sid **sid_mem, char ***names,
2559 uint32_t **name_types)
2561 struct winbind_cache *cache = get_cache(domain);
2562 struct cache_entry *centry = NULL;
2567 if (cache->tdb == NULL) {
2568 return NT_STATUS_NOT_FOUND;
2571 sid_string = sid_string_tos(group_sid);
2572 if (sid_string == NULL) {
2573 return NT_STATUS_NO_MEMORY;
2576 centry = wcache_fetch(cache, domain, "GM/%s", sid_string);
2577 TALLOC_FREE(sid_string);
2578 if (centry == NULL) {
2579 return NT_STATUS_NOT_FOUND;
2586 *num_names = centry_uint32(centry);
2587 if (*num_names == 0) {
2588 centry_free(centry);
2589 return NT_STATUS_OK;
2592 *sid_mem = talloc_array(mem_ctx, struct dom_sid, *num_names);
2593 *names = talloc_array(mem_ctx, char *, *num_names);
2594 *name_types = talloc_array(mem_ctx, uint32, *num_names);
2596 if ((*sid_mem == NULL) || (*names == NULL) || (*name_types == NULL)) {
2597 TALLOC_FREE(*sid_mem);
2598 TALLOC_FREE(*names);
2599 TALLOC_FREE(*name_types);
2600 centry_free(centry);
2601 return NT_STATUS_NO_MEMORY;
2604 for (i=0; i<(*num_names); i++) {
2605 centry_sid(centry, &(*sid_mem)[i]);
2606 (*names)[i] = centry_string(centry, mem_ctx);
2607 (*name_types)[i] = centry_uint32(centry);
2610 status = centry->status;
2612 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2613 "status: %s\n", domain->name, nt_errstr(status)));
2615 centry_free(centry);
2619 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
2620 TALLOC_CTX *mem_ctx,
2621 const struct dom_sid *group_sid,
2622 enum lsa_SidType type,
2624 struct dom_sid **sid_mem, char ***names,
2625 uint32 **name_types)
2627 struct cache_entry *centry = NULL;
2633 old_status = domain->online;
2634 status = wcache_lookup_groupmem(domain, mem_ctx, group_sid, num_names,
2635 sid_mem, names, name_types);
2636 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2643 (*name_types) = NULL;
2645 /* Return status value returned by seq number check */
2647 if (!NT_STATUS_IS_OK(domain->last_status))
2648 return domain->last_status;
2650 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2653 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid,
2655 sid_mem, names, name_types);
2657 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2658 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2659 if (!domain->internal && old_status) {
2660 set_domain_offline(domain);
2662 if (!domain->internal &&
2665 NTSTATUS cache_status;
2666 cache_status = wcache_lookup_groupmem(domain, mem_ctx, group_sid,
2667 num_names, sid_mem, names,
2669 return cache_status;
2673 refresh_sequence_number(domain, false);
2674 if (!NT_STATUS_IS_OK(status)) {
2677 centry = centry_start(domain, status);
2680 centry_put_uint32(centry, *num_names);
2681 for (i=0; i<(*num_names); i++) {
2682 centry_put_sid(centry, &(*sid_mem)[i]);
2683 centry_put_string(centry, (*names)[i]);
2684 centry_put_uint32(centry, (*name_types)[i]);
2686 centry_end(centry, "GM/%s", sid_to_fstring(sid_string, group_sid));
2687 centry_free(centry);
2693 /* find the sequence number for a domain */
2694 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
2696 refresh_sequence_number(domain, false);
2698 *seq = domain->sequence_number;
2700 return NT_STATUS_OK;
2703 /* enumerate trusted domains
2704 * (we need to have the list of trustdoms in the cache when we go offline) -
2706 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
2707 TALLOC_CTX *mem_ctx,
2708 struct netr_DomainTrustList *trusts)
2711 struct winbind_cache *cache;
2712 struct winbindd_tdc_domain *dom_list = NULL;
2713 size_t num_domains = 0;
2714 bool retval = false;
2718 old_status = domain->online;
2720 trusts->array = NULL;
2722 cache = get_cache(domain);
2723 if (!cache || !cache->tdb) {
2727 if (domain->online) {
2731 retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2732 if (!retval || !num_domains || !dom_list) {
2733 TALLOC_FREE(dom_list);
2738 trusts->array = TALLOC_ZERO_ARRAY(mem_ctx, struct netr_DomainTrust, num_domains);
2739 if (!trusts->array) {
2740 TALLOC_FREE(dom_list);
2741 return NT_STATUS_NO_MEMORY;
2744 for (i = 0; i < num_domains; i++) {
2745 struct netr_DomainTrust *trust;
2746 struct dom_sid *sid;
2747 struct winbindd_domain *dom;
2749 dom = find_domain_from_name_noinit(dom_list[i].domain_name);
2750 if (dom && dom->internal) {
2754 trust = &trusts->array[trusts->count];
2755 trust->netbios_name = talloc_strdup(trusts->array, dom_list[i].domain_name);
2756 trust->dns_name = talloc_strdup(trusts->array, dom_list[i].dns_name);
2757 sid = talloc(trusts->array, struct dom_sid);
2758 if (!trust->netbios_name || !trust->dns_name ||
2760 TALLOC_FREE(dom_list);
2761 TALLOC_FREE(trusts->array);
2762 return NT_STATUS_NO_MEMORY;
2765 trust->trust_flags = dom_list[i].trust_flags;
2766 trust->trust_attributes = dom_list[i].trust_attribs;
2767 trust->trust_type = dom_list[i].trust_type;
2768 sid_copy(sid, &dom_list[i].sid);
2773 TALLOC_FREE(dom_list);
2774 return NT_STATUS_OK;
2777 /* Return status value returned by seq number check */
2779 if (!NT_STATUS_IS_OK(domain->last_status))
2780 return domain->last_status;
2782 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2785 status = domain->backend->trusted_domains(domain, mem_ctx, trusts);
2787 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2788 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2789 if (!domain->internal && old_status) {
2790 set_domain_offline(domain);
2792 if (!domain->internal &&
2795 retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2796 if (retval && num_domains && dom_list) {
2797 TALLOC_FREE(trusts->array);
2799 goto do_fetch_cache;
2803 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2804 * so that the generic centry handling still applies correctly -
2807 if (!NT_STATUS_IS_ERR(status)) {
2808 status = NT_STATUS_OK;
2813 /* get lockout policy */
2814 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
2815 TALLOC_CTX *mem_ctx,
2816 struct samr_DomInfo12 *policy)
2818 struct winbind_cache *cache = get_cache(domain);
2819 struct cache_entry *centry = NULL;
2823 old_status = domain->online;
2827 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2833 policy->lockout_duration = centry_nttime(centry);
2834 policy->lockout_window = centry_nttime(centry);
2835 policy->lockout_threshold = centry_uint16(centry);
2837 status = centry->status;
2839 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2840 domain->name, nt_errstr(status) ));
2842 centry_free(centry);
2846 ZERO_STRUCTP(policy);
2848 /* Return status value returned by seq number check */
2850 if (!NT_STATUS_IS_OK(domain->last_status))
2851 return domain->last_status;
2853 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2856 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2858 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2859 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2860 if (!domain->internal && old_status) {
2861 set_domain_offline(domain);
2864 !domain->internal &&
2867 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2869 goto do_fetch_cache;
2874 refresh_sequence_number(domain, false);
2875 if (!NT_STATUS_IS_OK(status)) {
2878 wcache_save_lockout_policy(domain, status, policy);
2883 /* get password policy */
2884 static NTSTATUS password_policy(struct winbindd_domain *domain,
2885 TALLOC_CTX *mem_ctx,
2886 struct samr_DomInfo1 *policy)
2888 struct winbind_cache *cache = get_cache(domain);
2889 struct cache_entry *centry = NULL;
2893 old_status = domain->online;
2897 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2903 policy->min_password_length = centry_uint16(centry);
2904 policy->password_history_length = centry_uint16(centry);
2905 policy->password_properties = centry_uint32(centry);
2906 policy->max_password_age = centry_nttime(centry);
2907 policy->min_password_age = centry_nttime(centry);
2909 status = centry->status;
2911 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2912 domain->name, nt_errstr(status) ));
2914 centry_free(centry);
2918 ZERO_STRUCTP(policy);
2920 /* Return status value returned by seq number check */
2922 if (!NT_STATUS_IS_OK(domain->last_status))
2923 return domain->last_status;
2925 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2928 status = domain->backend->password_policy(domain, mem_ctx, policy);
2930 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2931 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2932 if (!domain->internal && old_status) {
2933 set_domain_offline(domain);
2936 !domain->internal &&
2939 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2941 goto do_fetch_cache;
2946 refresh_sequence_number(domain, false);
2947 if (!NT_STATUS_IS_OK(status)) {
2950 wcache_save_password_policy(domain, status, policy);
2956 /* Invalidate cached user and group lists coherently */
2958 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2961 if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
2962 strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
2963 tdb_delete(the_tdb, kbuf);
2968 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2970 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
2971 struct netr_SamInfo3 *info3)
2974 fstring key_str, sid_string;
2975 struct winbind_cache *cache;
2977 /* dont clear cached U/SID and UG/SID entries when we want to logon
2980 if (lp_winbind_offline_logon()) {
2987 cache = get_cache(domain);
2993 sid_compose(&sid, info3->base.domain_sid, info3->base.rid);
2995 /* Clear U/SID cache entry */
2996 fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, &sid));
2997 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
2998 tdb_delete(cache->tdb, string_tdb_data(key_str));
3000 /* Clear UG/SID cache entry */
3001 fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, &sid));
3002 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
3003 tdb_delete(cache->tdb, string_tdb_data(key_str));
3005 /* Samba/winbindd never needs this. */
3006 netsamlogon_clear_cached_user(info3);
3009 bool wcache_invalidate_cache(void)
3011 struct winbindd_domain *domain;
3013 for (domain = domain_list(); domain; domain = domain->next) {
3014 struct winbind_cache *cache = get_cache(domain);
3016 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3017 "entries for %s\n", domain->name));
3020 tdb_traverse(cache->tdb, traverse_fn, NULL);
3029 bool wcache_invalidate_cache_noinit(void)
3031 struct winbindd_domain *domain;
3033 for (domain = domain_list(); domain; domain = domain->next) {
3034 struct winbind_cache *cache;
3036 /* Skip uninitialized domains. */
3037 if (!domain->initialized && !domain->internal) {
3041 cache = get_cache(domain);
3043 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3044 "entries for %s\n", domain->name));
3047 tdb_traverse(cache->tdb, traverse_fn, NULL);
3049 * Flushing cache has nothing to with domains.
3050 * return here if we successfully flushed once.
3051 * To avoid unnecessary traversing the cache.
3062 bool init_wcache(void)
3064 if (wcache == NULL) {
3065 wcache = SMB_XMALLOC_P(struct winbind_cache);
3066 ZERO_STRUCTP(wcache);
3069 if (wcache->tdb != NULL)
3072 /* when working offline we must not clear the cache on restart */
3073 wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
3074 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3075 TDB_INCOMPATIBLE_HASH |
3076 (lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
3077 O_RDWR|O_CREAT, 0600);
3079 if (wcache->tdb == NULL) {
3080 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3087 /************************************************************************
3088 This is called by the parent to initialize the cache file.
3089 We don't need sophisticated locking here as we know we're the
3091 ************************************************************************/
3093 bool initialize_winbindd_cache(void)
3095 bool cache_bad = true;
3098 if (!init_wcache()) {
3099 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3103 /* Check version number. */
3104 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
3105 vers == WINBINDD_CACHE_VERSION) {
3110 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3111 "and re-creating with version number %d\n",
3112 WINBINDD_CACHE_VERSION ));
3114 tdb_close(wcache->tdb);
3117 if (unlink(cache_path("winbindd_cache.tdb")) == -1) {
3118 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3119 cache_path("winbindd_cache.tdb"),
3123 if (!init_wcache()) {
3124 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3125 "init_wcache failed.\n"));
3129 /* Write the version. */
3130 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
3131 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3132 tdb_errorstr(wcache->tdb) ));
3137 tdb_close(wcache->tdb);
3142 void close_winbindd_cache(void)
3148 tdb_close(wcache->tdb);
3153 bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
3154 char **domain_name, char **name,
3155 enum lsa_SidType *type)
3157 struct winbindd_domain *domain;
3160 domain = find_lookup_domain_from_sid(sid);
3161 if (domain == NULL) {
3164 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
3166 return NT_STATUS_IS_OK(status);
3169 bool lookup_cached_name(const char *domain_name,
3171 struct dom_sid *sid,
3172 enum lsa_SidType *type)
3174 struct winbindd_domain *domain;
3176 bool original_online_state;
3178 domain = find_lookup_domain_from_name(domain_name);
3179 if (domain == NULL) {
3183 /* If we are doing a cached logon, temporarily set the domain
3184 offline so the cache won't expire the entry */
3186 original_online_state = domain->online;
3187 domain->online = false;
3188 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
3189 domain->online = original_online_state;
3191 return NT_STATUS_IS_OK(status);
3194 void cache_name2sid(struct winbindd_domain *domain,
3195 const char *domain_name, const char *name,
3196 enum lsa_SidType type, const struct dom_sid *sid)
3198 refresh_sequence_number(domain, false);
3199 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
3204 * The original idea that this cache only contains centries has
3205 * been blurred - now other stuff gets put in here. Ensure we
3206 * ignore these things on cleanup.
3209 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
3210 TDB_DATA dbuf, void *state)
3212 struct cache_entry *centry;
3214 if (is_non_centry_key(kbuf)) {
3218 centry = wcache_fetch_raw((char *)kbuf.dptr);
3223 if (!NT_STATUS_IS_OK(centry->status)) {
3224 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
3225 tdb_delete(the_tdb, kbuf);
3228 centry_free(centry);
3232 /* flush the cache */
3233 void wcache_flush_cache(void)
3238 tdb_close(wcache->tdb);
3241 if (!winbindd_use_cache()) {
3245 /* when working offline we must not clear the cache on restart */
3246 wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
3247 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3248 TDB_INCOMPATIBLE_HASH |
3249 (lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST)),
3250 O_RDWR|O_CREAT, 0600);
3253 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3257 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
3259 DEBUG(10,("wcache_flush_cache success\n"));
3262 /* Count cached creds */
3264 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3267 int *cred_count = (int*)state;
3269 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3275 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
3277 struct winbind_cache *cache = get_cache(domain);
3282 return NT_STATUS_INTERNAL_DB_ERROR;
3285 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
3287 return NT_STATUS_OK;
3291 struct cred_list *prev, *next;
3296 static struct cred_list *wcache_cred_list;
3298 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3301 struct cred_list *cred;
3303 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3305 cred = SMB_MALLOC_P(struct cred_list);
3307 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3313 /* save a copy of the key */
3315 fstrcpy(cred->name, (const char *)kbuf.dptr);
3316 DLIST_ADD(wcache_cred_list, cred);
3322 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const struct dom_sid *sid)
3324 struct winbind_cache *cache = get_cache(domain);
3327 struct cred_list *cred, *oldest = NULL;
3330 return NT_STATUS_INTERNAL_DB_ERROR;
3333 /* we possibly already have an entry */
3334 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
3336 fstring key_str, tmp;
3338 DEBUG(11,("we already have an entry, deleting that\n"));
3340 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
3342 tdb_delete(cache->tdb, string_tdb_data(key_str));
3344 return NT_STATUS_OK;
3347 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
3349 return NT_STATUS_OK;
3350 } else if ((ret == -1) || (wcache_cred_list == NULL)) {
3351 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3354 ZERO_STRUCTP(oldest);
3356 for (cred = wcache_cred_list; cred; cred = cred->next) {
3361 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
3363 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3365 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
3369 t = IVAL(data.dptr, 0);
3370 SAFE_FREE(data.dptr);
3373 oldest = SMB_MALLOC_P(struct cred_list);
3374 if (oldest == NULL) {
3375 status = NT_STATUS_NO_MEMORY;
3379 fstrcpy(oldest->name, cred->name);
3380 oldest->created = t;
3384 if (t < oldest->created) {
3385 fstrcpy(oldest->name, cred->name);
3386 oldest->created = t;
3390 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
3391 status = NT_STATUS_OK;
3393 status = NT_STATUS_UNSUCCESSFUL;
3396 SAFE_FREE(wcache_cred_list);
3402 /* Change the global online/offline state. */
3403 bool set_global_winbindd_state_offline(void)
3407 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3409 /* Only go offline if someone has created
3410 the key "WINBINDD_OFFLINE" in the cache tdb. */
3412 if (wcache == NULL || wcache->tdb == NULL) {
3413 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3417 if (!lp_winbind_offline_logon()) {
3418 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3422 if (global_winbindd_offline_state) {
3423 /* Already offline. */
3427 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
3429 if (!data.dptr || data.dsize != 4) {
3430 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3431 SAFE_FREE(data.dptr);
3434 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3435 global_winbindd_offline_state = true;
3436 SAFE_FREE(data.dptr);
3441 void set_global_winbindd_state_online(void)
3443 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3445 if (!lp_winbind_offline_logon()) {
3446 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3450 if (!global_winbindd_offline_state) {
3451 /* Already online. */
3454 global_winbindd_offline_state = false;
3460 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3461 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
3464 bool get_global_winbindd_state_offline(void)
3466 return global_winbindd_offline_state;
3469 /***********************************************************************
3470 Validate functions for all possible cache tdb keys.
3471 ***********************************************************************/
3473 static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
3474 struct tdb_validation_status *state)
3476 struct cache_entry *centry;
3478 centry = SMB_XMALLOC_P(struct cache_entry);
3479 centry->data = (unsigned char *)memdup(data.dptr, data.dsize);
3480 if (!centry->data) {
3484 centry->len = data.dsize;
3487 if (centry->len < 8) {
3488 /* huh? corrupt cache? */
3489 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr));
3490 centry_free(centry);
3491 state->bad_entry = true;
3492 state->success = false;
3496 centry->status = NT_STATUS(centry_uint32(centry));
3497 centry->sequence_number = centry_uint32(centry);
3501 static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3502 struct tdb_validation_status *state)
3504 if (dbuf.dsize != 8) {
3505 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3506 keystr, (unsigned int)dbuf.dsize ));
3507 state->bad_entry = true;
3513 static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3514 struct tdb_validation_status *state)
3516 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3521 (void)centry_uint32(centry);
3522 if (NT_STATUS_IS_OK(centry->status)) {
3524 (void)centry_sid(centry, &sid);
3527 centry_free(centry);
3529 if (!(state->success)) {
3532 DEBUG(10,("validate_ns: %s ok\n", keystr));
3536 static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3537 struct tdb_validation_status *state)
3539 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3544 if (NT_STATUS_IS_OK(centry->status)) {
3545 (void)centry_uint32(centry);
3546 (void)centry_string(centry, mem_ctx);
3547 (void)centry_string(centry, mem_ctx);
3550 centry_free(centry);
3552 if (!(state->success)) {
3555 DEBUG(10,("validate_sn: %s ok\n", keystr));
3559 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3560 struct tdb_validation_status *state)
3562 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3569 (void)centry_string(centry, mem_ctx);
3570 (void)centry_string(centry, mem_ctx);
3571 (void)centry_string(centry, mem_ctx);
3572 (void)centry_string(centry, mem_ctx);
3573 (void)centry_uint32(centry);
3574 (void)centry_sid(centry, &sid);
3575 (void)centry_sid(centry, &sid);
3577 centry_free(centry);
3579 if (!(state->success)) {
3582 DEBUG(10,("validate_u: %s ok\n", keystr));
3586 static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3587 struct tdb_validation_status *state)
3589 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3595 (void)centry_nttime(centry);
3596 (void)centry_nttime(centry);
3597 (void)centry_uint16(centry);
3599 centry_free(centry);
3601 if (!(state->success)) {
3604 DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
3608 static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3609 struct tdb_validation_status *state)
3611 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3617 (void)centry_uint16(centry);
3618 (void)centry_uint16(centry);
3619 (void)centry_uint32(centry);
3620 (void)centry_nttime(centry);
3621 (void)centry_nttime(centry);
3623 centry_free(centry);
3625 if (!(state->success)) {
3628 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
3632 static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3633 struct tdb_validation_status *state)
3635 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3641 (void)centry_time(centry);
3642 (void)centry_hash16(centry, mem_ctx);
3644 /* We only have 17 bytes more data in the salted cred case. */
3645 if (centry->len - centry->ofs == 17) {
3646 (void)centry_hash16(centry, mem_ctx);
3649 centry_free(centry);
3651 if (!(state->success)) {
3654 DEBUG(10,("validate_cred: %s ok\n", keystr));
3658 static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3659 struct tdb_validation_status *state)
3661 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3662 int32 num_entries, i;
3668 num_entries = (int32)centry_uint32(centry);
3670 for (i=0; i< num_entries; i++) {
3672 (void)centry_string(centry, mem_ctx);
3673 (void)centry_string(centry, mem_ctx);
3674 (void)centry_string(centry, mem_ctx);
3675 (void)centry_string(centry, mem_ctx);
3676 (void)centry_sid(centry, &sid);
3677 (void)centry_sid(centry, &sid);
3680 centry_free(centry);
3682 if (!(state->success)) {
3685 DEBUG(10,("validate_ul: %s ok\n", keystr));
3689 static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3690 struct tdb_validation_status *state)
3692 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3693 int32 num_entries, i;
3699 num_entries = centry_uint32(centry);
3701 for (i=0; i< num_entries; i++) {
3702 (void)centry_string(centry, mem_ctx);
3703 (void)centry_string(centry, mem_ctx);
3704 (void)centry_uint32(centry);
3707 centry_free(centry);
3709 if (!(state->success)) {
3712 DEBUG(10,("validate_gl: %s ok\n", keystr));
3716 static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3717 struct tdb_validation_status *state)
3719 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3720 int32 num_groups, i;
3726 num_groups = centry_uint32(centry);
3728 for (i=0; i< num_groups; i++) {
3730 centry_sid(centry, &sid);
3733 centry_free(centry);
3735 if (!(state->success)) {
3738 DEBUG(10,("validate_ug: %s ok\n", keystr));
3742 static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3743 struct tdb_validation_status *state)
3745 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3746 int32 num_aliases, i;
3752 num_aliases = centry_uint32(centry);
3754 for (i=0; i < num_aliases; i++) {
3755 (void)centry_uint32(centry);
3758 centry_free(centry);
3760 if (!(state->success)) {
3763 DEBUG(10,("validate_ua: %s ok\n", keystr));
3767 static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3768 struct tdb_validation_status *state)
3770 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3777 num_names = centry_uint32(centry);
3779 for (i=0; i< num_names; i++) {
3781 centry_sid(centry, &sid);
3782 (void)centry_string(centry, mem_ctx);
3783 (void)centry_uint32(centry);
3786 centry_free(centry);
3788 if (!(state->success)) {
3791 DEBUG(10,("validate_gm: %s ok\n", keystr));
3795 static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3796 struct tdb_validation_status *state)
3798 /* Can't say anything about this other than must be nonzero. */
3799 if (dbuf.dsize == 0) {
3800 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3802 state->bad_entry = true;
3803 state->success = false;
3807 DEBUG(10,("validate_dr: %s ok\n", keystr));
3811 static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3812 struct tdb_validation_status *state)
3814 /* Can't say anything about this other than must be nonzero. */
3815 if (dbuf.dsize == 0) {
3816 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3818 state->bad_entry = true;
3819 state->success = false;
3823 DEBUG(10,("validate_de: %s ok\n", keystr));
3827 static int validate_pwinfo(TALLOC_CTX *mem_ctx, const char *keystr,
3828 TDB_DATA dbuf, struct tdb_validation_status *state)
3830 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3836 (void)centry_string(centry, mem_ctx);
3837 (void)centry_string(centry, mem_ctx);
3838 (void)centry_string(centry, mem_ctx);
3839 (void)centry_uint32(centry);
3841 centry_free(centry);
3843 if (!(state->success)) {
3846 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3850 static int validate_nss_an(TALLOC_CTX *mem_ctx, const char *keystr,
3852 struct tdb_validation_status *state)
3854 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3860 (void)centry_string( centry, mem_ctx );
3862 centry_free(centry);
3864 if (!(state->success)) {
3867 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3871 static int validate_nss_na(TALLOC_CTX *mem_ctx, const char *keystr,
3873 struct tdb_validation_status *state)
3875 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3881 (void)centry_string( centry, mem_ctx );
3883 centry_free(centry);
3885 if (!(state->success)) {
3888 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3892 static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
3894 struct tdb_validation_status *state)
3896 if (dbuf.dsize == 0) {
3897 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3898 "key %s (len ==0) ?\n", keystr));
3899 state->bad_entry = true;
3900 state->success = false;
3904 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
3905 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3909 static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3910 struct tdb_validation_status *state)
3912 if (dbuf.dsize != 4) {
3913 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3914 keystr, (unsigned int)dbuf.dsize ));
3915 state->bad_entry = true;
3916 state->success = false;
3919 DEBUG(10,("validate_offline: %s ok\n", keystr));
3923 static int validate_ndr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3924 struct tdb_validation_status *state)
3927 * Ignore validation for now. The proper way to do this is with a
3928 * checksum. Just pure parsing does not really catch much.
3933 static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3934 struct tdb_validation_status *state)
3936 if (dbuf.dsize != 4) {
3937 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3938 "key %s (len %u != 4) ?\n",
3939 keystr, (unsigned int)dbuf.dsize));
3940 state->bad_entry = true;
3941 state->success = false;
3945 DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
3949 /***********************************************************************
3950 A list of all possible cache tdb keys with associated validation
3952 ***********************************************************************/
3954 struct key_val_struct {
3955 const char *keyname;
3956 int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
3958 {"SEQNUM/", validate_seqnum},
3959 {"NS/", validate_ns},
3960 {"SN/", validate_sn},
3962 {"LOC_POL/", validate_loc_pol},
3963 {"PWD_POL/", validate_pwd_pol},
3964 {"CRED/", validate_cred},
3965 {"UL/", validate_ul},
3966 {"GL/", validate_gl},
3967 {"UG/", validate_ug},
3968 {"UA", validate_ua},
3969 {"GM/", validate_gm},
3970 {"DR/", validate_dr},
3971 {"DE/", validate_de},
3972 {"NSS/PWINFO/", validate_pwinfo},
3973 {"TRUSTDOMCACHE/", validate_trustdomcache},
3974 {"NSS/NA/", validate_nss_na},
3975 {"NSS/AN/", validate_nss_an},
3976 {"WINBINDD_OFFLINE", validate_offline},
3977 {"NDR/", validate_ndr},
3978 {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
3982 /***********************************************************************
3983 Function to look at every entry in the tdb and validate it as far as
3985 ***********************************************************************/
3987 static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
3990 unsigned int max_key_len = 1024;
3991 struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
3993 /* Paranoia check. */
3994 if (strncmp("UA/", (const char *)kbuf.dptr, 3) == 0) {
3995 max_key_len = 1024 * 1024;
3997 if (kbuf.dsize > max_key_len) {
3998 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4000 (unsigned int)kbuf.dsize, (unsigned int)max_key_len));
4004 for (i = 0; key_val[i].keyname; i++) {
4005 size_t namelen = strlen(key_val[i].keyname);
4006 if (kbuf.dsize >= namelen && (
4007 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
4008 TALLOC_CTX *mem_ctx;
4012 keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
4016 memcpy(keystr, kbuf.dptr, kbuf.dsize);
4017 keystr[kbuf.dsize] = '\0';
4019 mem_ctx = talloc_init("validate_ctx");
4025 ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
4029 talloc_destroy(mem_ctx);
4034 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4035 dump_data(0, (uint8 *)kbuf.dptr, kbuf.dsize);
4036 DEBUG(0,("data :\n"));
4037 dump_data(0, (uint8 *)dbuf.dptr, dbuf.dsize);
4038 v_state->unknown_key = true;
4039 v_state->success = false;
4040 return 1; /* terminate. */
4043 static void validate_panic(const char *const why)
4045 DEBUG(0,("validating cache: would panic %s\n", why ));
4046 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4050 /***********************************************************************
4051 Try and validate every entry in the winbindd cache. If we fail here,
4052 delete the cache tdb and return non-zero.
4053 ***********************************************************************/
4055 int winbindd_validate_cache(void)
4058 const char *tdb_path = cache_path("winbindd_cache.tdb");
4059 TDB_CONTEXT *tdb = NULL;
4061 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4062 smb_panic_fn = validate_panic;
4065 tdb = tdb_open_log(tdb_path,
4066 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
4067 TDB_INCOMPATIBLE_HASH |
4068 ( lp_winbind_offline_logon()
4070 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
4074 DEBUG(0, ("winbindd_validate_cache: "
4075 "error opening/initializing tdb\n"));
4080 ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
4083 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4084 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
4089 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4090 smb_panic_fn = smb_panic;
4094 /***********************************************************************
4095 Try and validate every entry in the winbindd cache.
4096 ***********************************************************************/
4098 int winbindd_validate_cache_nobackup(void)
4101 const char *tdb_path = cache_path("winbindd_cache.tdb");
4103 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4104 smb_panic_fn = validate_panic;
4107 if (wcache == NULL || wcache->tdb == NULL) {
4108 ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
4110 ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
4114 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4118 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4120 smb_panic_fn = smb_panic;
4124 bool winbindd_cache_validate_and_initialize(void)
4126 close_winbindd_cache();
4128 if (lp_winbind_offline_logon()) {
4129 if (winbindd_validate_cache() < 0) {
4130 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4131 "could be restored.\n"));
4135 return initialize_winbindd_cache();
4138 /*********************************************************************
4139 ********************************************************************/
4141 static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
4142 struct winbindd_tdc_domain **domains,
4143 size_t *num_domains )
4145 struct winbindd_tdc_domain *list = NULL;
4148 bool set_only = false;
4150 /* don't allow duplicates */
4155 for ( i=0; i< (*num_domains); i++ ) {
4156 if ( strequal( new_dom->name, list[i].domain_name ) ) {
4157 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4168 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, 1 );
4171 list = TALLOC_REALLOC_ARRAY( *domains, *domains,
4172 struct winbindd_tdc_domain,
4177 ZERO_STRUCT( list[idx] );
4183 list[idx].domain_name = talloc_strdup( list, new_dom->name );
4184 list[idx].dns_name = talloc_strdup( list, new_dom->alt_name );
4186 if ( !is_null_sid( &new_dom->sid ) ) {
4187 sid_copy( &list[idx].sid, &new_dom->sid );
4189 sid_copy(&list[idx].sid, &global_sid_NULL);
4192 if ( new_dom->domain_flags != 0x0 )
4193 list[idx].trust_flags = new_dom->domain_flags;
4195 if ( new_dom->domain_type != 0x0 )
4196 list[idx].trust_type = new_dom->domain_type;
4198 if ( new_dom->domain_trust_attribs != 0x0 )
4199 list[idx].trust_attribs = new_dom->domain_trust_attribs;
4203 *num_domains = idx + 1;
4209 /*********************************************************************
4210 ********************************************************************/
4212 static TDB_DATA make_tdc_key( const char *domain_name )
4214 char *keystr = NULL;
4215 TDB_DATA key = { NULL, 0 };
4217 if ( !domain_name ) {
4218 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4222 if (asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name ) == -1) {
4225 key = string_term_tdb_data(keystr);
4230 /*********************************************************************
4231 ********************************************************************/
4233 static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
4235 unsigned char **buf )
4237 unsigned char *buffer = NULL;
4242 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4250 /* Store the number of array items first */
4251 len += tdb_pack( buffer+len, buflen-len, "d",
4254 /* now pack each domain trust record */
4255 for ( i=0; i<num_domains; i++ ) {
4260 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4261 domains[i].domain_name,
4262 domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
4265 len += tdb_pack( buffer+len, buflen-len, "fffddd",
4266 domains[i].domain_name,
4267 domains[i].dns_name,
4268 sid_to_fstring(tmp, &domains[i].sid),
4269 domains[i].trust_flags,
4270 domains[i].trust_attribs,
4271 domains[i].trust_type );
4274 if ( buflen < len ) {
4276 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
4277 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4291 /*********************************************************************
4292 ********************************************************************/
4294 static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
4295 struct winbindd_tdc_domain **domains )
4297 fstring domain_name, dns_name, sid_string;
4298 uint32 type, attribs, flags;
4302 struct winbindd_tdc_domain *list = NULL;
4304 /* get the number of domains */
4305 len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
4307 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4311 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, num_domains );
4313 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4317 for ( i=0; i<num_domains; i++ ) {
4318 len += tdb_unpack( buf+len, buflen-len, "fffddd",
4327 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4328 TALLOC_FREE( list );
4332 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4333 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4334 domain_name, dns_name, sid_string,
4335 flags, attribs, type));
4337 list[i].domain_name = talloc_strdup( list, domain_name );
4338 list[i].dns_name = talloc_strdup( list, dns_name );
4339 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
4340 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4343 list[i].trust_flags = flags;
4344 list[i].trust_attribs = attribs;
4345 list[i].trust_type = type;
4353 /*********************************************************************
4354 ********************************************************************/
4356 static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
4358 TDB_DATA key = make_tdc_key( lp_workgroup() );
4359 TDB_DATA data = { NULL, 0 };
4365 /* See if we were asked to delete the cache entry */
4368 ret = tdb_delete( wcache->tdb, key );
4372 data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
4379 ret = tdb_store( wcache->tdb, key, data, 0 );
4382 SAFE_FREE( data.dptr );
4383 SAFE_FREE( key.dptr );
4385 return ( ret != -1 );
4388 /*********************************************************************
4389 ********************************************************************/
4391 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
4393 TDB_DATA key = make_tdc_key( lp_workgroup() );
4394 TDB_DATA data = { NULL, 0 };
4402 data = tdb_fetch( wcache->tdb, key );
4404 SAFE_FREE( key.dptr );
4409 *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
4411 SAFE_FREE( data.dptr );
4419 /*********************************************************************
4420 ********************************************************************/
4422 bool wcache_tdc_add_domain( struct winbindd_domain *domain )
4424 struct winbindd_tdc_domain *dom_list = NULL;
4425 size_t num_domains = 0;
4428 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4429 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4430 domain->name, domain->alt_name,
4431 sid_string_dbg(&domain->sid),
4432 domain->domain_flags,
4433 domain->domain_trust_attribs,
4434 domain->domain_type));
4436 if ( !init_wcache() ) {
4440 /* fetch the list */
4442 wcache_tdc_fetch_list( &dom_list, &num_domains );
4444 /* add the new domain */
4446 if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
4450 /* pack the domain */
4452 if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
4460 TALLOC_FREE( dom_list );
4465 /*********************************************************************
4466 ********************************************************************/
4468 struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
4470 struct winbindd_tdc_domain *dom_list = NULL;
4471 size_t num_domains = 0;
4473 struct winbindd_tdc_domain *d = NULL;
4475 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
4477 if ( !init_wcache() ) {
4481 /* fetch the list */
4483 wcache_tdc_fetch_list( &dom_list, &num_domains );
4485 for ( i=0; i<num_domains; i++ ) {
4486 if ( strequal(name, dom_list[i].domain_name) ||
4487 strequal(name, dom_list[i].dns_name) )
4489 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4492 d = TALLOC_P( ctx, struct winbindd_tdc_domain );
4496 d->domain_name = talloc_strdup( d, dom_list[i].domain_name );
4497 d->dns_name = talloc_strdup( d, dom_list[i].dns_name );
4498 sid_copy( &d->sid, &dom_list[i].sid );
4499 d->trust_flags = dom_list[i].trust_flags;
4500 d->trust_type = dom_list[i].trust_type;
4501 d->trust_attribs = dom_list[i].trust_attribs;
4507 TALLOC_FREE( dom_list );
4513 /*********************************************************************
4514 ********************************************************************/
4516 void wcache_tdc_clear( void )
4518 if ( !init_wcache() )
4521 wcache_tdc_store_list( NULL, 0 );
4527 /*********************************************************************
4528 ********************************************************************/
4530 static void wcache_save_user_pwinfo(struct winbindd_domain *domain,
4532 const struct dom_sid *user_sid,
4533 const char *homedir,
4538 struct cache_entry *centry;
4541 if ( (centry = centry_start(domain, status)) == NULL )
4544 centry_put_string( centry, homedir );
4545 centry_put_string( centry, shell );
4546 centry_put_string( centry, gecos );
4547 centry_put_uint32( centry, gid );
4549 centry_end(centry, "NSS/PWINFO/%s", sid_to_fstring(tmp, user_sid) );
4551 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid) ));
4553 centry_free(centry);
4558 NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
4559 const struct dom_sid *user_sid,
4561 ADS_STRUCT *ads, LDAPMessage *msg,
4562 const char **homedir, const char **shell,
4563 const char **gecos, gid_t *p_gid)
4565 struct winbind_cache *cache = get_cache(domain);
4566 struct cache_entry *centry = NULL;
4573 centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s",
4574 sid_to_fstring(tmp, user_sid));
4579 *homedir = centry_string( centry, ctx );
4580 *shell = centry_string( centry, ctx );
4581 *gecos = centry_string( centry, ctx );
4582 *p_gid = centry_uint32( centry );
4584 centry_free(centry);
4586 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4587 sid_string_dbg(user_sid)));
4589 return NT_STATUS_OK;
4593 nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg,
4594 homedir, shell, gecos, p_gid );
4596 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status)));
4598 if ( NT_STATUS_IS_OK(nt_status) ) {
4599 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir));
4600 DEBUGADD(10, ("\tshell = '%s'\n", *shell));
4601 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos));
4602 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid));
4604 wcache_save_user_pwinfo( domain, nt_status, user_sid,
4605 *homedir, *shell, *gecos, *p_gid );
4608 if ( NT_STATUS_EQUAL( nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
4609 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4611 set_domain_offline( domain );
4619 /* the cache backend methods are exposed via this structure */
4620 struct winbindd_methods cache_methods = {
4638 static bool wcache_ndr_key(TALLOC_CTX *mem_ctx, char *domain_name,
4639 uint32_t opnum, const DATA_BLOB *req,
4645 key = talloc_asprintf(mem_ctx, "NDR/%s/%d/", domain_name, (int)opnum);
4649 keylen = talloc_get_size(key) - 1;
4651 key = talloc_realloc(mem_ctx, key, char, keylen + req->length);
4655 memcpy(key + keylen, req->data, req->length);
4657 pkey->dptr = (uint8_t *)key;
4658 pkey->dsize = talloc_get_size(key);
4662 static bool wcache_opnum_cacheable(uint32_t opnum)
4665 case NDR_WBINT_PING:
4666 case NDR_WBINT_QUERYSEQUENCENUMBER:
4667 case NDR_WBINT_ALLOCATEUID:
4668 case NDR_WBINT_ALLOCATEGID:
4669 case NDR_WBINT_CHECKMACHINEACCOUNT:
4670 case NDR_WBINT_CHANGEMACHINEACCOUNT:
4671 case NDR_WBINT_PINGDC:
4677 bool wcache_fetch_ndr(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
4678 uint32_t opnum, const DATA_BLOB *req, DATA_BLOB *resp)
4683 if (!wcache_opnum_cacheable(opnum) ||
4684 is_my_own_sam_domain(domain) ||
4685 is_builtin_domain(domain)) {
4689 if (wcache->tdb == NULL) {
4693 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4696 data = tdb_fetch(wcache->tdb, key);
4697 TALLOC_FREE(key.dptr);
4699 if (data.dptr == NULL) {
4702 if (data.dsize < 4) {
4706 if (!is_domain_offline(domain)) {
4707 uint32_t entry_seqnum, dom_seqnum, last_check;
4709 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum,
4713 entry_seqnum = IVAL(data.dptr, 0);
4714 if (entry_seqnum != dom_seqnum) {
4715 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4716 (int)entry_seqnum));
4721 resp->data = (uint8_t *)talloc_memdup(mem_ctx, data.dptr + 4,
4723 if (resp->data == NULL) {
4724 DEBUG(10, ("talloc failed\n"));
4727 resp->length = data.dsize - 4;
4731 SAFE_FREE(data.dptr);
4735 void wcache_store_ndr(struct winbindd_domain *domain, uint32_t opnum,
4736 const DATA_BLOB *req, const DATA_BLOB *resp)
4739 uint32_t dom_seqnum, last_check;
4741 if (!wcache_opnum_cacheable(opnum) ||
4742 is_my_own_sam_domain(domain) ||
4743 is_builtin_domain(domain)) {
4747 if (wcache->tdb == NULL) {
4751 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum, &last_check)) {
4752 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4757 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4761 data.dsize = resp->length + 4;
4762 data.dptr = talloc_array(key.dptr, uint8_t, data.dsize);
4763 if (data.dptr == NULL) {
4767 SIVAL(data.dptr, 0, dom_seqnum);
4768 memcpy(data.dptr+4, resp->data, resp->length);
4770 tdb_store(wcache->tdb, key, data, 0);
4773 TALLOC_FREE(key.dptr);