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/dom_sid.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 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
3076 O_RDWR|O_CREAT, 0600);
3078 if (wcache->tdb == NULL) {
3079 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3086 /************************************************************************
3087 This is called by the parent to initialize the cache file.
3088 We don't need sophisticated locking here as we know we're the
3090 ************************************************************************/
3092 bool initialize_winbindd_cache(void)
3094 bool cache_bad = true;
3097 if (!init_wcache()) {
3098 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3102 /* Check version number. */
3103 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
3104 vers == WINBINDD_CACHE_VERSION) {
3109 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3110 "and re-creating with version number %d\n",
3111 WINBINDD_CACHE_VERSION ));
3113 tdb_close(wcache->tdb);
3116 if (unlink(cache_path("winbindd_cache.tdb")) == -1) {
3117 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3118 cache_path("winbindd_cache.tdb"),
3122 if (!init_wcache()) {
3123 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3124 "init_wcache failed.\n"));
3128 /* Write the version. */
3129 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
3130 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3131 tdb_errorstr(wcache->tdb) ));
3136 tdb_close(wcache->tdb);
3141 void close_winbindd_cache(void)
3147 tdb_close(wcache->tdb);
3152 bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
3153 char **domain_name, char **name,
3154 enum lsa_SidType *type)
3156 struct winbindd_domain *domain;
3159 domain = find_lookup_domain_from_sid(sid);
3160 if (domain == NULL) {
3163 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
3165 return NT_STATUS_IS_OK(status);
3168 bool lookup_cached_name(const char *domain_name,
3170 struct dom_sid *sid,
3171 enum lsa_SidType *type)
3173 struct winbindd_domain *domain;
3175 bool original_online_state;
3177 domain = find_lookup_domain_from_name(domain_name);
3178 if (domain == NULL) {
3182 /* If we are doing a cached logon, temporarily set the domain
3183 offline so the cache won't expire the entry */
3185 original_online_state = domain->online;
3186 domain->online = false;
3187 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
3188 domain->online = original_online_state;
3190 return NT_STATUS_IS_OK(status);
3193 void cache_name2sid(struct winbindd_domain *domain,
3194 const char *domain_name, const char *name,
3195 enum lsa_SidType type, const struct dom_sid *sid)
3197 refresh_sequence_number(domain, false);
3198 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
3203 * The original idea that this cache only contains centries has
3204 * been blurred - now other stuff gets put in here. Ensure we
3205 * ignore these things on cleanup.
3208 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
3209 TDB_DATA dbuf, void *state)
3211 struct cache_entry *centry;
3213 if (is_non_centry_key(kbuf)) {
3217 centry = wcache_fetch_raw((char *)kbuf.dptr);
3222 if (!NT_STATUS_IS_OK(centry->status)) {
3223 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
3224 tdb_delete(the_tdb, kbuf);
3227 centry_free(centry);
3231 /* flush the cache */
3232 void wcache_flush_cache(void)
3237 tdb_close(wcache->tdb);
3240 if (!winbindd_use_cache()) {
3244 /* when working offline we must not clear the cache on restart */
3245 wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
3246 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3247 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
3248 O_RDWR|O_CREAT, 0600);
3251 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3255 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
3257 DEBUG(10,("wcache_flush_cache success\n"));
3260 /* Count cached creds */
3262 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3265 int *cred_count = (int*)state;
3267 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3273 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
3275 struct winbind_cache *cache = get_cache(domain);
3280 return NT_STATUS_INTERNAL_DB_ERROR;
3283 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
3285 return NT_STATUS_OK;
3289 struct cred_list *prev, *next;
3294 static struct cred_list *wcache_cred_list;
3296 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3299 struct cred_list *cred;
3301 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3303 cred = SMB_MALLOC_P(struct cred_list);
3305 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3311 /* save a copy of the key */
3313 fstrcpy(cred->name, (const char *)kbuf.dptr);
3314 DLIST_ADD(wcache_cred_list, cred);
3320 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const struct dom_sid *sid)
3322 struct winbind_cache *cache = get_cache(domain);
3325 struct cred_list *cred, *oldest = NULL;
3328 return NT_STATUS_INTERNAL_DB_ERROR;
3331 /* we possibly already have an entry */
3332 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
3334 fstring key_str, tmp;
3336 DEBUG(11,("we already have an entry, deleting that\n"));
3338 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
3340 tdb_delete(cache->tdb, string_tdb_data(key_str));
3342 return NT_STATUS_OK;
3345 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
3347 return NT_STATUS_OK;
3348 } else if ((ret == -1) || (wcache_cred_list == NULL)) {
3349 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3352 ZERO_STRUCTP(oldest);
3354 for (cred = wcache_cred_list; cred; cred = cred->next) {
3359 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
3361 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3363 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
3367 t = IVAL(data.dptr, 0);
3368 SAFE_FREE(data.dptr);
3371 oldest = SMB_MALLOC_P(struct cred_list);
3372 if (oldest == NULL) {
3373 status = NT_STATUS_NO_MEMORY;
3377 fstrcpy(oldest->name, cred->name);
3378 oldest->created = t;
3382 if (t < oldest->created) {
3383 fstrcpy(oldest->name, cred->name);
3384 oldest->created = t;
3388 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
3389 status = NT_STATUS_OK;
3391 status = NT_STATUS_UNSUCCESSFUL;
3394 SAFE_FREE(wcache_cred_list);
3400 /* Change the global online/offline state. */
3401 bool set_global_winbindd_state_offline(void)
3405 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3407 /* Only go offline if someone has created
3408 the key "WINBINDD_OFFLINE" in the cache tdb. */
3410 if (wcache == NULL || wcache->tdb == NULL) {
3411 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3415 if (!lp_winbind_offline_logon()) {
3416 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3420 if (global_winbindd_offline_state) {
3421 /* Already offline. */
3425 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
3427 if (!data.dptr || data.dsize != 4) {
3428 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3429 SAFE_FREE(data.dptr);
3432 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3433 global_winbindd_offline_state = true;
3434 SAFE_FREE(data.dptr);
3439 void set_global_winbindd_state_online(void)
3441 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3443 if (!lp_winbind_offline_logon()) {
3444 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3448 if (!global_winbindd_offline_state) {
3449 /* Already online. */
3452 global_winbindd_offline_state = false;
3458 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3459 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
3462 bool get_global_winbindd_state_offline(void)
3464 return global_winbindd_offline_state;
3467 /***********************************************************************
3468 Validate functions for all possible cache tdb keys.
3469 ***********************************************************************/
3471 static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
3472 struct tdb_validation_status *state)
3474 struct cache_entry *centry;
3476 centry = SMB_XMALLOC_P(struct cache_entry);
3477 centry->data = (unsigned char *)memdup(data.dptr, data.dsize);
3478 if (!centry->data) {
3482 centry->len = data.dsize;
3485 if (centry->len < 8) {
3486 /* huh? corrupt cache? */
3487 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr));
3488 centry_free(centry);
3489 state->bad_entry = true;
3490 state->success = false;
3494 centry->status = NT_STATUS(centry_uint32(centry));
3495 centry->sequence_number = centry_uint32(centry);
3499 static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3500 struct tdb_validation_status *state)
3502 if (dbuf.dsize != 8) {
3503 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3504 keystr, (unsigned int)dbuf.dsize ));
3505 state->bad_entry = true;
3511 static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3512 struct tdb_validation_status *state)
3514 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3519 (void)centry_uint32(centry);
3520 if (NT_STATUS_IS_OK(centry->status)) {
3522 (void)centry_sid(centry, &sid);
3525 centry_free(centry);
3527 if (!(state->success)) {
3530 DEBUG(10,("validate_ns: %s ok\n", keystr));
3534 static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3535 struct tdb_validation_status *state)
3537 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3542 if (NT_STATUS_IS_OK(centry->status)) {
3543 (void)centry_uint32(centry);
3544 (void)centry_string(centry, mem_ctx);
3545 (void)centry_string(centry, mem_ctx);
3548 centry_free(centry);
3550 if (!(state->success)) {
3553 DEBUG(10,("validate_sn: %s ok\n", keystr));
3557 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3558 struct tdb_validation_status *state)
3560 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3567 (void)centry_string(centry, mem_ctx);
3568 (void)centry_string(centry, mem_ctx);
3569 (void)centry_string(centry, mem_ctx);
3570 (void)centry_string(centry, mem_ctx);
3571 (void)centry_uint32(centry);
3572 (void)centry_sid(centry, &sid);
3573 (void)centry_sid(centry, &sid);
3575 centry_free(centry);
3577 if (!(state->success)) {
3580 DEBUG(10,("validate_u: %s ok\n", keystr));
3584 static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3585 struct tdb_validation_status *state)
3587 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3593 (void)centry_nttime(centry);
3594 (void)centry_nttime(centry);
3595 (void)centry_uint16(centry);
3597 centry_free(centry);
3599 if (!(state->success)) {
3602 DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
3606 static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3607 struct tdb_validation_status *state)
3609 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3615 (void)centry_uint16(centry);
3616 (void)centry_uint16(centry);
3617 (void)centry_uint32(centry);
3618 (void)centry_nttime(centry);
3619 (void)centry_nttime(centry);
3621 centry_free(centry);
3623 if (!(state->success)) {
3626 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
3630 static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3631 struct tdb_validation_status *state)
3633 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3639 (void)centry_time(centry);
3640 (void)centry_hash16(centry, mem_ctx);
3642 /* We only have 17 bytes more data in the salted cred case. */
3643 if (centry->len - centry->ofs == 17) {
3644 (void)centry_hash16(centry, mem_ctx);
3647 centry_free(centry);
3649 if (!(state->success)) {
3652 DEBUG(10,("validate_cred: %s ok\n", keystr));
3656 static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3657 struct tdb_validation_status *state)
3659 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3660 int32 num_entries, i;
3666 num_entries = (int32)centry_uint32(centry);
3668 for (i=0; i< num_entries; i++) {
3670 (void)centry_string(centry, mem_ctx);
3671 (void)centry_string(centry, mem_ctx);
3672 (void)centry_string(centry, mem_ctx);
3673 (void)centry_string(centry, mem_ctx);
3674 (void)centry_sid(centry, &sid);
3675 (void)centry_sid(centry, &sid);
3678 centry_free(centry);
3680 if (!(state->success)) {
3683 DEBUG(10,("validate_ul: %s ok\n", keystr));
3687 static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3688 struct tdb_validation_status *state)
3690 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3691 int32 num_entries, i;
3697 num_entries = centry_uint32(centry);
3699 for (i=0; i< num_entries; i++) {
3700 (void)centry_string(centry, mem_ctx);
3701 (void)centry_string(centry, mem_ctx);
3702 (void)centry_uint32(centry);
3705 centry_free(centry);
3707 if (!(state->success)) {
3710 DEBUG(10,("validate_gl: %s ok\n", keystr));
3714 static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3715 struct tdb_validation_status *state)
3717 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3718 int32 num_groups, i;
3724 num_groups = centry_uint32(centry);
3726 for (i=0; i< num_groups; i++) {
3728 centry_sid(centry, &sid);
3731 centry_free(centry);
3733 if (!(state->success)) {
3736 DEBUG(10,("validate_ug: %s ok\n", keystr));
3740 static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3741 struct tdb_validation_status *state)
3743 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3744 int32 num_aliases, i;
3750 num_aliases = centry_uint32(centry);
3752 for (i=0; i < num_aliases; i++) {
3753 (void)centry_uint32(centry);
3756 centry_free(centry);
3758 if (!(state->success)) {
3761 DEBUG(10,("validate_ua: %s ok\n", keystr));
3765 static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3766 struct tdb_validation_status *state)
3768 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3775 num_names = centry_uint32(centry);
3777 for (i=0; i< num_names; i++) {
3779 centry_sid(centry, &sid);
3780 (void)centry_string(centry, mem_ctx);
3781 (void)centry_uint32(centry);
3784 centry_free(centry);
3786 if (!(state->success)) {
3789 DEBUG(10,("validate_gm: %s ok\n", keystr));
3793 static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3794 struct tdb_validation_status *state)
3796 /* Can't say anything about this other than must be nonzero. */
3797 if (dbuf.dsize == 0) {
3798 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3800 state->bad_entry = true;
3801 state->success = false;
3805 DEBUG(10,("validate_dr: %s ok\n", keystr));
3809 static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3810 struct tdb_validation_status *state)
3812 /* Can't say anything about this other than must be nonzero. */
3813 if (dbuf.dsize == 0) {
3814 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3816 state->bad_entry = true;
3817 state->success = false;
3821 DEBUG(10,("validate_de: %s ok\n", keystr));
3825 static int validate_pwinfo(TALLOC_CTX *mem_ctx, const char *keystr,
3826 TDB_DATA dbuf, struct tdb_validation_status *state)
3828 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3834 (void)centry_string(centry, mem_ctx);
3835 (void)centry_string(centry, mem_ctx);
3836 (void)centry_string(centry, mem_ctx);
3837 (void)centry_uint32(centry);
3839 centry_free(centry);
3841 if (!(state->success)) {
3844 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3848 static int validate_nss_an(TALLOC_CTX *mem_ctx, const char *keystr,
3850 struct tdb_validation_status *state)
3852 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3858 (void)centry_string( centry, mem_ctx );
3860 centry_free(centry);
3862 if (!(state->success)) {
3865 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3869 static int validate_nss_na(TALLOC_CTX *mem_ctx, const char *keystr,
3871 struct tdb_validation_status *state)
3873 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3879 (void)centry_string( centry, mem_ctx );
3881 centry_free(centry);
3883 if (!(state->success)) {
3886 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3890 static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
3892 struct tdb_validation_status *state)
3894 if (dbuf.dsize == 0) {
3895 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3896 "key %s (len ==0) ?\n", keystr));
3897 state->bad_entry = true;
3898 state->success = false;
3902 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
3903 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3907 static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3908 struct tdb_validation_status *state)
3910 if (dbuf.dsize != 4) {
3911 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3912 keystr, (unsigned int)dbuf.dsize ));
3913 state->bad_entry = true;
3914 state->success = false;
3917 DEBUG(10,("validate_offline: %s ok\n", keystr));
3921 static int validate_ndr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3922 struct tdb_validation_status *state)
3925 * Ignore validation for now. The proper way to do this is with a
3926 * checksum. Just pure parsing does not really catch much.
3931 static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3932 struct tdb_validation_status *state)
3934 if (dbuf.dsize != 4) {
3935 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3936 "key %s (len %u != 4) ?\n",
3937 keystr, (unsigned int)dbuf.dsize));
3938 state->bad_entry = true;
3939 state->success = false;
3943 DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
3947 /***********************************************************************
3948 A list of all possible cache tdb keys with associated validation
3950 ***********************************************************************/
3952 struct key_val_struct {
3953 const char *keyname;
3954 int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
3956 {"SEQNUM/", validate_seqnum},
3957 {"NS/", validate_ns},
3958 {"SN/", validate_sn},
3960 {"LOC_POL/", validate_loc_pol},
3961 {"PWD_POL/", validate_pwd_pol},
3962 {"CRED/", validate_cred},
3963 {"UL/", validate_ul},
3964 {"GL/", validate_gl},
3965 {"UG/", validate_ug},
3966 {"UA", validate_ua},
3967 {"GM/", validate_gm},
3968 {"DR/", validate_dr},
3969 {"DE/", validate_de},
3970 {"NSS/PWINFO/", validate_pwinfo},
3971 {"TRUSTDOMCACHE/", validate_trustdomcache},
3972 {"NSS/NA/", validate_nss_na},
3973 {"NSS/AN/", validate_nss_an},
3974 {"WINBINDD_OFFLINE", validate_offline},
3975 {"NDR/", validate_ndr},
3976 {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
3980 /***********************************************************************
3981 Function to look at every entry in the tdb and validate it as far as
3983 ***********************************************************************/
3985 static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
3988 unsigned int max_key_len = 1024;
3989 struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
3991 /* Paranoia check. */
3992 if (strncmp("UA/", (const char *)kbuf.dptr, 3) == 0) {
3993 max_key_len = 1024 * 1024;
3995 if (kbuf.dsize > max_key_len) {
3996 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
3998 (unsigned int)kbuf.dsize, (unsigned int)max_key_len));
4002 for (i = 0; key_val[i].keyname; i++) {
4003 size_t namelen = strlen(key_val[i].keyname);
4004 if (kbuf.dsize >= namelen && (
4005 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
4006 TALLOC_CTX *mem_ctx;
4010 keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
4014 memcpy(keystr, kbuf.dptr, kbuf.dsize);
4015 keystr[kbuf.dsize] = '\0';
4017 mem_ctx = talloc_init("validate_ctx");
4023 ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
4027 talloc_destroy(mem_ctx);
4032 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4033 dump_data(0, (uint8 *)kbuf.dptr, kbuf.dsize);
4034 DEBUG(0,("data :\n"));
4035 dump_data(0, (uint8 *)dbuf.dptr, dbuf.dsize);
4036 v_state->unknown_key = true;
4037 v_state->success = false;
4038 return 1; /* terminate. */
4041 static void validate_panic(const char *const why)
4043 DEBUG(0,("validating cache: would panic %s\n", why ));
4044 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4048 /***********************************************************************
4049 Try and validate every entry in the winbindd cache. If we fail here,
4050 delete the cache tdb and return non-zero.
4051 ***********************************************************************/
4053 int winbindd_validate_cache(void)
4056 const char *tdb_path = cache_path("winbindd_cache.tdb");
4057 TDB_CONTEXT *tdb = NULL;
4059 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4060 smb_panic_fn = validate_panic;
4063 tdb = tdb_open_log(tdb_path,
4064 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
4065 ( lp_winbind_offline_logon()
4067 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
4071 DEBUG(0, ("winbindd_validate_cache: "
4072 "error opening/initializing tdb\n"));
4077 ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
4080 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4081 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
4086 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4087 smb_panic_fn = smb_panic;
4091 /***********************************************************************
4092 Try and validate every entry in the winbindd cache.
4093 ***********************************************************************/
4095 int winbindd_validate_cache_nobackup(void)
4098 const char *tdb_path = cache_path("winbindd_cache.tdb");
4100 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4101 smb_panic_fn = validate_panic;
4104 if (wcache == NULL || wcache->tdb == NULL) {
4105 ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
4107 ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
4111 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4115 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4117 smb_panic_fn = smb_panic;
4121 bool winbindd_cache_validate_and_initialize(void)
4123 close_winbindd_cache();
4125 if (lp_winbind_offline_logon()) {
4126 if (winbindd_validate_cache() < 0) {
4127 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4128 "could be restored.\n"));
4132 return initialize_winbindd_cache();
4135 /*********************************************************************
4136 ********************************************************************/
4138 static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
4139 struct winbindd_tdc_domain **domains,
4140 size_t *num_domains )
4142 struct winbindd_tdc_domain *list = NULL;
4145 bool set_only = false;
4147 /* don't allow duplicates */
4152 for ( i=0; i< (*num_domains); i++ ) {
4153 if ( strequal( new_dom->name, list[i].domain_name ) ) {
4154 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4165 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, 1 );
4168 list = TALLOC_REALLOC_ARRAY( *domains, *domains,
4169 struct winbindd_tdc_domain,
4174 ZERO_STRUCT( list[idx] );
4180 list[idx].domain_name = talloc_strdup( list, new_dom->name );
4181 list[idx].dns_name = talloc_strdup( list, new_dom->alt_name );
4183 if ( !is_null_sid( &new_dom->sid ) ) {
4184 sid_copy( &list[idx].sid, &new_dom->sid );
4186 sid_copy(&list[idx].sid, &global_sid_NULL);
4189 if ( new_dom->domain_flags != 0x0 )
4190 list[idx].trust_flags = new_dom->domain_flags;
4192 if ( new_dom->domain_type != 0x0 )
4193 list[idx].trust_type = new_dom->domain_type;
4195 if ( new_dom->domain_trust_attribs != 0x0 )
4196 list[idx].trust_attribs = new_dom->domain_trust_attribs;
4200 *num_domains = idx + 1;
4206 /*********************************************************************
4207 ********************************************************************/
4209 static TDB_DATA make_tdc_key( const char *domain_name )
4211 char *keystr = NULL;
4212 TDB_DATA key = { NULL, 0 };
4214 if ( !domain_name ) {
4215 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4219 if (asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name ) == -1) {
4222 key = string_term_tdb_data(keystr);
4227 /*********************************************************************
4228 ********************************************************************/
4230 static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
4232 unsigned char **buf )
4234 unsigned char *buffer = NULL;
4239 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4247 /* Store the number of array items first */
4248 len += tdb_pack( buffer+len, buflen-len, "d",
4251 /* now pack each domain trust record */
4252 for ( i=0; i<num_domains; i++ ) {
4257 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4258 domains[i].domain_name,
4259 domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
4262 len += tdb_pack( buffer+len, buflen-len, "fffddd",
4263 domains[i].domain_name,
4264 domains[i].dns_name,
4265 sid_to_fstring(tmp, &domains[i].sid),
4266 domains[i].trust_flags,
4267 domains[i].trust_attribs,
4268 domains[i].trust_type );
4271 if ( buflen < len ) {
4273 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
4274 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4288 /*********************************************************************
4289 ********************************************************************/
4291 static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
4292 struct winbindd_tdc_domain **domains )
4294 fstring domain_name, dns_name, sid_string;
4295 uint32 type, attribs, flags;
4299 struct winbindd_tdc_domain *list = NULL;
4301 /* get the number of domains */
4302 len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
4304 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4308 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, num_domains );
4310 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4314 for ( i=0; i<num_domains; i++ ) {
4315 len += tdb_unpack( buf+len, buflen-len, "fffddd",
4324 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4325 TALLOC_FREE( list );
4329 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4330 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4331 domain_name, dns_name, sid_string,
4332 flags, attribs, type));
4334 list[i].domain_name = talloc_strdup( list, domain_name );
4335 list[i].dns_name = talloc_strdup( list, dns_name );
4336 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
4337 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4340 list[i].trust_flags = flags;
4341 list[i].trust_attribs = attribs;
4342 list[i].trust_type = type;
4350 /*********************************************************************
4351 ********************************************************************/
4353 static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
4355 TDB_DATA key = make_tdc_key( lp_workgroup() );
4356 TDB_DATA data = { NULL, 0 };
4362 /* See if we were asked to delete the cache entry */
4365 ret = tdb_delete( wcache->tdb, key );
4369 data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
4376 ret = tdb_store( wcache->tdb, key, data, 0 );
4379 SAFE_FREE( data.dptr );
4380 SAFE_FREE( key.dptr );
4382 return ( ret != -1 );
4385 /*********************************************************************
4386 ********************************************************************/
4388 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
4390 TDB_DATA key = make_tdc_key( lp_workgroup() );
4391 TDB_DATA data = { NULL, 0 };
4399 data = tdb_fetch( wcache->tdb, key );
4401 SAFE_FREE( key.dptr );
4406 *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
4408 SAFE_FREE( data.dptr );
4416 /*********************************************************************
4417 ********************************************************************/
4419 bool wcache_tdc_add_domain( struct winbindd_domain *domain )
4421 struct winbindd_tdc_domain *dom_list = NULL;
4422 size_t num_domains = 0;
4425 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4426 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4427 domain->name, domain->alt_name,
4428 sid_string_dbg(&domain->sid),
4429 domain->domain_flags,
4430 domain->domain_trust_attribs,
4431 domain->domain_type));
4433 if ( !init_wcache() ) {
4437 /* fetch the list */
4439 wcache_tdc_fetch_list( &dom_list, &num_domains );
4441 /* add the new domain */
4443 if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
4447 /* pack the domain */
4449 if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
4457 TALLOC_FREE( dom_list );
4462 /*********************************************************************
4463 ********************************************************************/
4465 struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
4467 struct winbindd_tdc_domain *dom_list = NULL;
4468 size_t num_domains = 0;
4470 struct winbindd_tdc_domain *d = NULL;
4472 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
4474 if ( !init_wcache() ) {
4478 /* fetch the list */
4480 wcache_tdc_fetch_list( &dom_list, &num_domains );
4482 for ( i=0; i<num_domains; i++ ) {
4483 if ( strequal(name, dom_list[i].domain_name) ||
4484 strequal(name, dom_list[i].dns_name) )
4486 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4489 d = TALLOC_P( ctx, struct winbindd_tdc_domain );
4493 d->domain_name = talloc_strdup( d, dom_list[i].domain_name );
4494 d->dns_name = talloc_strdup( d, dom_list[i].dns_name );
4495 sid_copy( &d->sid, &dom_list[i].sid );
4496 d->trust_flags = dom_list[i].trust_flags;
4497 d->trust_type = dom_list[i].trust_type;
4498 d->trust_attribs = dom_list[i].trust_attribs;
4504 TALLOC_FREE( dom_list );
4510 /*********************************************************************
4511 ********************************************************************/
4513 void wcache_tdc_clear( void )
4515 if ( !init_wcache() )
4518 wcache_tdc_store_list( NULL, 0 );
4524 /*********************************************************************
4525 ********************************************************************/
4527 static void wcache_save_user_pwinfo(struct winbindd_domain *domain,
4529 const struct dom_sid *user_sid,
4530 const char *homedir,
4535 struct cache_entry *centry;
4538 if ( (centry = centry_start(domain, status)) == NULL )
4541 centry_put_string( centry, homedir );
4542 centry_put_string( centry, shell );
4543 centry_put_string( centry, gecos );
4544 centry_put_uint32( centry, gid );
4546 centry_end(centry, "NSS/PWINFO/%s", sid_to_fstring(tmp, user_sid) );
4548 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid) ));
4550 centry_free(centry);
4553 NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
4554 const struct dom_sid *user_sid,
4556 ADS_STRUCT *ads, LDAPMessage *msg,
4557 const char **homedir, const char **shell,
4558 const char **gecos, gid_t *p_gid)
4560 struct winbind_cache *cache = get_cache(domain);
4561 struct cache_entry *centry = NULL;
4568 centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s",
4569 sid_to_fstring(tmp, user_sid));
4574 *homedir = centry_string( centry, ctx );
4575 *shell = centry_string( centry, ctx );
4576 *gecos = centry_string( centry, ctx );
4577 *p_gid = centry_uint32( centry );
4579 centry_free(centry);
4581 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4582 sid_string_dbg(user_sid)));
4584 return NT_STATUS_OK;
4588 nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg,
4589 homedir, shell, gecos, p_gid );
4591 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status)));
4593 if ( NT_STATUS_IS_OK(nt_status) ) {
4594 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir));
4595 DEBUGADD(10, ("\tshell = '%s'\n", *shell));
4596 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos));
4597 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid));
4599 wcache_save_user_pwinfo( domain, nt_status, user_sid,
4600 *homedir, *shell, *gecos, *p_gid );
4603 if ( NT_STATUS_EQUAL( nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
4604 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4606 set_domain_offline( domain );
4613 /* the cache backend methods are exposed via this structure */
4614 struct winbindd_methods cache_methods = {
4632 static bool wcache_ndr_key(TALLOC_CTX *mem_ctx, char *domain_name,
4633 uint32_t opnum, const DATA_BLOB *req,
4639 key = talloc_asprintf(mem_ctx, "NDR/%s/%d/", domain_name, (int)opnum);
4643 keylen = talloc_get_size(key) - 1;
4645 key = talloc_realloc(mem_ctx, key, char, keylen + req->length);
4649 memcpy(key + keylen, req->data, req->length);
4651 pkey->dptr = (uint8_t *)key;
4652 pkey->dsize = talloc_get_size(key);
4656 static bool wcache_opnum_cacheable(uint32_t opnum)
4659 case NDR_WBINT_PING:
4660 case NDR_WBINT_QUERYSEQUENCENUMBER:
4661 case NDR_WBINT_ALLOCATEUID:
4662 case NDR_WBINT_ALLOCATEGID:
4663 case NDR_WBINT_CHECKMACHINEACCOUNT:
4664 case NDR_WBINT_CHANGEMACHINEACCOUNT:
4665 case NDR_WBINT_PINGDC:
4671 bool wcache_fetch_ndr(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
4672 uint32_t opnum, const DATA_BLOB *req, DATA_BLOB *resp)
4677 if (!wcache_opnum_cacheable(opnum) ||
4678 is_my_own_sam_domain(domain) ||
4679 is_builtin_domain(domain)) {
4683 if (wcache->tdb == NULL) {
4687 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4690 data = tdb_fetch(wcache->tdb, key);
4691 TALLOC_FREE(key.dptr);
4693 if (data.dptr == NULL) {
4696 if (data.dsize < 4) {
4700 if (!is_domain_offline(domain)) {
4701 uint32_t entry_seqnum, dom_seqnum, last_check;
4703 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum,
4707 entry_seqnum = IVAL(data.dptr, 0);
4708 if (entry_seqnum != dom_seqnum) {
4709 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4710 (int)entry_seqnum));
4715 resp->data = (uint8_t *)talloc_memdup(mem_ctx, data.dptr + 4,
4717 if (resp->data == NULL) {
4718 DEBUG(10, ("talloc failed\n"));
4721 resp->length = data.dsize - 4;
4725 SAFE_FREE(data.dptr);
4729 void wcache_store_ndr(struct winbindd_domain *domain, uint32_t opnum,
4730 const DATA_BLOB *req, const DATA_BLOB *resp)
4733 uint32_t dom_seqnum, last_check;
4735 if (!wcache_opnum_cacheable(opnum) ||
4736 is_my_own_sam_domain(domain) ||
4737 is_builtin_domain(domain)) {
4741 if (wcache->tdb == NULL) {
4745 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum, &last_check)) {
4746 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4751 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4755 data.dsize = resp->length + 4;
4756 data.dptr = talloc_array(key.dptr, uint8_t, data.dsize);
4757 if (data.dptr == NULL) {
4761 SIVAL(data.dptr, 0, dom_seqnum);
4762 memcpy(data.dptr+4, resp->data, resp->length);
4764 tdb_store(wcache->tdb, key, data, 0);
4767 TALLOC_FREE(key.dptr);