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 #define DBGC_CLASS DBGC_WINBIND
35 #define WINBINDD_CACHE_VERSION 1
36 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
38 extern struct winbindd_methods reconnect_methods;
40 extern struct winbindd_methods ads_methods;
42 extern struct winbindd_methods builtin_passdb_methods;
45 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
46 * Here are the list of entry types that are *not* stored
47 * as form struct cache_entry in the cache.
50 static const char *non_centry_keys[] = {
55 WINBINDD_CACHE_VERSION_KEYSTR,
59 /************************************************************************
60 Is this key a non-centry type ?
61 ************************************************************************/
63 static bool is_non_centry_key(TDB_DATA kbuf)
67 if (kbuf.dptr == NULL || kbuf.dsize == 0) {
70 for (i = 0; non_centry_keys[i] != NULL; i++) {
71 size_t namelen = strlen(non_centry_keys[i]);
72 if (kbuf.dsize < namelen) {
75 if (strncmp(non_centry_keys[i], (const char *)kbuf.dptr, namelen) == 0) {
82 /* Global online/offline state - False when online. winbindd starts up online
83 and sets this to true if the first query fails and there's an entry in
84 the cache tdb telling us to stay offline. */
86 static bool global_winbindd_offline_state;
88 struct winbind_cache {
94 uint32 sequence_number;
99 void (*smb_panic_fn)(const char *const why) = smb_panic;
101 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
103 static struct winbind_cache *wcache;
105 void winbindd_check_cache_size(time_t t)
107 static time_t last_check_time;
110 if (last_check_time == (time_t)0)
113 if (t - last_check_time < 60 && t - last_check_time > 0)
116 if (wcache == NULL || wcache->tdb == NULL) {
117 DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
121 if (fstat(tdb_fd(wcache->tdb), &st) == -1) {
122 DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno) ));
126 if (st.st_size > WINBINDD_MAX_CACHE_SIZE) {
127 DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
128 (unsigned long)st.st_size,
129 (unsigned long)WINBINDD_MAX_CACHE_SIZE));
130 wcache_flush_cache();
134 /* get the winbind_cache structure */
135 static struct winbind_cache *get_cache(struct winbindd_domain *domain)
137 struct winbind_cache *ret = wcache;
139 /* We have to know what type of domain we are dealing with first. */
141 if (domain->internal) {
142 domain->backend = &builtin_passdb_methods;
143 domain->initialized = True;
145 if ( !domain->initialized ) {
146 init_dc_connection( domain );
150 OK. listen up becasue I'm only going to say this once.
151 We have the following scenarios to consider
152 (a) trusted AD domains on a Samba DC,
153 (b) trusted AD domains and we are joined to a non-kerberos domain
154 (c) trusted AD domains and we are joined to a kerberos (AD) domain
156 For (a) we can always contact the trusted domain using krb5
157 since we have the domain trust account password
159 For (b) we can only use RPC since we have no way of
160 getting a krb5 ticket in our own domain
162 For (c) we can always use krb5 since we have a kerberos trust
167 if (!domain->backend) {
169 struct winbindd_domain *our_domain = domain;
171 /* find our domain first so we can figure out if we
172 are joined to a kerberized domain */
174 if ( !domain->primary )
175 our_domain = find_our_domain();
177 if ((our_domain->active_directory || IS_DC)
178 && domain->active_directory
179 && !lp_winbind_rpc_only()) {
180 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain->name));
181 domain->backend = &ads_methods;
183 #endif /* HAVE_ADS */
184 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain->name));
185 domain->backend = &reconnect_methods;
188 #endif /* HAVE_ADS */
194 ret = SMB_XMALLOC_P(struct winbind_cache);
198 wcache_flush_cache();
204 free a centry structure
206 static void centry_free(struct cache_entry *centry)
210 SAFE_FREE(centry->data);
214 static bool centry_check_bytes(struct cache_entry *centry, size_t nbytes)
216 if (centry->len - centry->ofs < nbytes) {
217 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
218 (unsigned int)nbytes,
219 centry->len - centry->ofs));
226 pull a uint32 from a cache entry
228 static uint32 centry_uint32(struct cache_entry *centry)
232 if (!centry_check_bytes(centry, 4)) {
233 smb_panic_fn("centry_uint32");
235 ret = IVAL(centry->data, centry->ofs);
241 pull a uint16 from a cache entry
243 static uint16 centry_uint16(struct cache_entry *centry)
246 if (!centry_check_bytes(centry, 2)) {
247 smb_panic_fn("centry_uint16");
249 ret = CVAL(centry->data, centry->ofs);
255 pull a uint8 from a cache entry
257 static uint8 centry_uint8(struct cache_entry *centry)
260 if (!centry_check_bytes(centry, 1)) {
261 smb_panic_fn("centry_uint8");
263 ret = CVAL(centry->data, centry->ofs);
269 pull a NTTIME from a cache entry
271 static NTTIME centry_nttime(struct cache_entry *centry)
274 if (!centry_check_bytes(centry, 8)) {
275 smb_panic_fn("centry_nttime");
277 ret = IVAL(centry->data, centry->ofs);
279 ret += (uint64_t)IVAL(centry->data, centry->ofs) << 32;
285 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
287 static time_t centry_time(struct cache_entry *centry)
289 return (time_t)centry_nttime(centry);
292 /* pull a string from a cache entry, using the supplied
295 static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
300 len = centry_uint8(centry);
303 /* a deliberate NULL string */
307 if (!centry_check_bytes(centry, (size_t)len)) {
308 smb_panic_fn("centry_string");
311 ret = TALLOC_ARRAY(mem_ctx, char, len+1);
313 smb_panic_fn("centry_string out of memory\n");
315 memcpy(ret,centry->data + centry->ofs, len);
321 /* pull a hash16 from a cache entry, using the supplied
324 static char *centry_hash16(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
329 len = centry_uint8(centry);
332 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
337 if (!centry_check_bytes(centry, 16)) {
341 ret = TALLOC_ARRAY(mem_ctx, char, 16);
343 smb_panic_fn("centry_hash out of memory\n");
345 memcpy(ret,centry->data + centry->ofs, 16);
350 /* pull a sid from a cache entry, using the supplied
353 static bool centry_sid(struct cache_entry *centry, struct dom_sid *sid)
358 sid_string = centry_string(centry, talloc_tos());
359 if (sid_string == NULL) {
362 ret = string_to_sid(sid, sid_string);
363 TALLOC_FREE(sid_string);
369 pull a NTSTATUS from a cache entry
371 static NTSTATUS centry_ntstatus(struct cache_entry *centry)
375 status = NT_STATUS(centry_uint32(centry));
380 /* the server is considered down if it can't give us a sequence number */
381 static bool wcache_server_down(struct winbindd_domain *domain)
388 ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
391 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
396 static bool wcache_fetch_seqnum(const char *domain_name, uint32_t *seqnum,
397 uint32_t *last_seq_check)
402 if (wcache->tdb == NULL) {
403 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
407 key = talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name);
409 DEBUG(10, ("talloc failed\n"));
413 data = tdb_fetch_bystring(wcache->tdb, key);
416 if (data.dptr == NULL) {
417 DEBUG(10, ("wcache_fetch_seqnum: %s not found\n",
421 if (data.dsize != 8) {
422 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
424 SAFE_FREE(data.dptr);
428 *seqnum = IVAL(data.dptr, 0);
429 *last_seq_check = IVAL(data.dptr, 4);
430 SAFE_FREE(data.dptr);
435 static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
437 uint32 last_check, time_diff;
439 if (!wcache_fetch_seqnum(domain->name, &domain->sequence_number,
441 return NT_STATUS_UNSUCCESSFUL;
443 domain->last_seq_check = last_check;
445 /* have we expired? */
447 time_diff = now - domain->last_seq_check;
448 if ( time_diff > lp_winbind_cache_time() ) {
449 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
450 domain->name, domain->sequence_number,
451 (uint32)domain->last_seq_check));
452 return NT_STATUS_UNSUCCESSFUL;
455 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
456 domain->name, domain->sequence_number,
457 (uint32)domain->last_seq_check));
462 bool wcache_store_seqnum(const char *domain_name, uint32_t seqnum,
463 time_t last_seq_check)
469 if (wcache->tdb == NULL) {
470 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
474 key_str = talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name);
475 if (key_str == NULL) {
476 DEBUG(10, ("talloc_asprintf failed\n"));
480 SIVAL(buf, 0, seqnum);
481 SIVAL(buf, 4, last_seq_check);
483 ret = tdb_store_bystring(wcache->tdb, key_str,
484 make_tdb_data(buf, sizeof(buf)), TDB_REPLACE);
485 TALLOC_FREE(key_str);
487 DEBUG(10, ("tdb_store_bystring failed: %s\n",
488 tdb_errorstr(wcache->tdb)));
489 TALLOC_FREE(key_str);
493 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
494 domain_name, seqnum, (unsigned)last_seq_check));
499 static bool store_cache_seqnum( struct winbindd_domain *domain )
501 return wcache_store_seqnum(domain->name, domain->sequence_number,
502 domain->last_seq_check);
506 refresh the domain sequence number. If force is true
507 then always refresh it, no matter how recently we fetched it
510 static void refresh_sequence_number(struct winbindd_domain *domain, bool force)
514 time_t t = time(NULL);
515 unsigned cache_time = lp_winbind_cache_time();
517 if (is_domain_offline(domain)) {
523 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
524 /* trying to reconnect is expensive, don't do it too often */
525 if (domain->sequence_number == DOM_SEQUENCE_NONE) {
530 time_diff = t - domain->last_seq_check;
532 /* see if we have to refetch the domain sequence number */
533 if (!force && (time_diff < cache_time) &&
534 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
535 NT_STATUS_IS_OK(domain->last_status)) {
536 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
540 /* try to get the sequence number from the tdb cache first */
541 /* this will update the timestamp as well */
543 status = fetch_cache_seqnum( domain, t );
544 if (NT_STATUS_IS_OK(status) &&
545 (domain->sequence_number != DOM_SEQUENCE_NONE) &&
546 NT_STATUS_IS_OK(domain->last_status)) {
550 /* important! make sure that we know if this is a native
551 mode domain or not. And that we can contact it. */
553 if ( winbindd_can_contact_domain( domain ) ) {
554 status = domain->backend->sequence_number(domain,
555 &domain->sequence_number);
557 /* just use the current time */
558 status = NT_STATUS_OK;
559 domain->sequence_number = time(NULL);
563 /* the above call could have set our domain->backend to NULL when
564 * coming from offline to online mode, make sure to reinitialize the
565 * backend - Guenther */
568 if (!NT_STATUS_IS_OK(status)) {
569 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status)));
570 domain->sequence_number = DOM_SEQUENCE_NONE;
573 domain->last_status = status;
574 domain->last_seq_check = time(NULL);
576 /* save the new sequence number in the cache */
577 store_cache_seqnum( domain );
580 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
581 domain->name, domain->sequence_number));
587 decide if a cache entry has expired
589 static bool centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
591 /* If we've been told to be offline - stay in that state... */
592 if (lp_winbind_offline_logon() && global_winbindd_offline_state) {
593 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
594 keystr, domain->name ));
598 /* when the domain is offline return the cached entry.
599 * This deals with transient offline states... */
601 if (!domain->online) {
602 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
603 keystr, domain->name ));
607 /* if the server is OK and our cache entry came from when it was down then
608 the entry is invalid */
609 if ((domain->sequence_number != DOM_SEQUENCE_NONE) &&
610 (centry->sequence_number == DOM_SEQUENCE_NONE)) {
611 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
612 keystr, domain->name ));
616 /* if the server is down or the cache entry is not older than the
617 current sequence number then it is OK */
618 if (wcache_server_down(domain) ||
619 centry->sequence_number == domain->sequence_number) {
620 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
621 keystr, domain->name ));
625 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
626 keystr, domain->name ));
632 static struct cache_entry *wcache_fetch_raw(char *kstr)
635 struct cache_entry *centry;
638 key = string_tdb_data(kstr);
639 data = tdb_fetch(wcache->tdb, key);
645 centry = SMB_XMALLOC_P(struct cache_entry);
646 centry->data = (unsigned char *)data.dptr;
647 centry->len = data.dsize;
650 if (centry->len < 8) {
651 /* huh? corrupt cache? */
652 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr));
657 centry->status = centry_ntstatus(centry);
658 centry->sequence_number = centry_uint32(centry);
664 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
665 number and return status
667 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
668 struct winbindd_domain *domain,
669 const char *format, ...) PRINTF_ATTRIBUTE(3,4);
670 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
671 struct winbindd_domain *domain,
672 const char *format, ...)
676 struct cache_entry *centry;
678 if (!winbindd_use_cache()) {
682 refresh_sequence_number(domain, false);
684 va_start(ap, format);
685 smb_xvasprintf(&kstr, format, ap);
688 centry = wcache_fetch_raw(kstr);
689 if (centry == NULL) {
694 if (centry_expired(domain, kstr, centry)) {
696 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
697 kstr, domain->name ));
704 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
705 kstr, domain->name ));
711 static void wcache_delete(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
712 static void wcache_delete(const char *format, ...)
718 va_start(ap, format);
719 smb_xvasprintf(&kstr, format, ap);
722 key = string_tdb_data(kstr);
724 tdb_delete(wcache->tdb, key);
729 make sure we have at least len bytes available in a centry
731 static void centry_expand(struct cache_entry *centry, uint32 len)
733 if (centry->len - centry->ofs >= len)
736 centry->data = SMB_REALLOC_ARRAY(centry->data, unsigned char,
739 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
740 smb_panic_fn("out of memory in centry_expand");
745 push a uint32 into a centry
747 static void centry_put_uint32(struct cache_entry *centry, uint32 v)
749 centry_expand(centry, 4);
750 SIVAL(centry->data, centry->ofs, v);
755 push a uint16 into a centry
757 static void centry_put_uint16(struct cache_entry *centry, uint16 v)
759 centry_expand(centry, 2);
760 SIVAL(centry->data, centry->ofs, v);
765 push a uint8 into a centry
767 static void centry_put_uint8(struct cache_entry *centry, uint8 v)
769 centry_expand(centry, 1);
770 SCVAL(centry->data, centry->ofs, v);
775 push a string into a centry
777 static void centry_put_string(struct cache_entry *centry, const char *s)
782 /* null strings are marked as len 0xFFFF */
783 centry_put_uint8(centry, 0xFF);
788 /* can't handle more than 254 char strings. Truncating is probably best */
790 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len));
793 centry_put_uint8(centry, len);
794 centry_expand(centry, len);
795 memcpy(centry->data + centry->ofs, s, len);
800 push a 16 byte hash into a centry - treat as 16 byte string.
802 static void centry_put_hash16(struct cache_entry *centry, const uint8 val[16])
804 centry_put_uint8(centry, 16);
805 centry_expand(centry, 16);
806 memcpy(centry->data + centry->ofs, val, 16);
810 static void centry_put_sid(struct cache_entry *centry, const DOM_SID *sid)
813 centry_put_string(centry, sid_to_fstring(sid_string, sid));
818 put NTSTATUS into a centry
820 static void centry_put_ntstatus(struct cache_entry *centry, NTSTATUS status)
822 uint32 status_value = NT_STATUS_V(status);
823 centry_put_uint32(centry, status_value);
828 push a NTTIME into a centry
830 static void centry_put_nttime(struct cache_entry *centry, NTTIME nt)
832 centry_expand(centry, 8);
833 SIVAL(centry->data, centry->ofs, nt & 0xFFFFFFFF);
835 SIVAL(centry->data, centry->ofs, nt >> 32);
840 push a time_t into a centry - use a 64 bit size.
841 NTTIME here is being used as a convenient 64-bit size.
843 static void centry_put_time(struct cache_entry *centry, time_t t)
845 NTTIME nt = (NTTIME)t;
846 centry_put_nttime(centry, nt);
850 start a centry for output. When finished, call centry_end()
852 struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status)
854 struct cache_entry *centry;
859 centry = SMB_XMALLOC_P(struct cache_entry);
861 centry->len = 8192; /* reasonable default */
862 centry->data = SMB_XMALLOC_ARRAY(uint8, centry->len);
864 centry->sequence_number = domain->sequence_number;
865 centry_put_ntstatus(centry, status);
866 centry_put_uint32(centry, centry->sequence_number);
871 finish a centry and write it to the tdb
873 static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
874 static void centry_end(struct cache_entry *centry, const char *format, ...)
880 if (!winbindd_use_cache()) {
884 va_start(ap, format);
885 smb_xvasprintf(&kstr, format, ap);
888 key = string_tdb_data(kstr);
889 data.dptr = centry->data;
890 data.dsize = centry->ofs;
892 tdb_store(wcache->tdb, key, data, TDB_REPLACE);
896 static void wcache_save_name_to_sid(struct winbindd_domain *domain,
897 NTSTATUS status, const char *domain_name,
898 const char *name, const DOM_SID *sid,
899 enum lsa_SidType type)
901 struct cache_entry *centry;
904 centry = centry_start(domain, status);
907 centry_put_uint32(centry, type);
908 centry_put_sid(centry, sid);
909 fstrcpy(uname, name);
911 centry_end(centry, "NS/%s/%s", domain_name, uname);
912 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name,
913 uname, sid_string_dbg(sid), nt_errstr(status)));
917 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
918 const DOM_SID *sid, const char *domain_name, const char *name, enum lsa_SidType type)
920 struct cache_entry *centry;
923 centry = centry_start(domain, status);
927 if (NT_STATUS_IS_OK(status)) {
928 centry_put_uint32(centry, type);
929 centry_put_string(centry, domain_name);
930 centry_put_string(centry, name);
933 centry_end(centry, "SN/%s", sid_to_fstring(sid_string, sid));
934 DEBUG(10,("wcache_save_sid_to_name: %s -> %s (%s)\n", sid_string,
935 name, nt_errstr(status)));
940 static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status,
941 struct wbint_userinfo *info)
943 struct cache_entry *centry;
946 if (is_null_sid(&info->user_sid)) {
950 centry = centry_start(domain, status);
953 centry_put_string(centry, info->acct_name);
954 centry_put_string(centry, info->full_name);
955 centry_put_string(centry, info->homedir);
956 centry_put_string(centry, info->shell);
957 centry_put_uint32(centry, info->primary_gid);
958 centry_put_sid(centry, &info->user_sid);
959 centry_put_sid(centry, &info->group_sid);
960 centry_end(centry, "U/%s", sid_to_fstring(sid_string,
962 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
966 static void wcache_save_lockout_policy(struct winbindd_domain *domain,
968 struct samr_DomInfo12 *lockout_policy)
970 struct cache_entry *centry;
972 centry = centry_start(domain, status);
976 centry_put_nttime(centry, lockout_policy->lockout_duration);
977 centry_put_nttime(centry, lockout_policy->lockout_window);
978 centry_put_uint16(centry, lockout_policy->lockout_threshold);
980 centry_end(centry, "LOC_POL/%s", domain->name);
982 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
989 static void wcache_save_password_policy(struct winbindd_domain *domain,
991 struct samr_DomInfo1 *policy)
993 struct cache_entry *centry;
995 centry = centry_start(domain, status);
999 centry_put_uint16(centry, policy->min_password_length);
1000 centry_put_uint16(centry, policy->password_history_length);
1001 centry_put_uint32(centry, policy->password_properties);
1002 centry_put_nttime(centry, policy->max_password_age);
1003 centry_put_nttime(centry, policy->min_password_age);
1005 centry_end(centry, "PWD_POL/%s", domain->name);
1007 DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
1009 centry_free(centry);
1012 /***************************************************************************
1013 ***************************************************************************/
1015 static void wcache_save_username_alias(struct winbindd_domain *domain,
1017 const char *name, const char *alias)
1019 struct cache_entry *centry;
1022 if ( (centry = centry_start(domain, status)) == NULL )
1025 centry_put_string( centry, alias );
1027 fstrcpy(uname, name);
1029 centry_end(centry, "NSS/NA/%s", uname);
1031 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name, alias ));
1033 centry_free(centry);
1036 static void wcache_save_alias_username(struct winbindd_domain *domain,
1038 const char *alias, const char *name)
1040 struct cache_entry *centry;
1043 if ( (centry = centry_start(domain, status)) == NULL )
1046 centry_put_string( centry, name );
1048 fstrcpy(uname, alias);
1050 centry_end(centry, "NSS/AN/%s", uname);
1052 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias, name ));
1054 centry_free(centry);
1057 /***************************************************************************
1058 ***************************************************************************/
1060 NTSTATUS resolve_username_to_alias( TALLOC_CTX *mem_ctx,
1061 struct winbindd_domain *domain,
1062 const char *name, char **alias )
1064 struct winbind_cache *cache = get_cache(domain);
1065 struct cache_entry *centry = NULL;
1069 if ( domain->internal )
1070 return NT_STATUS_NOT_SUPPORTED;
1075 if ( (upper_name = SMB_STRDUP(name)) == NULL )
1076 return NT_STATUS_NO_MEMORY;
1077 strupper_m(upper_name);
1079 centry = wcache_fetch(cache, domain, "NSS/NA/%s", upper_name);
1081 SAFE_FREE( upper_name );
1086 status = centry->status;
1088 if (!NT_STATUS_IS_OK(status)) {
1089 centry_free(centry);
1093 *alias = centry_string( centry, mem_ctx );
1095 centry_free(centry);
1097 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1098 name, *alias ? *alias : "(none)"));
1100 return (*alias) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1104 /* If its not in cache and we are offline, then fail */
1106 if ( get_global_winbindd_state_offline() || !domain->online ) {
1107 DEBUG(8,("resolve_username_to_alias: rejecting query "
1108 "in offline mode\n"));
1109 return NT_STATUS_NOT_FOUND;
1112 status = nss_map_to_alias( mem_ctx, domain->name, name, alias );
1114 if ( NT_STATUS_IS_OK( status ) ) {
1115 wcache_save_username_alias(domain, status, name, *alias);
1118 if ( NT_STATUS_EQUAL( status, NT_STATUS_NONE_MAPPED ) ) {
1119 wcache_save_username_alias(domain, status, name, "(NULL)");
1122 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1123 nt_errstr(status)));
1125 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1126 set_domain_offline( domain );
1132 /***************************************************************************
1133 ***************************************************************************/
1135 NTSTATUS resolve_alias_to_username( TALLOC_CTX *mem_ctx,
1136 struct winbindd_domain *domain,
1137 const char *alias, char **name )
1139 struct winbind_cache *cache = get_cache(domain);
1140 struct cache_entry *centry = NULL;
1144 if ( domain->internal )
1145 return NT_STATUS_NOT_SUPPORTED;
1150 if ( (upper_name = SMB_STRDUP(alias)) == NULL )
1151 return NT_STATUS_NO_MEMORY;
1152 strupper_m(upper_name);
1154 centry = wcache_fetch(cache, domain, "NSS/AN/%s", upper_name);
1156 SAFE_FREE( upper_name );
1161 status = centry->status;
1163 if (!NT_STATUS_IS_OK(status)) {
1164 centry_free(centry);
1168 *name = centry_string( centry, mem_ctx );
1170 centry_free(centry);
1172 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1173 alias, *name ? *name : "(none)"));
1175 return (*name) ? NT_STATUS_OK : NT_STATUS_OBJECT_NAME_NOT_FOUND;
1179 /* If its not in cache and we are offline, then fail */
1181 if ( get_global_winbindd_state_offline() || !domain->online ) {
1182 DEBUG(8,("resolve_alias_to_username: rejecting query "
1183 "in offline mode\n"));
1184 return NT_STATUS_NOT_FOUND;
1187 /* an alias cannot contain a domain prefix or '@' */
1189 if (strchr(alias, '\\') || strchr(alias, '@')) {
1190 DEBUG(10,("resolve_alias_to_username: skipping fully "
1191 "qualified name %s\n", alias));
1192 return NT_STATUS_OBJECT_NAME_INVALID;
1195 status = nss_map_from_alias( mem_ctx, domain->name, alias, name );
1197 if ( NT_STATUS_IS_OK( status ) ) {
1198 wcache_save_alias_username( domain, status, alias, *name );
1201 if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1202 wcache_save_alias_username(domain, status, alias, "(NULL)");
1205 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1206 nt_errstr(status)));
1208 if ( NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ) {
1209 set_domain_offline( domain );
1215 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const DOM_SID *sid)
1217 struct winbind_cache *cache = get_cache(domain);
1219 fstring key_str, tmp;
1223 return NT_STATUS_INTERNAL_DB_ERROR;
1226 if (is_null_sid(sid)) {
1227 return NT_STATUS_INVALID_SID;
1230 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1231 return NT_STATUS_INVALID_SID;
1234 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
1236 data = tdb_fetch(cache->tdb, string_tdb_data(key_str));
1238 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1241 SAFE_FREE(data.dptr);
1242 return NT_STATUS_OK;
1245 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1246 as new salted ones. */
1248 NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
1249 TALLOC_CTX *mem_ctx,
1251 const uint8 **cached_nt_pass,
1252 const uint8 **cached_salt)
1254 struct winbind_cache *cache = get_cache(domain);
1255 struct cache_entry *centry = NULL;
1262 return NT_STATUS_INTERNAL_DB_ERROR;
1265 if (is_null_sid(sid)) {
1266 return NT_STATUS_INVALID_SID;
1269 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1270 return NT_STATUS_INVALID_SID;
1273 /* Try and get a salted cred first. If we can't
1274 fall back to an unsalted cred. */
1276 centry = wcache_fetch(cache, domain, "CRED/%s",
1277 sid_to_fstring(tmp, sid));
1279 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1280 sid_string_dbg(sid)));
1281 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1284 t = centry_time(centry);
1286 /* In the salted case this isn't actually the nt_hash itself,
1287 but the MD5 of the salt + nt_hash. Let the caller
1288 sort this out. It can tell as we only return the cached_salt
1289 if we are returning a salted cred. */
1291 *cached_nt_pass = (const uint8 *)centry_hash16(centry, mem_ctx);
1292 if (*cached_nt_pass == NULL) {
1295 sid_to_fstring(sidstr, sid);
1297 /* Bad (old) cred cache. Delete and pretend we
1299 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1301 wcache_delete("CRED/%s", sidstr);
1302 centry_free(centry);
1303 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1306 /* We only have 17 bytes more data in the salted cred case. */
1307 if (centry->len - centry->ofs == 17) {
1308 *cached_salt = (const uint8 *)centry_hash16(centry, mem_ctx);
1310 *cached_salt = NULL;
1313 dump_data_pw("cached_nt_pass", *cached_nt_pass, NT_HASH_LEN);
1315 dump_data_pw("cached_salt", *cached_salt, NT_HASH_LEN);
1318 status = centry->status;
1320 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1321 sid_string_dbg(sid), nt_errstr(status) ));
1323 centry_free(centry);
1327 /* Store creds for a SID - only writes out new salted ones. */
1329 NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
1330 TALLOC_CTX *mem_ctx,
1332 const uint8 nt_pass[NT_HASH_LEN])
1334 struct cache_entry *centry;
1337 uint8 cred_salt[NT_HASH_LEN];
1338 uint8 salted_hash[NT_HASH_LEN];
1340 if (is_null_sid(sid)) {
1341 return NT_STATUS_INVALID_SID;
1344 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
1345 return NT_STATUS_INVALID_SID;
1348 centry = centry_start(domain, NT_STATUS_OK);
1350 return NT_STATUS_INTERNAL_DB_ERROR;
1353 dump_data_pw("nt_pass", nt_pass, NT_HASH_LEN);
1355 centry_put_time(centry, time(NULL));
1357 /* Create a salt and then salt the hash. */
1358 generate_random_buffer(cred_salt, NT_HASH_LEN);
1359 E_md5hash(cred_salt, nt_pass, salted_hash);
1361 centry_put_hash16(centry, salted_hash);
1362 centry_put_hash16(centry, cred_salt);
1363 centry_end(centry, "CRED/%s", sid_to_fstring(sid_string, sid));
1365 DEBUG(10,("wcache_save_creds: %s\n", sid_string));
1367 centry_free(centry);
1369 return NT_STATUS_OK;
1373 /* Query display info. This is the basic user list fn */
1374 static NTSTATUS query_user_list(struct winbindd_domain *domain,
1375 TALLOC_CTX *mem_ctx,
1376 uint32 *num_entries,
1377 struct wbint_userinfo **info)
1379 struct winbind_cache *cache = get_cache(domain);
1380 struct cache_entry *centry = NULL;
1382 unsigned int i, retry;
1383 bool old_status = domain->online;
1388 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1393 *num_entries = centry_uint32(centry);
1395 if (*num_entries == 0)
1398 (*info) = TALLOC_ARRAY(mem_ctx, struct wbint_userinfo, *num_entries);
1400 smb_panic_fn("query_user_list out of memory");
1402 for (i=0; i<(*num_entries); i++) {
1403 (*info)[i].acct_name = centry_string(centry, mem_ctx);
1404 (*info)[i].full_name = centry_string(centry, mem_ctx);
1405 (*info)[i].homedir = centry_string(centry, mem_ctx);
1406 (*info)[i].shell = centry_string(centry, mem_ctx);
1407 centry_sid(centry, &(*info)[i].user_sid);
1408 centry_sid(centry, &(*info)[i].group_sid);
1412 status = centry->status;
1414 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1415 domain->name, nt_errstr(status) ));
1417 centry_free(centry);
1424 /* Return status value returned by seq number check */
1426 if (!NT_STATUS_IS_OK(domain->last_status))
1427 return domain->last_status;
1429 /* Put the query_user_list() in a retry loop. There appears to be
1430 * some bug either with Windows 2000 or Samba's handling of large
1431 * rpc replies. This manifests itself as sudden disconnection
1432 * at a random point in the enumeration of a large (60k) user list.
1433 * The retry loop simply tries the operation again. )-: It's not
1434 * pretty but an acceptable workaround until we work out what the
1435 * real problem is. */
1440 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1443 status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
1444 if (!NT_STATUS_IS_OK(status)) {
1445 DEBUG(3, ("query_user_list: returned 0x%08x, "
1446 "retrying\n", NT_STATUS_V(status)));
1448 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1449 DEBUG(3, ("query_user_list: flushing "
1450 "connection cache\n"));
1451 invalidate_cm_connection(&domain->conn);
1453 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1454 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1455 if (!domain->internal && old_status) {
1456 set_domain_offline(domain);
1458 /* store partial response. */
1459 if (*num_entries > 0) {
1461 * humm, what about the status used for cache?
1462 * Should it be NT_STATUS_OK?
1467 * domain is offline now, and there is no user entries,
1468 * try to fetch from cache again.
1470 if (cache->tdb && !domain->online && !domain->internal && old_status) {
1471 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1472 /* partial response... */
1476 goto do_fetch_cache;
1483 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
1487 refresh_sequence_number(domain, false);
1488 if (!NT_STATUS_IS_OK(status)) {
1491 centry = centry_start(domain, status);
1494 centry_put_uint32(centry, *num_entries);
1495 for (i=0; i<(*num_entries); i++) {
1496 centry_put_string(centry, (*info)[i].acct_name);
1497 centry_put_string(centry, (*info)[i].full_name);
1498 centry_put_string(centry, (*info)[i].homedir);
1499 centry_put_string(centry, (*info)[i].shell);
1500 centry_put_sid(centry, &(*info)[i].user_sid);
1501 centry_put_sid(centry, &(*info)[i].group_sid);
1502 if (domain->backend && domain->backend->consistent) {
1503 /* when the backend is consistent we can pre-prime some mappings */
1504 wcache_save_name_to_sid(domain, NT_STATUS_OK,
1506 (*info)[i].acct_name,
1507 &(*info)[i].user_sid,
1509 wcache_save_sid_to_name(domain, NT_STATUS_OK,
1510 &(*info)[i].user_sid,
1512 (*info)[i].acct_name,
1514 wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
1517 centry_end(centry, "UL/%s", domain->name);
1518 centry_free(centry);
1524 /* list all domain groups */
1525 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
1526 TALLOC_CTX *mem_ctx,
1527 uint32 *num_entries,
1528 struct acct_info **info)
1530 struct winbind_cache *cache = get_cache(domain);
1531 struct cache_entry *centry = NULL;
1536 old_status = domain->online;
1540 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1545 *num_entries = centry_uint32(centry);
1547 if (*num_entries == 0)
1550 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1552 smb_panic_fn("enum_dom_groups out of memory");
1554 for (i=0; i<(*num_entries); i++) {
1555 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1556 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1557 (*info)[i].rid = centry_uint32(centry);
1561 status = centry->status;
1563 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1564 domain->name, nt_errstr(status) ));
1566 centry_free(centry);
1573 /* Return status value returned by seq number check */
1575 if (!NT_STATUS_IS_OK(domain->last_status))
1576 return domain->last_status;
1578 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1581 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1583 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1584 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1585 if (!domain->internal && old_status) {
1586 set_domain_offline(domain);
1590 !domain->internal &&
1592 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1594 goto do_fetch_cache;
1599 refresh_sequence_number(domain, false);
1600 if (!NT_STATUS_IS_OK(status)) {
1603 centry = centry_start(domain, status);
1606 centry_put_uint32(centry, *num_entries);
1607 for (i=0; i<(*num_entries); i++) {
1608 centry_put_string(centry, (*info)[i].acct_name);
1609 centry_put_string(centry, (*info)[i].acct_desc);
1610 centry_put_uint32(centry, (*info)[i].rid);
1612 centry_end(centry, "GL/%s/domain", domain->name);
1613 centry_free(centry);
1619 /* list all domain groups */
1620 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
1621 TALLOC_CTX *mem_ctx,
1622 uint32 *num_entries,
1623 struct acct_info **info)
1625 struct winbind_cache *cache = get_cache(domain);
1626 struct cache_entry *centry = NULL;
1631 old_status = domain->online;
1635 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1640 *num_entries = centry_uint32(centry);
1642 if (*num_entries == 0)
1645 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1647 smb_panic_fn("enum_dom_groups out of memory");
1649 for (i=0; i<(*num_entries); i++) {
1650 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1651 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1652 (*info)[i].rid = centry_uint32(centry);
1657 /* If we are returning cached data and the domain controller
1658 is down then we don't know whether the data is up to date
1659 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1662 if (wcache_server_down(domain)) {
1663 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1664 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1666 status = centry->status;
1668 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1669 domain->name, nt_errstr(status) ));
1671 centry_free(centry);
1678 /* Return status value returned by seq number check */
1680 if (!NT_STATUS_IS_OK(domain->last_status))
1681 return domain->last_status;
1683 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1686 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1688 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1689 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1690 if (!domain->internal && old_status) {
1691 set_domain_offline(domain);
1694 !domain->internal &&
1697 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1699 goto do_fetch_cache;
1704 refresh_sequence_number(domain, false);
1705 if (!NT_STATUS_IS_OK(status)) {
1708 centry = centry_start(domain, status);
1711 centry_put_uint32(centry, *num_entries);
1712 for (i=0; i<(*num_entries); i++) {
1713 centry_put_string(centry, (*info)[i].acct_name);
1714 centry_put_string(centry, (*info)[i].acct_desc);
1715 centry_put_uint32(centry, (*info)[i].rid);
1717 centry_end(centry, "GL/%s/local", domain->name);
1718 centry_free(centry);
1724 NTSTATUS wcache_name_to_sid(struct winbindd_domain *domain,
1725 const char *domain_name,
1727 struct dom_sid *sid,
1728 enum lsa_SidType *type)
1730 struct winbind_cache *cache = get_cache(domain);
1731 struct cache_entry *centry;
1735 if (cache->tdb == NULL) {
1736 return NT_STATUS_NOT_FOUND;
1739 uname = talloc_strdup_upper(talloc_tos(), name);
1740 if (uname == NULL) {
1741 return NT_STATUS_NO_MEMORY;
1744 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1746 if (centry == NULL) {
1747 return NT_STATUS_NOT_FOUND;
1750 status = centry->status;
1751 if (NT_STATUS_IS_OK(status)) {
1752 *type = (enum lsa_SidType)centry_uint32(centry);
1753 centry_sid(centry, sid);
1756 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1757 "%s\n", domain->name, nt_errstr(status) ));
1759 centry_free(centry);
1763 /* convert a single name to a sid in a domain */
1764 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
1765 TALLOC_CTX *mem_ctx,
1766 const char *domain_name,
1770 enum lsa_SidType *type)
1775 old_status = domain->online;
1777 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1778 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1784 /* If the seq number check indicated that there is a problem
1785 * with this DC, then return that status... except for
1786 * access_denied. This is special because the dc may be in
1787 * "restrict anonymous = 1" mode, in which case it will deny
1788 * most unauthenticated operations, but *will* allow the LSA
1789 * name-to-sid that we try as a fallback. */
1791 if (!(NT_STATUS_IS_OK(domain->last_status)
1792 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1793 return domain->last_status;
1795 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1798 status = domain->backend->name_to_sid(domain, mem_ctx, domain_name,
1799 name, flags, sid, type);
1801 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1802 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1803 if (!domain->internal && old_status) {
1804 set_domain_offline(domain);
1806 if (!domain->internal &&
1809 NTSTATUS cache_status;
1810 cache_status = wcache_name_to_sid(domain, domain_name, name, sid, type);
1811 return cache_status;
1815 refresh_sequence_number(domain, false);
1817 if (domain->online &&
1818 (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))) {
1819 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1821 /* Only save the reverse mapping if this was not a UPN */
1822 if (!strchr(name, '@')) {
1823 strupper_m(CONST_DISCARD(char *,domain_name));
1824 strlower_m(CONST_DISCARD(char *,name));
1825 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1832 NTSTATUS wcache_sid_to_name(struct winbindd_domain *domain,
1833 const struct dom_sid *sid,
1834 TALLOC_CTX *mem_ctx,
1837 enum lsa_SidType *type)
1839 struct winbind_cache *cache = get_cache(domain);
1840 struct cache_entry *centry;
1844 if (cache->tdb == NULL) {
1845 return NT_STATUS_NOT_FOUND;
1848 sid_string = sid_string_tos(sid);
1849 if (sid_string == NULL) {
1850 return NT_STATUS_NO_MEMORY;
1853 centry = wcache_fetch(cache, domain, "SN/%s", sid_string);
1854 TALLOC_FREE(sid_string);
1855 if (centry == NULL) {
1856 return NT_STATUS_NOT_FOUND;
1859 if (NT_STATUS_IS_OK(centry->status)) {
1860 *type = (enum lsa_SidType)centry_uint32(centry);
1861 *domain_name = centry_string(centry, mem_ctx);
1862 *name = centry_string(centry, mem_ctx);
1865 status = centry->status;
1866 centry_free(centry);
1868 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1869 "%s\n", domain->name, nt_errstr(status) ));
1874 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1876 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
1877 TALLOC_CTX *mem_ctx,
1881 enum lsa_SidType *type)
1886 old_status = domain->online;
1887 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
1889 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
1894 *domain_name = NULL;
1896 /* If the seq number check indicated that there is a problem
1897 * with this DC, then return that status... except for
1898 * access_denied. This is special because the dc may be in
1899 * "restrict anonymous = 1" mode, in which case it will deny
1900 * most unauthenticated operations, but *will* allow the LSA
1901 * sid-to-name that we try as a fallback. */
1903 if (!(NT_STATUS_IS_OK(domain->last_status)
1904 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1905 return domain->last_status;
1907 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1910 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1912 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
1913 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1914 if (!domain->internal && old_status) {
1915 set_domain_offline(domain);
1917 if (!domain->internal &&
1920 NTSTATUS cache_status;
1921 cache_status = wcache_sid_to_name(domain, sid, mem_ctx,
1922 domain_name, name, type);
1923 return cache_status;
1927 refresh_sequence_number(domain, false);
1928 if (!NT_STATUS_IS_OK(status)) {
1931 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1933 /* We can't save the name to sid mapping here, as with sid history a
1934 * later name2sid would give the wrong sid. */
1939 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
1940 TALLOC_CTX *mem_ctx,
1941 const DOM_SID *domain_sid,
1946 enum lsa_SidType **types)
1948 struct winbind_cache *cache = get_cache(domain);
1950 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1955 old_status = domain->online;
1956 *domain_name = NULL;
1964 if (num_rids == 0) {
1965 return NT_STATUS_OK;
1968 *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
1969 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
1971 if ((*names == NULL) || (*types == NULL)) {
1972 result = NT_STATUS_NO_MEMORY;
1976 have_mapped = have_unmapped = false;
1978 for (i=0; i<num_rids; i++) {
1980 struct cache_entry *centry;
1983 if (!sid_compose(&sid, domain_sid, rids[i])) {
1984 result = NT_STATUS_INTERNAL_ERROR;
1988 centry = wcache_fetch(cache, domain, "SN/%s",
1989 sid_to_fstring(tmp, &sid));
1994 (*types)[i] = SID_NAME_UNKNOWN;
1995 (*names)[i] = talloc_strdup(*names, "");
1997 if (NT_STATUS_IS_OK(centry->status)) {
2000 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
2002 dom = centry_string(centry, mem_ctx);
2003 if (*domain_name == NULL) {
2009 (*names)[i] = centry_string(centry, *names);
2011 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
2012 have_unmapped = true;
2015 /* something's definitely wrong */
2016 result = centry->status;
2020 centry_free(centry);
2024 return NT_STATUS_NONE_MAPPED;
2026 if (!have_unmapped) {
2027 return NT_STATUS_OK;
2029 return STATUS_SOME_UNMAPPED;
2033 TALLOC_FREE(*names);
2034 TALLOC_FREE(*types);
2036 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
2037 rids, num_rids, domain_name,
2040 if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
2041 NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2042 if (!domain->internal && old_status) {
2043 set_domain_offline(domain);
2046 !domain->internal &&
2049 have_mapped = have_unmapped = false;
2051 for (i=0; i<num_rids; i++) {
2053 struct cache_entry *centry;
2056 if (!sid_compose(&sid, domain_sid, rids[i])) {
2057 result = NT_STATUS_INTERNAL_ERROR;
2061 centry = wcache_fetch(cache, domain, "SN/%s",
2062 sid_to_fstring(tmp, &sid));
2064 (*types)[i] = SID_NAME_UNKNOWN;
2065 (*names)[i] = talloc_strdup(*names, "");
2069 (*types)[i] = SID_NAME_UNKNOWN;
2070 (*names)[i] = talloc_strdup(*names, "");
2072 if (NT_STATUS_IS_OK(centry->status)) {
2075 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
2077 dom = centry_string(centry, mem_ctx);
2078 if (*domain_name == NULL) {
2084 (*names)[i] = centry_string(centry, *names);
2086 } else if (NT_STATUS_EQUAL(centry->status, NT_STATUS_NONE_MAPPED)) {
2087 have_unmapped = true;
2090 /* something's definitely wrong */
2091 result = centry->status;
2095 centry_free(centry);
2099 return NT_STATUS_NONE_MAPPED;
2101 if (!have_unmapped) {
2102 return NT_STATUS_OK;
2104 return STATUS_SOME_UNMAPPED;
2108 None of the queried rids has been found so save all negative entries
2110 if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED)) {
2111 for (i = 0; i < num_rids; i++) {
2113 const char *name = "";
2114 const enum lsa_SidType type = SID_NAME_UNKNOWN;
2115 NTSTATUS status = NT_STATUS_NONE_MAPPED;
2117 if (!sid_compose(&sid, domain_sid, rids[i])) {
2118 return NT_STATUS_INTERNAL_ERROR;
2121 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2129 Some or all of the queried rids have been found.
2131 if (!NT_STATUS_IS_OK(result) &&
2132 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
2136 refresh_sequence_number(domain, false);
2138 for (i=0; i<num_rids; i++) {
2142 if (!sid_compose(&sid, domain_sid, rids[i])) {
2143 result = NT_STATUS_INTERNAL_ERROR;
2147 status = (*types)[i] == SID_NAME_UNKNOWN ?
2148 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
2150 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
2151 (*names)[i], (*types)[i]);
2157 TALLOC_FREE(*names);
2158 TALLOC_FREE(*types);
2162 NTSTATUS wcache_query_user(struct winbindd_domain *domain,
2163 TALLOC_CTX *mem_ctx,
2164 const struct dom_sid *user_sid,
2165 struct wbint_userinfo *info)
2167 struct winbind_cache *cache = get_cache(domain);
2168 struct cache_entry *centry = NULL;
2172 if (cache->tdb == NULL) {
2173 return NT_STATUS_NOT_FOUND;
2176 sid_string = sid_string_tos(user_sid);
2177 if (sid_string == NULL) {
2178 return NT_STATUS_NO_MEMORY;
2181 centry = wcache_fetch(cache, domain, "U/%s", sid_string);
2182 TALLOC_FREE(sid_string);
2183 if (centry == NULL) {
2184 return NT_STATUS_NOT_FOUND;
2188 * If we have an access denied cache entry and a cached info3
2189 * in the samlogon cache then do a query. This will force the
2190 * rpc back end to return the info3 data.
2193 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED) &&
2194 netsamlogon_cache_have(user_sid)) {
2195 DEBUG(10, ("query_user: cached access denied and have cached "
2197 domain->last_status = NT_STATUS_OK;
2198 centry_free(centry);
2199 return NT_STATUS_NOT_FOUND;
2202 /* if status is not ok then this is a negative hit
2203 and the rest of the data doesn't matter */
2204 status = centry->status;
2205 if (NT_STATUS_IS_OK(status)) {
2206 info->acct_name = centry_string(centry, mem_ctx);
2207 info->full_name = centry_string(centry, mem_ctx);
2208 info->homedir = centry_string(centry, mem_ctx);
2209 info->shell = centry_string(centry, mem_ctx);
2210 info->primary_gid = centry_uint32(centry);
2211 centry_sid(centry, &info->user_sid);
2212 centry_sid(centry, &info->group_sid);
2215 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2216 "%s\n", domain->name, nt_errstr(status) ));
2218 centry_free(centry);
2222 /* Lookup user information from a rid */
2223 static NTSTATUS query_user(struct winbindd_domain *domain,
2224 TALLOC_CTX *mem_ctx,
2225 const DOM_SID *user_sid,
2226 struct wbint_userinfo *info)
2231 old_status = domain->online;
2232 status = wcache_query_user(domain, mem_ctx, user_sid, info);
2233 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2239 /* Return status value returned by seq number check */
2241 if (!NT_STATUS_IS_OK(domain->last_status))
2242 return domain->last_status;
2244 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2247 status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
2249 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2250 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2251 if (!domain->internal && old_status) {
2252 set_domain_offline(domain);
2254 if (!domain->internal &&
2257 NTSTATUS cache_status;
2258 cache_status = wcache_query_user(domain, mem_ctx, user_sid, info);
2259 return cache_status;
2263 refresh_sequence_number(domain, false);
2264 if (!NT_STATUS_IS_OK(status)) {
2267 wcache_save_user(domain, status, info);
2272 NTSTATUS wcache_lookup_usergroups(struct winbindd_domain *domain,
2273 TALLOC_CTX *mem_ctx,
2274 const struct dom_sid *user_sid,
2275 uint32_t *pnum_sids,
2276 struct dom_sid **psids)
2278 struct winbind_cache *cache = get_cache(domain);
2279 struct cache_entry *centry = NULL;
2281 uint32_t i, num_sids;
2282 struct dom_sid *sids;
2285 if (cache->tdb == NULL) {
2286 return NT_STATUS_NOT_FOUND;
2289 centry = wcache_fetch(cache, domain, "UG/%s",
2290 sid_to_fstring(sid_string, user_sid));
2291 if (centry == NULL) {
2292 return NT_STATUS_NOT_FOUND;
2295 /* If we have an access denied cache entry and a cached info3 in the
2296 samlogon cache then do a query. This will force the rpc back end
2297 to return the info3 data. */
2299 if (NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)
2300 && netsamlogon_cache_have(user_sid)) {
2301 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2303 domain->last_status = NT_STATUS_OK;
2304 centry_free(centry);
2305 return NT_STATUS_NOT_FOUND;
2308 num_sids = centry_uint32(centry);
2309 sids = talloc_array(mem_ctx, struct dom_sid, num_sids);
2311 centry_free(centry);
2312 return NT_STATUS_NO_MEMORY;
2315 for (i=0; i<num_sids; i++) {
2316 centry_sid(centry, &sids[i]);
2319 status = centry->status;
2321 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2322 "status: %s\n", domain->name, nt_errstr(status)));
2324 centry_free(centry);
2326 *pnum_sids = num_sids;
2331 /* Lookup groups a user is a member of. */
2332 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
2333 TALLOC_CTX *mem_ctx,
2334 const DOM_SID *user_sid,
2335 uint32 *num_groups, DOM_SID **user_gids)
2337 struct cache_entry *centry = NULL;
2343 old_status = domain->online;
2344 status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2345 num_groups, user_gids);
2346 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2351 (*user_gids) = NULL;
2353 /* Return status value returned by seq number check */
2355 if (!NT_STATUS_IS_OK(domain->last_status))
2356 return domain->last_status;
2358 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2361 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
2363 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2364 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2365 if (!domain->internal && old_status) {
2366 set_domain_offline(domain);
2368 if (!domain->internal &&
2371 NTSTATUS cache_status;
2372 cache_status = wcache_lookup_usergroups(domain, mem_ctx, user_sid,
2373 num_groups, user_gids);
2374 return cache_status;
2377 if ( NT_STATUS_EQUAL(status, NT_STATUS_SYNCHRONIZATION_REQUIRED) )
2381 refresh_sequence_number(domain, false);
2382 if (!NT_STATUS_IS_OK(status)) {
2385 centry = centry_start(domain, status);
2389 centry_put_uint32(centry, *num_groups);
2390 for (i=0; i<(*num_groups); i++) {
2391 centry_put_sid(centry, &(*user_gids)[i]);
2394 centry_end(centry, "UG/%s", sid_to_fstring(sid_string, user_sid));
2395 centry_free(centry);
2401 static char *wcache_make_sidlist(TALLOC_CTX *mem_ctx, uint32_t num_sids,
2402 const struct dom_sid *sids)
2407 sidlist = talloc_strdup(mem_ctx, "");
2408 if (sidlist == NULL) {
2411 for (i=0; i<num_sids; i++) {
2413 sidlist = talloc_asprintf_append_buffer(
2414 sidlist, "/%s", sid_to_fstring(tmp, &sids[i]));
2415 if (sidlist == NULL) {
2422 NTSTATUS wcache_lookup_useraliases(struct winbindd_domain *domain,
2423 TALLOC_CTX *mem_ctx, uint32_t num_sids,
2424 const struct dom_sid *sids,
2425 uint32_t *pnum_aliases, uint32_t **paliases)
2427 struct winbind_cache *cache = get_cache(domain);
2428 struct cache_entry *centry = NULL;
2429 uint32_t num_aliases;
2435 if (cache->tdb == NULL) {
2436 return NT_STATUS_NOT_FOUND;
2439 if (num_sids == 0) {
2442 return NT_STATUS_OK;
2445 /* We need to cache indexed by the whole list of SIDs, the aliases
2446 * resulting might come from any of the SIDs. */
2448 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2449 if (sidlist == NULL) {
2450 return NT_STATUS_NO_MEMORY;
2453 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
2454 TALLOC_FREE(sidlist);
2455 if (centry == NULL) {
2456 return NT_STATUS_NOT_FOUND;
2459 num_aliases = centry_uint32(centry);
2460 aliases = talloc_array(mem_ctx, uint32_t, num_aliases);
2461 if (aliases == NULL) {
2462 centry_free(centry);
2463 return NT_STATUS_NO_MEMORY;
2466 for (i=0; i<num_aliases; i++) {
2467 aliases[i] = centry_uint32(centry);
2470 status = centry->status;
2472 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2473 "status %s\n", domain->name, nt_errstr(status)));
2475 centry_free(centry);
2477 *pnum_aliases = num_aliases;
2478 *paliases = aliases;
2483 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
2484 TALLOC_CTX *mem_ctx,
2485 uint32 num_sids, const DOM_SID *sids,
2486 uint32 *num_aliases, uint32 **alias_rids)
2488 struct cache_entry *centry = NULL;
2494 old_status = domain->online;
2495 status = wcache_lookup_useraliases(domain, mem_ctx, num_sids, sids,
2496 num_aliases, alias_rids);
2497 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2502 (*alias_rids) = NULL;
2504 if (!NT_STATUS_IS_OK(domain->last_status))
2505 return domain->last_status;
2507 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2508 "for domain %s\n", domain->name ));
2510 sidlist = wcache_make_sidlist(talloc_tos(), num_sids, sids);
2511 if (sidlist == NULL) {
2512 return NT_STATUS_NO_MEMORY;
2515 status = domain->backend->lookup_useraliases(domain, mem_ctx,
2517 num_aliases, alias_rids);
2519 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2520 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2521 if (!domain->internal && old_status) {
2522 set_domain_offline(domain);
2524 if (!domain->internal &&
2527 NTSTATUS cache_status;
2528 cache_status = wcache_lookup_useraliases(domain, mem_ctx, num_sids,
2529 sids, num_aliases, alias_rids);
2530 return cache_status;
2534 refresh_sequence_number(domain, false);
2535 if (!NT_STATUS_IS_OK(status)) {
2538 centry = centry_start(domain, status);
2541 centry_put_uint32(centry, *num_aliases);
2542 for (i=0; i<(*num_aliases); i++)
2543 centry_put_uint32(centry, (*alias_rids)[i]);
2544 centry_end(centry, "UA%s", sidlist);
2545 centry_free(centry);
2551 NTSTATUS wcache_lookup_groupmem(struct winbindd_domain *domain,
2552 TALLOC_CTX *mem_ctx,
2553 const struct dom_sid *group_sid,
2554 uint32_t *num_names,
2555 struct dom_sid **sid_mem, char ***names,
2556 uint32_t **name_types)
2558 struct winbind_cache *cache = get_cache(domain);
2559 struct cache_entry *centry = NULL;
2564 if (cache->tdb == NULL) {
2565 return NT_STATUS_NOT_FOUND;
2568 sid_string = sid_string_tos(group_sid);
2569 if (sid_string == NULL) {
2570 return NT_STATUS_NO_MEMORY;
2573 centry = wcache_fetch(cache, domain, "GM/%s", sid_string);
2574 TALLOC_FREE(sid_string);
2575 if (centry == NULL) {
2576 return NT_STATUS_NOT_FOUND;
2583 *num_names = centry_uint32(centry);
2584 if (*num_names == 0) {
2585 centry_free(centry);
2586 return NT_STATUS_OK;
2589 *sid_mem = talloc_array(mem_ctx, DOM_SID, *num_names);
2590 *names = talloc_array(mem_ctx, char *, *num_names);
2591 *name_types = talloc_array(mem_ctx, uint32, *num_names);
2593 if ((*sid_mem == NULL) || (*names == NULL) || (*name_types == NULL)) {
2594 TALLOC_FREE(*sid_mem);
2595 TALLOC_FREE(*names);
2596 TALLOC_FREE(*name_types);
2597 centry_free(centry);
2598 return NT_STATUS_NO_MEMORY;
2601 for (i=0; i<(*num_names); i++) {
2602 centry_sid(centry, &(*sid_mem)[i]);
2603 (*names)[i] = centry_string(centry, mem_ctx);
2604 (*name_types)[i] = centry_uint32(centry);
2607 status = centry->status;
2609 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2610 "status: %s\n", domain->name, nt_errstr(status)));
2612 centry_free(centry);
2616 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
2617 TALLOC_CTX *mem_ctx,
2618 const DOM_SID *group_sid,
2619 enum lsa_SidType type,
2621 DOM_SID **sid_mem, char ***names,
2622 uint32 **name_types)
2624 struct cache_entry *centry = NULL;
2630 old_status = domain->online;
2631 status = wcache_lookup_groupmem(domain, mem_ctx, group_sid, num_names,
2632 sid_mem, names, name_types);
2633 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
2640 (*name_types) = NULL;
2642 /* Return status value returned by seq number check */
2644 if (!NT_STATUS_IS_OK(domain->last_status))
2645 return domain->last_status;
2647 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2650 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid,
2652 sid_mem, names, name_types);
2654 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2655 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2656 if (!domain->internal && old_status) {
2657 set_domain_offline(domain);
2659 if (!domain->internal &&
2662 NTSTATUS cache_status;
2663 cache_status = wcache_lookup_groupmem(domain, mem_ctx, group_sid,
2664 num_names, sid_mem, names,
2666 return cache_status;
2670 refresh_sequence_number(domain, false);
2671 if (!NT_STATUS_IS_OK(status)) {
2674 centry = centry_start(domain, status);
2677 centry_put_uint32(centry, *num_names);
2678 for (i=0; i<(*num_names); i++) {
2679 centry_put_sid(centry, &(*sid_mem)[i]);
2680 centry_put_string(centry, (*names)[i]);
2681 centry_put_uint32(centry, (*name_types)[i]);
2683 centry_end(centry, "GM/%s", sid_to_fstring(sid_string, group_sid));
2684 centry_free(centry);
2690 /* find the sequence number for a domain */
2691 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
2693 refresh_sequence_number(domain, false);
2695 *seq = domain->sequence_number;
2697 return NT_STATUS_OK;
2700 /* enumerate trusted domains
2701 * (we need to have the list of trustdoms in the cache when we go offline) -
2703 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
2704 TALLOC_CTX *mem_ctx,
2705 struct netr_DomainTrustList *trusts)
2708 struct winbind_cache *cache;
2709 struct winbindd_tdc_domain *dom_list = NULL;
2710 size_t num_domains = 0;
2711 bool retval = false;
2715 old_status = domain->online;
2717 trusts->array = NULL;
2718 if (domain->online) {
2722 cache = get_cache(domain);
2723 if (!cache || !cache->tdb) {
2727 retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2728 if (!retval || !num_domains || !dom_list) {
2729 TALLOC_FREE(dom_list);
2734 trusts->array = TALLOC_ZERO_ARRAY(mem_ctx, struct netr_DomainTrust, num_domains);
2735 if (!trusts->array) {
2736 TALLOC_FREE(dom_list);
2737 return NT_STATUS_NO_MEMORY;
2740 for (i = 0; i < num_domains; i++) {
2741 struct netr_DomainTrust *trust;
2742 struct dom_sid *sid;
2743 struct winbindd_domain *dom;
2745 dom = find_domain_from_name_noinit(dom_list[i].domain_name);
2746 if (dom && dom->internal) {
2750 trust = &trusts->array[trusts->count];
2751 trust->netbios_name = talloc_strdup(trusts->array, dom_list[i].domain_name);
2752 trust->dns_name = talloc_strdup(trusts->array, dom_list[i].dns_name);
2753 sid = talloc(trusts->array, struct dom_sid);
2754 if (!trust->netbios_name || !trust->dns_name ||
2756 TALLOC_FREE(dom_list);
2757 TALLOC_FREE(trusts->array);
2758 return NT_STATUS_NO_MEMORY;
2761 trust->trust_flags = dom_list[i].trust_flags;
2762 trust->trust_attributes = dom_list[i].trust_attribs;
2763 trust->trust_type = dom_list[i].trust_type;
2764 sid_copy(sid, &dom_list[i].sid);
2769 TALLOC_FREE(dom_list);
2770 return NT_STATUS_OK;
2773 /* Return status value returned by seq number check */
2775 if (!NT_STATUS_IS_OK(domain->last_status))
2776 return domain->last_status;
2778 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2781 status = domain->backend->trusted_domains(domain, mem_ctx, trusts);
2783 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2784 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2785 if (!domain->internal && old_status) {
2786 set_domain_offline(domain);
2788 if (!domain->internal &&
2791 retval = wcache_tdc_fetch_list(&dom_list, &num_domains);
2792 if (retval && num_domains && dom_list) {
2793 TALLOC_FREE(trusts->array);
2795 goto do_fetch_cache;
2799 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2800 * so that the generic centry handling still applies correctly -
2803 if (!NT_STATUS_IS_ERR(status)) {
2804 status = NT_STATUS_OK;
2809 /* get lockout policy */
2810 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
2811 TALLOC_CTX *mem_ctx,
2812 struct samr_DomInfo12 *policy)
2814 struct winbind_cache *cache = get_cache(domain);
2815 struct cache_entry *centry = NULL;
2819 old_status = domain->online;
2823 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2829 policy->lockout_duration = centry_nttime(centry);
2830 policy->lockout_window = centry_nttime(centry);
2831 policy->lockout_threshold = centry_uint16(centry);
2833 status = centry->status;
2835 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2836 domain->name, nt_errstr(status) ));
2838 centry_free(centry);
2842 ZERO_STRUCTP(policy);
2844 /* Return status value returned by seq number check */
2846 if (!NT_STATUS_IS_OK(domain->last_status))
2847 return domain->last_status;
2849 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2852 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2854 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2855 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2856 if (!domain->internal && old_status) {
2857 set_domain_offline(domain);
2860 !domain->internal &&
2863 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
2865 goto do_fetch_cache;
2870 refresh_sequence_number(domain, false);
2871 if (!NT_STATUS_IS_OK(status)) {
2874 wcache_save_lockout_policy(domain, status, policy);
2879 /* get password policy */
2880 static NTSTATUS password_policy(struct winbindd_domain *domain,
2881 TALLOC_CTX *mem_ctx,
2882 struct samr_DomInfo1 *policy)
2884 struct winbind_cache *cache = get_cache(domain);
2885 struct cache_entry *centry = NULL;
2889 old_status = domain->online;
2893 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2899 policy->min_password_length = centry_uint16(centry);
2900 policy->password_history_length = centry_uint16(centry);
2901 policy->password_properties = centry_uint32(centry);
2902 policy->max_password_age = centry_nttime(centry);
2903 policy->min_password_age = centry_nttime(centry);
2905 status = centry->status;
2907 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2908 domain->name, nt_errstr(status) ));
2910 centry_free(centry);
2914 ZERO_STRUCTP(policy);
2916 /* Return status value returned by seq number check */
2918 if (!NT_STATUS_IS_OK(domain->last_status))
2919 return domain->last_status;
2921 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2924 status = domain->backend->password_policy(domain, mem_ctx, policy);
2926 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
2927 NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
2928 if (!domain->internal && old_status) {
2929 set_domain_offline(domain);
2932 !domain->internal &&
2935 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2937 goto do_fetch_cache;
2942 refresh_sequence_number(domain, false);
2943 if (!NT_STATUS_IS_OK(status)) {
2946 wcache_save_password_policy(domain, status, policy);
2952 /* Invalidate cached user and group lists coherently */
2954 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2957 if (strncmp((const char *)kbuf.dptr, "UL/", 3) == 0 ||
2958 strncmp((const char *)kbuf.dptr, "GL/", 3) == 0)
2959 tdb_delete(the_tdb, kbuf);
2964 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2966 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
2967 struct netr_SamInfo3 *info3)
2970 fstring key_str, sid_string;
2971 struct winbind_cache *cache;
2973 /* dont clear cached U/SID and UG/SID entries when we want to logon
2976 if (lp_winbind_offline_logon()) {
2983 cache = get_cache(domain);
2989 sid_compose(&sid, info3->base.domain_sid, info3->base.rid);
2991 /* Clear U/SID cache entry */
2992 fstr_sprintf(key_str, "U/%s", sid_to_fstring(sid_string, &sid));
2993 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
2994 tdb_delete(cache->tdb, string_tdb_data(key_str));
2996 /* Clear UG/SID cache entry */
2997 fstr_sprintf(key_str, "UG/%s", sid_to_fstring(sid_string, &sid));
2998 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str));
2999 tdb_delete(cache->tdb, string_tdb_data(key_str));
3001 /* Samba/winbindd never needs this. */
3002 netsamlogon_clear_cached_user(info3);
3005 bool wcache_invalidate_cache(void)
3007 struct winbindd_domain *domain;
3009 for (domain = domain_list(); domain; domain = domain->next) {
3010 struct winbind_cache *cache = get_cache(domain);
3012 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3013 "entries for %s\n", domain->name));
3016 tdb_traverse(cache->tdb, traverse_fn, NULL);
3025 bool init_wcache(void)
3027 if (wcache == NULL) {
3028 wcache = SMB_XMALLOC_P(struct winbind_cache);
3029 ZERO_STRUCTP(wcache);
3032 if (wcache->tdb != NULL)
3035 /* when working offline we must not clear the cache on restart */
3036 wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
3037 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3038 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
3039 O_RDWR|O_CREAT, 0600);
3041 if (wcache->tdb == NULL) {
3042 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3049 /************************************************************************
3050 This is called by the parent to initialize the cache file.
3051 We don't need sophisticated locking here as we know we're the
3053 ************************************************************************/
3055 bool initialize_winbindd_cache(void)
3057 bool cache_bad = true;
3060 if (!init_wcache()) {
3061 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3065 /* Check version number. */
3066 if (tdb_fetch_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, &vers) &&
3067 vers == WINBINDD_CACHE_VERSION) {
3072 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3073 "and re-creating with version number %d\n",
3074 WINBINDD_CACHE_VERSION ));
3076 tdb_close(wcache->tdb);
3079 if (unlink(cache_path("winbindd_cache.tdb")) == -1) {
3080 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3081 cache_path("winbindd_cache.tdb"),
3085 if (!init_wcache()) {
3086 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3087 "init_wcache failed.\n"));
3091 /* Write the version. */
3092 if (!tdb_store_uint32(wcache->tdb, WINBINDD_CACHE_VERSION_KEYSTR, WINBINDD_CACHE_VERSION)) {
3093 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3094 tdb_errorstr(wcache->tdb) ));
3099 tdb_close(wcache->tdb);
3104 void close_winbindd_cache(void)
3110 tdb_close(wcache->tdb);
3115 bool lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
3116 char **domain_name, char **name,
3117 enum lsa_SidType *type)
3119 struct winbindd_domain *domain;
3122 domain = find_lookup_domain_from_sid(sid);
3123 if (domain == NULL) {
3126 status = wcache_sid_to_name(domain, sid, mem_ctx, domain_name, name,
3128 return NT_STATUS_IS_OK(status);
3131 bool lookup_cached_name(TALLOC_CTX *mem_ctx,
3132 const char *domain_name,
3135 enum lsa_SidType *type)
3137 struct winbindd_domain *domain;
3139 bool original_online_state;
3141 domain = find_lookup_domain_from_name(domain_name);
3142 if (domain == NULL) {
3146 /* If we are doing a cached logon, temporarily set the domain
3147 offline so the cache won't expire the entry */
3149 original_online_state = domain->online;
3150 domain->online = false;
3151 status = wcache_name_to_sid(domain, domain_name, name, sid, type);
3152 domain->online = original_online_state;
3154 return NT_STATUS_IS_OK(status);
3157 void cache_name2sid(struct winbindd_domain *domain,
3158 const char *domain_name, const char *name,
3159 enum lsa_SidType type, const DOM_SID *sid)
3161 refresh_sequence_number(domain, false);
3162 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
3167 * The original idea that this cache only contains centries has
3168 * been blurred - now other stuff gets put in here. Ensure we
3169 * ignore these things on cleanup.
3172 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
3173 TDB_DATA dbuf, void *state)
3175 struct cache_entry *centry;
3177 if (is_non_centry_key(kbuf)) {
3181 centry = wcache_fetch_raw((char *)kbuf.dptr);
3186 if (!NT_STATUS_IS_OK(centry->status)) {
3187 DEBUG(10,("deleting centry %s\n", (const char *)kbuf.dptr));
3188 tdb_delete(the_tdb, kbuf);
3191 centry_free(centry);
3195 /* flush the cache */
3196 void wcache_flush_cache(void)
3201 tdb_close(wcache->tdb);
3204 if (!winbindd_use_cache()) {
3208 /* when working offline we must not clear the cache on restart */
3209 wcache->tdb = tdb_open_log(cache_path("winbindd_cache.tdb"),
3210 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
3211 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
3212 O_RDWR|O_CREAT, 0600);
3215 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3219 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
3221 DEBUG(10,("wcache_flush_cache success\n"));
3224 /* Count cached creds */
3226 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3229 int *cred_count = (int*)state;
3231 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3237 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
3239 struct winbind_cache *cache = get_cache(domain);
3244 return NT_STATUS_INTERNAL_DB_ERROR;
3247 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
3249 return NT_STATUS_OK;
3253 struct cred_list *prev, *next;
3258 static struct cred_list *wcache_cred_list;
3260 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
3263 struct cred_list *cred;
3265 if (strncmp((const char *)kbuf.dptr, "CRED/", 5) == 0) {
3267 cred = SMB_MALLOC_P(struct cred_list);
3269 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3275 /* save a copy of the key */
3277 fstrcpy(cred->name, (const char *)kbuf.dptr);
3278 DLIST_ADD(wcache_cred_list, cred);
3284 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const DOM_SID *sid)
3286 struct winbind_cache *cache = get_cache(domain);
3289 struct cred_list *cred, *oldest = NULL;
3292 return NT_STATUS_INTERNAL_DB_ERROR;
3295 /* we possibly already have an entry */
3296 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
3298 fstring key_str, tmp;
3300 DEBUG(11,("we already have an entry, deleting that\n"));
3302 fstr_sprintf(key_str, "CRED/%s", sid_to_fstring(tmp, sid));
3304 tdb_delete(cache->tdb, string_tdb_data(key_str));
3306 return NT_STATUS_OK;
3309 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
3311 return NT_STATUS_OK;
3312 } else if ((ret == -1) || (wcache_cred_list == NULL)) {
3313 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3316 ZERO_STRUCTP(oldest);
3318 for (cred = wcache_cred_list; cred; cred = cred->next) {
3323 data = tdb_fetch(cache->tdb, string_tdb_data(cred->name));
3325 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3327 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
3331 t = IVAL(data.dptr, 0);
3332 SAFE_FREE(data.dptr);
3335 oldest = SMB_MALLOC_P(struct cred_list);
3336 if (oldest == NULL) {
3337 status = NT_STATUS_NO_MEMORY;
3341 fstrcpy(oldest->name, cred->name);
3342 oldest->created = t;
3346 if (t < oldest->created) {
3347 fstrcpy(oldest->name, cred->name);
3348 oldest->created = t;
3352 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
3353 status = NT_STATUS_OK;
3355 status = NT_STATUS_UNSUCCESSFUL;
3358 SAFE_FREE(wcache_cred_list);
3364 /* Change the global online/offline state. */
3365 bool set_global_winbindd_state_offline(void)
3369 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3371 /* Only go offline if someone has created
3372 the key "WINBINDD_OFFLINE" in the cache tdb. */
3374 if (wcache == NULL || wcache->tdb == NULL) {
3375 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3379 if (!lp_winbind_offline_logon()) {
3380 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3384 if (global_winbindd_offline_state) {
3385 /* Already offline. */
3389 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
3391 if (!data.dptr || data.dsize != 4) {
3392 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3393 SAFE_FREE(data.dptr);
3396 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3397 global_winbindd_offline_state = true;
3398 SAFE_FREE(data.dptr);
3403 void set_global_winbindd_state_online(void)
3405 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3407 if (!lp_winbind_offline_logon()) {
3408 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3412 if (!global_winbindd_offline_state) {
3413 /* Already online. */
3416 global_winbindd_offline_state = false;
3422 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3423 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
3426 bool get_global_winbindd_state_offline(void)
3428 return global_winbindd_offline_state;
3431 /***********************************************************************
3432 Validate functions for all possible cache tdb keys.
3433 ***********************************************************************/
3435 static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
3436 struct tdb_validation_status *state)
3438 struct cache_entry *centry;
3440 centry = SMB_XMALLOC_P(struct cache_entry);
3441 centry->data = (unsigned char *)memdup(data.dptr, data.dsize);
3442 if (!centry->data) {
3446 centry->len = data.dsize;
3449 if (centry->len < 8) {
3450 /* huh? corrupt cache? */
3451 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr));
3452 centry_free(centry);
3453 state->bad_entry = true;
3454 state->success = false;
3458 centry->status = NT_STATUS(centry_uint32(centry));
3459 centry->sequence_number = centry_uint32(centry);
3463 static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3464 struct tdb_validation_status *state)
3466 if (dbuf.dsize != 8) {
3467 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3468 keystr, (unsigned int)dbuf.dsize ));
3469 state->bad_entry = true;
3475 static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3476 struct tdb_validation_status *state)
3478 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3483 (void)centry_uint32(centry);
3484 if (NT_STATUS_IS_OK(centry->status)) {
3486 (void)centry_sid(centry, &sid);
3489 centry_free(centry);
3491 if (!(state->success)) {
3494 DEBUG(10,("validate_ns: %s ok\n", keystr));
3498 static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3499 struct tdb_validation_status *state)
3501 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3506 if (NT_STATUS_IS_OK(centry->status)) {
3507 (void)centry_uint32(centry);
3508 (void)centry_string(centry, mem_ctx);
3509 (void)centry_string(centry, mem_ctx);
3512 centry_free(centry);
3514 if (!(state->success)) {
3517 DEBUG(10,("validate_sn: %s ok\n", keystr));
3521 static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3522 struct tdb_validation_status *state)
3524 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3531 (void)centry_string(centry, mem_ctx);
3532 (void)centry_string(centry, mem_ctx);
3533 (void)centry_string(centry, mem_ctx);
3534 (void)centry_string(centry, mem_ctx);
3535 (void)centry_uint32(centry);
3536 (void)centry_sid(centry, &sid);
3537 (void)centry_sid(centry, &sid);
3539 centry_free(centry);
3541 if (!(state->success)) {
3544 DEBUG(10,("validate_u: %s ok\n", keystr));
3548 static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3549 struct tdb_validation_status *state)
3551 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3557 (void)centry_nttime(centry);
3558 (void)centry_nttime(centry);
3559 (void)centry_uint16(centry);
3561 centry_free(centry);
3563 if (!(state->success)) {
3566 DEBUG(10,("validate_loc_pol: %s ok\n", keystr));
3570 static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3571 struct tdb_validation_status *state)
3573 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3579 (void)centry_uint16(centry);
3580 (void)centry_uint16(centry);
3581 (void)centry_uint32(centry);
3582 (void)centry_nttime(centry);
3583 (void)centry_nttime(centry);
3585 centry_free(centry);
3587 if (!(state->success)) {
3590 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr));
3594 static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3595 struct tdb_validation_status *state)
3597 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3603 (void)centry_time(centry);
3604 (void)centry_hash16(centry, mem_ctx);
3606 /* We only have 17 bytes more data in the salted cred case. */
3607 if (centry->len - centry->ofs == 17) {
3608 (void)centry_hash16(centry, mem_ctx);
3611 centry_free(centry);
3613 if (!(state->success)) {
3616 DEBUG(10,("validate_cred: %s ok\n", keystr));
3620 static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3621 struct tdb_validation_status *state)
3623 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3624 int32 num_entries, i;
3630 num_entries = (int32)centry_uint32(centry);
3632 for (i=0; i< num_entries; i++) {
3634 (void)centry_string(centry, mem_ctx);
3635 (void)centry_string(centry, mem_ctx);
3636 (void)centry_string(centry, mem_ctx);
3637 (void)centry_string(centry, mem_ctx);
3638 (void)centry_sid(centry, &sid);
3639 (void)centry_sid(centry, &sid);
3642 centry_free(centry);
3644 if (!(state->success)) {
3647 DEBUG(10,("validate_ul: %s ok\n", keystr));
3651 static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3652 struct tdb_validation_status *state)
3654 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3655 int32 num_entries, i;
3661 num_entries = centry_uint32(centry);
3663 for (i=0; i< num_entries; i++) {
3664 (void)centry_string(centry, mem_ctx);
3665 (void)centry_string(centry, mem_ctx);
3666 (void)centry_uint32(centry);
3669 centry_free(centry);
3671 if (!(state->success)) {
3674 DEBUG(10,("validate_gl: %s ok\n", keystr));
3678 static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3679 struct tdb_validation_status *state)
3681 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3682 int32 num_groups, i;
3688 num_groups = centry_uint32(centry);
3690 for (i=0; i< num_groups; i++) {
3692 centry_sid(centry, &sid);
3695 centry_free(centry);
3697 if (!(state->success)) {
3700 DEBUG(10,("validate_ug: %s ok\n", keystr));
3704 static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3705 struct tdb_validation_status *state)
3707 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3708 int32 num_aliases, i;
3714 num_aliases = centry_uint32(centry);
3716 for (i=0; i < num_aliases; i++) {
3717 (void)centry_uint32(centry);
3720 centry_free(centry);
3722 if (!(state->success)) {
3725 DEBUG(10,("validate_ua: %s ok\n", keystr));
3729 static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3730 struct tdb_validation_status *state)
3732 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3739 num_names = centry_uint32(centry);
3741 for (i=0; i< num_names; i++) {
3743 centry_sid(centry, &sid);
3744 (void)centry_string(centry, mem_ctx);
3745 (void)centry_uint32(centry);
3748 centry_free(centry);
3750 if (!(state->success)) {
3753 DEBUG(10,("validate_gm: %s ok\n", keystr));
3757 static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3758 struct tdb_validation_status *state)
3760 /* Can't say anything about this other than must be nonzero. */
3761 if (dbuf.dsize == 0) {
3762 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3764 state->bad_entry = true;
3765 state->success = false;
3769 DEBUG(10,("validate_dr: %s ok\n", keystr));
3773 static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3774 struct tdb_validation_status *state)
3776 /* Can't say anything about this other than must be nonzero. */
3777 if (dbuf.dsize == 0) {
3778 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3780 state->bad_entry = true;
3781 state->success = false;
3785 DEBUG(10,("validate_de: %s ok\n", keystr));
3789 static int validate_pwinfo(TALLOC_CTX *mem_ctx, const char *keystr,
3790 TDB_DATA dbuf, struct tdb_validation_status *state)
3792 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3798 (void)centry_string(centry, mem_ctx);
3799 (void)centry_string(centry, mem_ctx);
3800 (void)centry_string(centry, mem_ctx);
3801 (void)centry_uint32(centry);
3803 centry_free(centry);
3805 if (!(state->success)) {
3808 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3812 static int validate_nss_an(TALLOC_CTX *mem_ctx, const char *keystr,
3814 struct tdb_validation_status *state)
3816 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3822 (void)centry_string( centry, mem_ctx );
3824 centry_free(centry);
3826 if (!(state->success)) {
3829 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3833 static int validate_nss_na(TALLOC_CTX *mem_ctx, const char *keystr,
3835 struct tdb_validation_status *state)
3837 struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
3843 (void)centry_string( centry, mem_ctx );
3845 centry_free(centry);
3847 if (!(state->success)) {
3850 DEBUG(10,("validate_pwinfo: %s ok\n", keystr));
3854 static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
3856 struct tdb_validation_status *state)
3858 if (dbuf.dsize == 0) {
3859 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3860 "key %s (len ==0) ?\n", keystr));
3861 state->bad_entry = true;
3862 state->success = false;
3866 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr));
3867 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3871 static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3872 struct tdb_validation_status *state)
3874 if (dbuf.dsize != 4) {
3875 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3876 keystr, (unsigned int)dbuf.dsize ));
3877 state->bad_entry = true;
3878 state->success = false;
3881 DEBUG(10,("validate_offline: %s ok\n", keystr));
3885 static int validate_ndr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3886 struct tdb_validation_status *state)
3889 * Ignore validation for now. The proper way to do this is with a
3890 * checksum. Just pure parsing does not really catch much.
3895 static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
3896 struct tdb_validation_status *state)
3898 if (dbuf.dsize != 4) {
3899 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3900 "key %s (len %u != 4) ?\n",
3901 keystr, (unsigned int)dbuf.dsize));
3902 state->bad_entry = true;
3903 state->success = false;
3907 DEBUG(10, ("validate_cache_version: %s ok\n", keystr));
3911 /***********************************************************************
3912 A list of all possible cache tdb keys with associated validation
3914 ***********************************************************************/
3916 struct key_val_struct {
3917 const char *keyname;
3918 int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
3920 {"SEQNUM/", validate_seqnum},
3921 {"NS/", validate_ns},
3922 {"SN/", validate_sn},
3924 {"LOC_POL/", validate_loc_pol},
3925 {"PWD_POL/", validate_pwd_pol},
3926 {"CRED/", validate_cred},
3927 {"UL/", validate_ul},
3928 {"GL/", validate_gl},
3929 {"UG/", validate_ug},
3930 {"UA", validate_ua},
3931 {"GM/", validate_gm},
3932 {"DR/", validate_dr},
3933 {"DE/", validate_de},
3934 {"NSS/PWINFO/", validate_pwinfo},
3935 {"TRUSTDOMCACHE/", validate_trustdomcache},
3936 {"NSS/NA/", validate_nss_na},
3937 {"NSS/AN/", validate_nss_an},
3938 {"WINBINDD_OFFLINE", validate_offline},
3939 {"NDR/", validate_ndr},
3940 {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version},
3944 /***********************************************************************
3945 Function to look at every entry in the tdb and validate it as far as
3947 ***********************************************************************/
3949 static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
3952 unsigned int max_key_len = 1024;
3953 struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
3955 /* Paranoia check. */
3956 if (strncmp("UA/", (const char *)kbuf.dptr, 3) == 0) {
3957 max_key_len = 1024 * 1024;
3959 if (kbuf.dsize > max_key_len) {
3960 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
3962 (unsigned int)kbuf.dsize, (unsigned int)max_key_len));
3966 for (i = 0; key_val[i].keyname; i++) {
3967 size_t namelen = strlen(key_val[i].keyname);
3968 if (kbuf.dsize >= namelen && (
3969 strncmp(key_val[i].keyname, (const char *)kbuf.dptr, namelen)) == 0) {
3970 TALLOC_CTX *mem_ctx;
3974 keystr = SMB_MALLOC_ARRAY(char, kbuf.dsize+1);
3978 memcpy(keystr, kbuf.dptr, kbuf.dsize);
3979 keystr[kbuf.dsize] = '\0';
3981 mem_ctx = talloc_init("validate_ctx");
3987 ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf,
3991 talloc_destroy(mem_ctx);
3996 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
3997 dump_data(0, (uint8 *)kbuf.dptr, kbuf.dsize);
3998 DEBUG(0,("data :\n"));
3999 dump_data(0, (uint8 *)dbuf.dptr, dbuf.dsize);
4000 v_state->unknown_key = true;
4001 v_state->success = false;
4002 return 1; /* terminate. */
4005 static void validate_panic(const char *const why)
4007 DEBUG(0,("validating cache: would panic %s\n", why ));
4008 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4012 /***********************************************************************
4013 Try and validate every entry in the winbindd cache. If we fail here,
4014 delete the cache tdb and return non-zero.
4015 ***********************************************************************/
4017 int winbindd_validate_cache(void)
4020 const char *tdb_path = cache_path("winbindd_cache.tdb");
4021 TDB_CONTEXT *tdb = NULL;
4023 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4024 smb_panic_fn = validate_panic;
4027 tdb = tdb_open_log(tdb_path,
4028 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
4029 ( lp_winbind_offline_logon()
4031 : TDB_DEFAULT | TDB_CLEAR_IF_FIRST ),
4035 DEBUG(0, ("winbindd_validate_cache: "
4036 "error opening/initializing tdb\n"));
4041 ret = tdb_validate_and_backup(tdb_path, cache_traverse_validate_fn);
4044 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4045 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
4050 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4051 smb_panic_fn = smb_panic;
4055 /***********************************************************************
4056 Try and validate every entry in the winbindd cache.
4057 ***********************************************************************/
4059 int winbindd_validate_cache_nobackup(void)
4062 const char *tdb_path = cache_path("winbindd_cache.tdb");
4064 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4065 smb_panic_fn = validate_panic;
4068 if (wcache == NULL || wcache->tdb == NULL) {
4069 ret = tdb_validate_open(tdb_path, cache_traverse_validate_fn);
4071 ret = tdb_validate(wcache->tdb, cache_traverse_validate_fn);
4075 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4079 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4081 smb_panic_fn = smb_panic;
4085 bool winbindd_cache_validate_and_initialize(void)
4087 close_winbindd_cache();
4089 if (lp_winbind_offline_logon()) {
4090 if (winbindd_validate_cache() < 0) {
4091 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4092 "could be restored.\n"));
4096 return initialize_winbindd_cache();
4099 /*********************************************************************
4100 ********************************************************************/
4102 static bool add_wbdomain_to_tdc_array( struct winbindd_domain *new_dom,
4103 struct winbindd_tdc_domain **domains,
4104 size_t *num_domains )
4106 struct winbindd_tdc_domain *list = NULL;
4109 bool set_only = false;
4111 /* don't allow duplicates */
4116 for ( i=0; i< (*num_domains); i++ ) {
4117 if ( strequal( new_dom->name, list[i].domain_name ) ) {
4118 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4129 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, 1 );
4132 list = TALLOC_REALLOC_ARRAY( *domains, *domains,
4133 struct winbindd_tdc_domain,
4138 ZERO_STRUCT( list[idx] );
4144 list[idx].domain_name = talloc_strdup( list, new_dom->name );
4145 list[idx].dns_name = talloc_strdup( list, new_dom->alt_name );
4147 if ( !is_null_sid( &new_dom->sid ) ) {
4148 sid_copy( &list[idx].sid, &new_dom->sid );
4150 sid_copy(&list[idx].sid, &global_sid_NULL);
4153 if ( new_dom->domain_flags != 0x0 )
4154 list[idx].trust_flags = new_dom->domain_flags;
4156 if ( new_dom->domain_type != 0x0 )
4157 list[idx].trust_type = new_dom->domain_type;
4159 if ( new_dom->domain_trust_attribs != 0x0 )
4160 list[idx].trust_attribs = new_dom->domain_trust_attribs;
4164 *num_domains = idx + 1;
4170 /*********************************************************************
4171 ********************************************************************/
4173 static TDB_DATA make_tdc_key( const char *domain_name )
4175 char *keystr = NULL;
4176 TDB_DATA key = { NULL, 0 };
4178 if ( !domain_name ) {
4179 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4183 if (asprintf( &keystr, "TRUSTDOMCACHE/%s", domain_name ) == -1) {
4186 key = string_term_tdb_data(keystr);
4191 /*********************************************************************
4192 ********************************************************************/
4194 static int pack_tdc_domains( struct winbindd_tdc_domain *domains,
4196 unsigned char **buf )
4198 unsigned char *buffer = NULL;
4203 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4211 /* Store the number of array items first */
4212 len += tdb_pack( buffer+len, buflen-len, "d",
4215 /* now pack each domain trust record */
4216 for ( i=0; i<num_domains; i++ ) {
4221 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4222 domains[i].domain_name,
4223 domains[i].dns_name ? domains[i].dns_name : "UNKNOWN" ));
4226 len += tdb_pack( buffer+len, buflen-len, "fffddd",
4227 domains[i].domain_name,
4228 domains[i].dns_name,
4229 sid_to_fstring(tmp, &domains[i].sid),
4230 domains[i].trust_flags,
4231 domains[i].trust_attribs,
4232 domains[i].trust_type );
4235 if ( buflen < len ) {
4237 if ( (buffer = SMB_MALLOC_ARRAY(unsigned char, len)) == NULL ) {
4238 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4252 /*********************************************************************
4253 ********************************************************************/
4255 static size_t unpack_tdc_domains( unsigned char *buf, int buflen,
4256 struct winbindd_tdc_domain **domains )
4258 fstring domain_name, dns_name, sid_string;
4259 uint32 type, attribs, flags;
4263 struct winbindd_tdc_domain *list = NULL;
4265 /* get the number of domains */
4266 len += tdb_unpack( buf+len, buflen-len, "d", &num_domains);
4268 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4272 list = TALLOC_ARRAY( NULL, struct winbindd_tdc_domain, num_domains );
4274 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4278 for ( i=0; i<num_domains; i++ ) {
4279 len += tdb_unpack( buf+len, buflen-len, "fffddd",
4288 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4289 TALLOC_FREE( list );
4293 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4294 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4295 domain_name, dns_name, sid_string,
4296 flags, attribs, type));
4298 list[i].domain_name = talloc_strdup( list, domain_name );
4299 list[i].dns_name = talloc_strdup( list, dns_name );
4300 if ( !string_to_sid( &(list[i].sid), sid_string ) ) {
4301 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4304 list[i].trust_flags = flags;
4305 list[i].trust_attribs = attribs;
4306 list[i].trust_type = type;
4314 /*********************************************************************
4315 ********************************************************************/
4317 static bool wcache_tdc_store_list( struct winbindd_tdc_domain *domains, size_t num_domains )
4319 TDB_DATA key = make_tdc_key( lp_workgroup() );
4320 TDB_DATA data = { NULL, 0 };
4326 /* See if we were asked to delete the cache entry */
4329 ret = tdb_delete( wcache->tdb, key );
4333 data.dsize = pack_tdc_domains( domains, num_domains, &data.dptr );
4340 ret = tdb_store( wcache->tdb, key, data, 0 );
4343 SAFE_FREE( data.dptr );
4344 SAFE_FREE( key.dptr );
4346 return ( ret != -1 );
4349 /*********************************************************************
4350 ********************************************************************/
4352 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain **domains, size_t *num_domains )
4354 TDB_DATA key = make_tdc_key( lp_workgroup() );
4355 TDB_DATA data = { NULL, 0 };
4363 data = tdb_fetch( wcache->tdb, key );
4365 SAFE_FREE( key.dptr );
4370 *num_domains = unpack_tdc_domains( data.dptr, data.dsize, domains );
4372 SAFE_FREE( data.dptr );
4380 /*********************************************************************
4381 ********************************************************************/
4383 bool wcache_tdc_add_domain( struct winbindd_domain *domain )
4385 struct winbindd_tdc_domain *dom_list = NULL;
4386 size_t num_domains = 0;
4389 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4390 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4391 domain->name, domain->alt_name,
4392 sid_string_dbg(&domain->sid),
4393 domain->domain_flags,
4394 domain->domain_trust_attribs,
4395 domain->domain_type));
4397 if ( !init_wcache() ) {
4401 /* fetch the list */
4403 wcache_tdc_fetch_list( &dom_list, &num_domains );
4405 /* add the new domain */
4407 if ( !add_wbdomain_to_tdc_array( domain, &dom_list, &num_domains ) ) {
4411 /* pack the domain */
4413 if ( !wcache_tdc_store_list( dom_list, num_domains ) ) {
4421 TALLOC_FREE( dom_list );
4426 /*********************************************************************
4427 ********************************************************************/
4429 struct winbindd_tdc_domain * wcache_tdc_fetch_domain( TALLOC_CTX *ctx, const char *name )
4431 struct winbindd_tdc_domain *dom_list = NULL;
4432 size_t num_domains = 0;
4434 struct winbindd_tdc_domain *d = NULL;
4436 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name));
4438 if ( !init_wcache() ) {
4442 /* fetch the list */
4444 wcache_tdc_fetch_list( &dom_list, &num_domains );
4446 for ( i=0; i<num_domains; i++ ) {
4447 if ( strequal(name, dom_list[i].domain_name) ||
4448 strequal(name, dom_list[i].dns_name) )
4450 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4453 d = TALLOC_P( ctx, struct winbindd_tdc_domain );
4457 d->domain_name = talloc_strdup( d, dom_list[i].domain_name );
4458 d->dns_name = talloc_strdup( d, dom_list[i].dns_name );
4459 sid_copy( &d->sid, &dom_list[i].sid );
4460 d->trust_flags = dom_list[i].trust_flags;
4461 d->trust_type = dom_list[i].trust_type;
4462 d->trust_attribs = dom_list[i].trust_attribs;
4468 TALLOC_FREE( dom_list );
4474 /*********************************************************************
4475 ********************************************************************/
4477 void wcache_tdc_clear( void )
4479 if ( !init_wcache() )
4482 wcache_tdc_store_list( NULL, 0 );
4488 /*********************************************************************
4489 ********************************************************************/
4491 static void wcache_save_user_pwinfo(struct winbindd_domain *domain,
4493 const DOM_SID *user_sid,
4494 const char *homedir,
4499 struct cache_entry *centry;
4502 if ( (centry = centry_start(domain, status)) == NULL )
4505 centry_put_string( centry, homedir );
4506 centry_put_string( centry, shell );
4507 centry_put_string( centry, gecos );
4508 centry_put_uint32( centry, gid );
4510 centry_end(centry, "NSS/PWINFO/%s", sid_to_fstring(tmp, user_sid) );
4512 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid) ));
4514 centry_free(centry);
4517 NTSTATUS nss_get_info_cached( struct winbindd_domain *domain,
4518 const DOM_SID *user_sid,
4520 ADS_STRUCT *ads, LDAPMessage *msg,
4521 const char **homedir, const char **shell,
4522 const char **gecos, gid_t *p_gid)
4524 struct winbind_cache *cache = get_cache(domain);
4525 struct cache_entry *centry = NULL;
4532 centry = wcache_fetch(cache, domain, "NSS/PWINFO/%s",
4533 sid_to_fstring(tmp, user_sid));
4538 *homedir = centry_string( centry, ctx );
4539 *shell = centry_string( centry, ctx );
4540 *gecos = centry_string( centry, ctx );
4541 *p_gid = centry_uint32( centry );
4543 centry_free(centry);
4545 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4546 sid_string_dbg(user_sid)));
4548 return NT_STATUS_OK;
4552 nt_status = nss_get_info( domain->name, user_sid, ctx, ads, msg,
4553 homedir, shell, gecos, p_gid );
4555 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status)));
4557 if ( NT_STATUS_IS_OK(nt_status) ) {
4558 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir));
4559 DEBUGADD(10, ("\tshell = '%s'\n", *shell));
4560 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos));
4561 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid));
4563 wcache_save_user_pwinfo( domain, nt_status, user_sid,
4564 *homedir, *shell, *gecos, *p_gid );
4567 if ( NT_STATUS_EQUAL( nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND ) ) {
4568 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4570 set_domain_offline( domain );
4577 /* the cache backend methods are exposed via this structure */
4578 struct winbindd_methods cache_methods = {
4596 static bool wcache_ndr_key(TALLOC_CTX *mem_ctx, char *domain_name,
4597 uint32_t opnum, const DATA_BLOB *req,
4603 key = talloc_asprintf(mem_ctx, "NDR/%s/%d/", domain_name, (int)opnum);
4607 keylen = talloc_get_size(key) - 1;
4609 key = talloc_realloc(mem_ctx, key, char, keylen + req->length);
4613 memcpy(key + keylen, req->data, req->length);
4615 pkey->dptr = (uint8_t *)key;
4616 pkey->dsize = talloc_get_size(key);
4620 static bool wcache_opnum_cacheable(uint32_t opnum)
4623 case NDR_WBINT_PING:
4624 case NDR_WBINT_QUERYSEQUENCENUMBER:
4625 case NDR_WBINT_ALLOCATEUID:
4626 case NDR_WBINT_ALLOCATEGID:
4627 case NDR_WBINT_CHECKMACHINEACCOUNT:
4628 case NDR_WBINT_CHANGEMACHINEACCOUNT:
4629 case NDR_WBINT_PINGDC:
4635 bool wcache_fetch_ndr(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
4636 uint32_t opnum, const DATA_BLOB *req, DATA_BLOB *resp)
4641 if (!wcache_opnum_cacheable(opnum)) {
4645 if (wcache->tdb == NULL) {
4649 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4652 data = tdb_fetch(wcache->tdb, key);
4653 TALLOC_FREE(key.dptr);
4655 if (data.dptr == NULL) {
4658 if (data.dsize < 4) {
4662 if (!is_domain_offline(domain)) {
4663 uint32_t entry_seqnum, dom_seqnum, last_check;
4665 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum,
4669 entry_seqnum = IVAL(data.dptr, 0);
4670 if (entry_seqnum != dom_seqnum) {
4671 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4672 (int)entry_seqnum));
4677 resp->data = (uint8_t *)talloc_memdup(mem_ctx, data.dptr + 4,
4679 if (resp->data == NULL) {
4680 DEBUG(10, ("talloc failed\n"));
4683 resp->length = data.dsize - 4;
4687 SAFE_FREE(data.dptr);
4691 void wcache_store_ndr(struct winbindd_domain *domain, uint32_t opnum,
4692 const DATA_BLOB *req, const DATA_BLOB *resp)
4695 uint32_t dom_seqnum, last_check;
4697 if (!wcache_opnum_cacheable(opnum)) {
4701 if (wcache->tdb == NULL) {
4705 if (!wcache_fetch_seqnum(domain->name, &dom_seqnum, &last_check)) {
4706 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4711 if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) {
4715 data.dsize = resp->length + 4;
4716 data.dptr = talloc_array(key.dptr, uint8_t, data.dsize);
4717 if (data.dptr == NULL) {
4721 SIVAL(data.dptr, 0, dom_seqnum);
4722 memcpy(data.dptr+4, resp->data, resp->length);
4724 tdb_store(wcache->tdb, key, data, 0);
4727 TALLOC_FREE(key.dptr);