2 Unix SMB/CIFS implementation.
4 Winbind cache backend functions
6 Copyright (C) Andrew Tridgell 2001
7 Copyright (C) Gerald Carter 2003-2007
8 Copyright (C) Volker Lendecke 2005
9 Copyright (C) Guenther Deschner 2005
10 Copyright (C) Michael Adam 2007
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include "system/filesys.h"
29 #include "tdb_validate.h"
30 #include "../libcli/auth/libcli_auth.h"
31 #include "../librpc/gen_ndr/ndr_winbind.h"
34 #include "../libcli/security/security.h"
35 #include "passdb/machine_sid.h"
37 #include "libsmb/samlogon_cache.h"
38 #include "lib/namemap_cache.h"
39 #include "lib/util/string_wrappers.h"
41 #include "lib/crypto/gnutls_helpers.h"
42 #include <gnutls/crypto.h>
45 #define DBGC_CLASS DBGC_WINBIND
47 #define WINBINDD_CACHE_VER1 1 /* initial db version */
48 #define WINBINDD_CACHE_VER2 2 /* second version with timeouts for NDR entries */
50 #define WINBINDD_CACHE_VERSION WINBINDD_CACHE_VER2
51 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
53 extern struct winbindd_methods reconnect_methods
;
55 extern struct winbindd_methods reconnect_ads_methods
;
57 extern struct winbindd_methods builtin_passdb_methods
;
58 extern struct winbindd_methods sam_passdb_methods
;
60 static void wcache_flush_cache(void);
63 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
64 * Here are the list of entry types that are *not* stored
65 * as form struct cache_entry in the cache.
68 static const char *non_centry_keys
[] = {
71 WINBINDD_CACHE_VERSION_KEYSTR
,
75 /************************************************************************
76 Is this key a non-centry type ?
77 ************************************************************************/
79 static bool is_non_centry_key(TDB_DATA kbuf
)
83 if (kbuf
.dptr
== NULL
|| kbuf
.dsize
== 0) {
86 for (i
= 0; non_centry_keys
[i
] != NULL
; i
++) {
87 size_t namelen
= strlen(non_centry_keys
[i
]);
88 if (kbuf
.dsize
< namelen
) {
91 if (strncmp(non_centry_keys
[i
], (const char *)kbuf
.dptr
, namelen
) == 0) {
98 struct winbind_cache
{
104 uint32_t sequence_number
;
110 void (*smb_panic_fn
)(const char *const why
) = smb_panic
;
112 static struct winbind_cache
*wcache
;
114 static char *wcache_path(void)
117 * Data needs to be kept persistent in state directory for
118 * running with "winbindd offline logon".
120 return state_path(talloc_tos(), "winbindd_cache.tdb");
123 static void winbindd_domain_init_backend(struct winbindd_domain
*domain
)
125 if (domain
->backend
!= NULL
) {
129 if (domain
->internal
) {
130 domain
->backend
= &builtin_passdb_methods
;
133 if (dom_sid_equal(&domain
->sid
, &global_sid_Builtin
)) {
134 domain
->initialized
= true;
137 if (strequal(domain
->name
, get_global_sam_name()) &&
138 sid_check_is_our_sam(&domain
->sid
))
140 domain
->backend
= &sam_passdb_methods
;
143 if (!domain
->initialized
) {
144 /* We do not need a connection to an RW DC for cache operation */
145 init_dc_connection(domain
, false);
149 if (domain
->backend
== NULL
) {
150 struct winbindd_domain
*our_domain
= domain
;
152 /* find our domain first so we can figure out if we
153 are joined to a kerberized domain */
155 if (!domain
->primary
) {
156 our_domain
= find_our_domain();
159 if ((our_domain
->active_directory
|| IS_DC
)
160 && domain
->active_directory
161 && !lp_winbind_rpc_only())
163 DBG_INFO("Setting ADS methods for domain %s\n",
165 domain
->backend
= &reconnect_ads_methods
;
168 #endif /* HAVE_ADS */
170 if (domain
->backend
== NULL
) {
171 DBG_INFO("Setting MS-RPC methods for domain %s\n", domain
->name
);
172 domain
->backend
= &reconnect_methods
;
176 /* get the winbind_cache structure */
177 static struct winbind_cache
*get_cache(struct winbindd_domain
*domain
)
179 struct winbind_cache
*ret
= wcache
;
181 winbindd_domain_init_backend(domain
);
187 ret
= SMB_XMALLOC_P(struct winbind_cache
);
191 wcache_flush_cache();
197 free a centry structure
199 static void centry_free(struct cache_entry
*centry
)
203 SAFE_FREE(centry
->data
);
207 static bool centry_check_bytes(struct cache_entry
*centry
, size_t nbytes
)
209 if (centry
->len
- centry
->ofs
< nbytes
) {
210 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
211 (unsigned int)nbytes
,
212 centry
->len
- centry
->ofs
));
219 pull a uint64_t from a cache entry
221 static uint64_t centry_uint64_t(struct cache_entry
*centry
)
225 if (!centry_check_bytes(centry
, 8)) {
226 smb_panic_fn("centry_uint64_t");
228 ret
= BVAL(centry
->data
, centry
->ofs
);
234 pull a uint32_t from a cache entry
236 static uint32_t centry_uint32(struct cache_entry
*centry
)
240 if (!centry_check_bytes(centry
, 4)) {
241 smb_panic_fn("centry_uint32");
243 ret
= IVAL(centry
->data
, centry
->ofs
);
249 pull a uint16_t from a cache entry
251 static uint16_t centry_uint16(struct cache_entry
*centry
)
254 if (!centry_check_bytes(centry
, 2)) {
255 smb_panic_fn("centry_uint16");
257 ret
= SVAL(centry
->data
, centry
->ofs
);
263 pull a uint8_t from a cache entry
265 static uint8_t centry_uint8(struct cache_entry
*centry
)
268 if (!centry_check_bytes(centry
, 1)) {
269 smb_panic_fn("centry_uint8");
271 ret
= CVAL(centry
->data
, centry
->ofs
);
277 pull a NTTIME from a cache entry
279 static NTTIME
centry_nttime(struct cache_entry
*centry
)
282 if (!centry_check_bytes(centry
, 8)) {
283 smb_panic_fn("centry_nttime");
285 ret
= IVAL(centry
->data
, centry
->ofs
);
287 ret
+= (uint64_t)IVAL(centry
->data
, centry
->ofs
) << 32;
293 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
295 static time_t centry_time(struct cache_entry
*centry
)
297 return (time_t)centry_nttime(centry
);
300 /* pull a string from a cache entry, using the supplied
303 static char *centry_string(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
308 len
= centry_uint8(centry
);
311 /* a deliberate NULL string */
315 if (!centry_check_bytes(centry
, (size_t)len
)) {
316 smb_panic_fn("centry_string");
319 ret
= talloc_array(mem_ctx
, char, len
+1);
321 smb_panic_fn("centry_string out of memory\n");
323 memcpy(ret
,centry
->data
+ centry
->ofs
, len
);
329 /* pull a hash16 from a cache entry, using the supplied
332 static char *centry_hash16(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
337 len
= centry_uint8(centry
);
340 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
345 if (!centry_check_bytes(centry
, 16)) {
349 ret
= talloc_array(mem_ctx
, char, 16);
351 smb_panic_fn("centry_hash out of memory\n");
353 memcpy(ret
,centry
->data
+ centry
->ofs
, 16);
358 /* pull a sid from a cache entry, using the supplied
361 static bool centry_sid(struct cache_entry
*centry
, struct dom_sid
*sid
)
366 sid_string
= centry_string(centry
, talloc_tos());
367 if (sid_string
== NULL
) {
370 ret
= string_to_sid(sid
, sid_string
);
371 TALLOC_FREE(sid_string
);
377 pull a NTSTATUS from a cache entry
379 static NTSTATUS
centry_ntstatus(struct cache_entry
*centry
)
383 status
= NT_STATUS(centry_uint32(centry
));
388 /* the server is considered down if it can't give us a sequence number */
389 static bool wcache_server_down(struct winbindd_domain
*domain
)
396 ret
= (domain
->sequence_number
== DOM_SEQUENCE_NONE
);
399 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
404 struct wcache_seqnum_state
{
406 uint32_t *last_seq_check
;
409 static int wcache_seqnum_parser(TDB_DATA key
, TDB_DATA data
,
412 struct wcache_seqnum_state
*state
= private_data
;
414 if (data
.dsize
!= 8) {
415 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
420 *state
->seqnum
= IVAL(data
.dptr
, 0);
421 *state
->last_seq_check
= IVAL(data
.dptr
, 4);
425 static bool wcache_fetch_seqnum(const char *domain_name
, uint32_t *seqnum
,
426 uint32_t *last_seq_check
)
428 struct wcache_seqnum_state state
= {
429 .seqnum
= seqnum
, .last_seq_check
= last_seq_check
431 size_t len
= strlen(domain_name
);
433 TDB_DATA key
= { .dptr
= (uint8_t *)keystr
, .dsize
= sizeof(keystr
) };
436 if (wcache
->tdb
== NULL
) {
437 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
441 snprintf(keystr
, sizeof(keystr
), "SEQNUM/%s", domain_name
);
443 ret
= tdb_parse_record(wcache
->tdb
, key
, wcache_seqnum_parser
,
448 static NTSTATUS
fetch_cache_seqnum( struct winbindd_domain
*domain
, time_t now
)
450 uint32_t last_check
, time_diff
;
452 if (!wcache_fetch_seqnum(domain
->name
, &domain
->sequence_number
,
454 return NT_STATUS_UNSUCCESSFUL
;
456 domain
->last_seq_check
= last_check
;
458 /* have we expired? */
460 time_diff
= now
- domain
->last_seq_check
;
461 if ((int)time_diff
> lp_winbind_cache_time()) {
462 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
463 domain
->name
, domain
->sequence_number
,
464 (uint32_t)domain
->last_seq_check
));
465 return NT_STATUS_UNSUCCESSFUL
;
468 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
469 domain
->name
, domain
->sequence_number
,
470 (uint32_t)domain
->last_seq_check
));
475 bool wcache_store_seqnum(const char *domain_name
, uint32_t seqnum
,
476 time_t last_seq_check
)
478 size_t len
= strlen(domain_name
);
480 TDB_DATA key
= { .dptr
= (uint8_t *)keystr
, .dsize
= sizeof(keystr
) };
484 if (wcache
->tdb
== NULL
) {
485 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
489 snprintf(keystr
, sizeof(keystr
), "SEQNUM/%s", domain_name
);
491 SIVAL(buf
, 0, seqnum
);
492 SIVAL(buf
, 4, last_seq_check
);
494 ret
= tdb_store(wcache
->tdb
, key
, make_tdb_data(buf
, sizeof(buf
)),
497 DEBUG(10, ("tdb_store_bystring failed: %s\n",
498 tdb_errorstr(wcache
->tdb
)));
502 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
503 domain_name
, seqnum
, (unsigned)last_seq_check
));
508 static bool store_cache_seqnum( struct winbindd_domain
*domain
)
510 return wcache_store_seqnum(domain
->name
, domain
->sequence_number
,
511 domain
->last_seq_check
);
515 refresh the domain sequence number on timeout.
518 static void refresh_sequence_number(struct winbindd_domain
*domain
)
522 time_t t
= time(NULL
);
523 unsigned cache_time
= lp_winbind_cache_time();
525 if (is_domain_offline(domain
)) {
531 time_diff
= t
- domain
->last_seq_check
;
533 /* see if we have to refetch the domain sequence number */
534 if ((time_diff
< cache_time
) &&
535 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
536 NT_STATUS_IS_OK(domain
->last_status
)) {
537 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain
->name
));
541 /* try to get the sequence number from the tdb cache first */
542 /* this will update the timestamp as well */
544 status
= fetch_cache_seqnum( domain
, t
);
545 if (NT_STATUS_IS_OK(status
) &&
546 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
547 NT_STATUS_IS_OK(domain
->last_status
)) {
551 /* just use the current time */
552 domain
->last_status
= NT_STATUS_OK
;
553 domain
->sequence_number
= time(NULL
);
554 domain
->last_seq_check
= time(NULL
);
556 /* save the new sequence number in the cache */
557 store_cache_seqnum( domain
);
560 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
561 domain
->name
, domain
->sequence_number
));
567 decide if a cache entry has expired
569 static bool centry_expired(struct winbindd_domain
*domain
, const char *keystr
, struct cache_entry
*centry
)
571 /* If we've been told to be offline - stay in that state... */
572 if (lp_winbind_offline_logon() && get_global_winbindd_state_offline()) {
573 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
574 keystr
, domain
->name
));
578 /* when the domain is offline return the cached entry.
579 * This deals with transient offline states... */
581 if (!domain
->online
) {
582 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
583 keystr
, domain
->name
));
587 /* if the server is OK and our cache entry came from when it was down then
588 the entry is invalid */
589 if ((domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
590 (centry
->sequence_number
== DOM_SEQUENCE_NONE
)) {
591 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
592 keystr
, domain
->name
));
596 /* if the server is down or the cache entry is not older than the
597 current sequence number or it did not timeout then it is OK */
598 if (wcache_server_down(domain
)
599 || ((centry
->sequence_number
== domain
->sequence_number
)
600 && ((time_t)centry
->timeout
> time(NULL
)))) {
601 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
602 keystr
, domain
->name
));
606 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
607 keystr
, domain
->name
));
613 static struct cache_entry
*wcache_fetch_raw(char *kstr
)
616 struct cache_entry
*centry
;
619 key
= string_tdb_data(kstr
);
620 data
= tdb_fetch(wcache
->tdb
, key
);
626 centry
= SMB_XMALLOC_P(struct cache_entry
);
627 centry
->data
= (unsigned char *)data
.dptr
;
628 centry
->len
= data
.dsize
;
631 if (centry
->len
< 16) {
632 /* huh? corrupt cache? */
633 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s "
634 "(len < 16)?\n", kstr
));
639 centry
->status
= centry_ntstatus(centry
);
640 centry
->sequence_number
= centry_uint32(centry
);
641 centry
->timeout
= centry_uint64_t(centry
);
646 static bool is_my_own_sam_domain(struct winbindd_domain
*domain
)
648 if (strequal(domain
->name
, get_global_sam_name()) &&
649 sid_check_is_our_sam(&domain
->sid
)) {
656 static bool is_builtin_domain(struct winbindd_domain
*domain
)
658 if (strequal(domain
->name
, "BUILTIN") &&
659 sid_check_is_builtin(&domain
->sid
)) {
667 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
668 number and return status
670 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
671 struct winbindd_domain
*domain
,
672 const char *format
, ...) PRINTF_ATTRIBUTE(3,4);
673 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
674 struct winbindd_domain
*domain
,
675 const char *format
, ...)
679 struct cache_entry
*centry
;
682 if (!winbindd_use_cache() ||
683 is_my_own_sam_domain(domain
) ||
684 is_builtin_domain(domain
)) {
688 refresh_sequence_number(domain
);
690 va_start(ap
, format
);
691 ret
= vasprintf(&kstr
, format
, ap
);
698 centry
= wcache_fetch_raw(kstr
);
699 if (centry
== NULL
) {
704 if (centry_expired(domain
, kstr
, centry
)) {
706 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
707 kstr
, domain
->name
));
714 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
715 kstr
, domain
->name
));
721 static void wcache_delete(const char *format
, ...) PRINTF_ATTRIBUTE(1,2);
722 static void wcache_delete(const char *format
, ...)
729 va_start(ap
, format
);
730 ret
= vasprintf(&kstr
, format
, ap
);
737 key
= string_tdb_data(kstr
);
739 tdb_delete(wcache
->tdb
, key
);
744 make sure we have at least len bytes available in a centry
746 static void centry_expand(struct cache_entry
*centry
, uint32_t len
)
748 if (centry
->len
- centry
->ofs
>= len
)
751 centry
->data
= SMB_REALLOC_ARRAY(centry
->data
, unsigned char,
754 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry
->len
));
755 smb_panic_fn("out of memory in centry_expand");
760 push a uint64_t into a centry
762 static void centry_put_uint64_t(struct cache_entry
*centry
, uint64_t v
)
764 centry_expand(centry
, 8);
765 SBVAL(centry
->data
, centry
->ofs
, v
);
770 push a uint32_t into a centry
772 static void centry_put_uint32(struct cache_entry
*centry
, uint32_t v
)
774 centry_expand(centry
, 4);
775 SIVAL(centry
->data
, centry
->ofs
, v
);
780 push a uint16_t into a centry
782 static void centry_put_uint16(struct cache_entry
*centry
, uint16_t v
)
784 centry_expand(centry
, 2);
785 SSVAL(centry
->data
, centry
->ofs
, v
);
790 push a uint8_t into a centry
792 static void centry_put_uint8(struct cache_entry
*centry
, uint8_t v
)
794 centry_expand(centry
, 1);
795 SCVAL(centry
->data
, centry
->ofs
, v
);
800 push a string into a centry
802 static void centry_put_string(struct cache_entry
*centry
, const char *s
)
807 /* null strings are marked as len 0xFFFF */
808 centry_put_uint8(centry
, 0xFF);
813 /* can't handle more than 254 char strings. Truncating is probably best */
815 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len
));
818 centry_put_uint8(centry
, len
);
819 centry_expand(centry
, len
);
820 memcpy(centry
->data
+ centry
->ofs
, s
, len
);
825 push a 16 byte hash into a centry - treat as 16 byte string.
827 static void centry_put_hash16(struct cache_entry
*centry
, const uint8_t val
[16])
829 centry_put_uint8(centry
, 16);
830 centry_expand(centry
, 16);
831 memcpy(centry
->data
+ centry
->ofs
, val
, 16);
835 static void centry_put_sid(struct cache_entry
*centry
, const struct dom_sid
*sid
)
837 struct dom_sid_buf sid_string
;
838 centry_put_string(centry
, dom_sid_str_buf(sid
, &sid_string
));
843 put NTSTATUS into a centry
845 static void centry_put_ntstatus(struct cache_entry
*centry
, NTSTATUS status
)
847 uint32_t status_value
= NT_STATUS_V(status
);
848 centry_put_uint32(centry
, status_value
);
853 push a NTTIME into a centry
855 static void centry_put_nttime(struct cache_entry
*centry
, NTTIME nt
)
857 centry_expand(centry
, 8);
858 SIVAL(centry
->data
, centry
->ofs
, nt
& 0xFFFFFFFF);
860 SIVAL(centry
->data
, centry
->ofs
, nt
>> 32);
865 push a time_t into a centry - use a 64 bit size.
866 NTTIME here is being used as a convenient 64-bit size.
868 static void centry_put_time(struct cache_entry
*centry
, time_t t
)
870 NTTIME nt
= (NTTIME
)t
;
871 centry_put_nttime(centry
, nt
);
875 start a centry for output. When finished, call centry_end()
877 static struct cache_entry
*centry_start(struct winbindd_domain
*domain
,
880 struct cache_entry
*centry
;
885 centry
= SMB_XMALLOC_P(struct cache_entry
);
887 centry
->len
= 8192; /* reasonable default */
888 centry
->data
= SMB_XMALLOC_ARRAY(uint8_t, centry
->len
);
890 centry
->sequence_number
= domain
->sequence_number
;
891 centry
->timeout
= lp_winbind_cache_time() + time(NULL
);
892 centry_put_ntstatus(centry
, status
);
893 centry_put_uint32(centry
, centry
->sequence_number
);
894 centry_put_uint64_t(centry
, centry
->timeout
);
899 finish a centry and write it to the tdb
901 static void centry_end(struct cache_entry
*centry
, const char *format
, ...) PRINTF_ATTRIBUTE(2,3);
902 static void centry_end(struct cache_entry
*centry
, const char *format
, ...)
909 if (!winbindd_use_cache()) {
913 va_start(ap
, format
);
914 ret
= vasprintf(&kstr
, format
, ap
);
921 key
= string_tdb_data(kstr
);
922 data
.dptr
= centry
->data
;
923 data
.dsize
= centry
->ofs
;
925 tdb_store(wcache
->tdb
, key
, data
, TDB_REPLACE
);
929 static void wcache_save_name_to_sid(struct winbindd_domain
*domain
,
930 NTSTATUS status
, const char *domain_name
,
931 const char *name
, const struct dom_sid
*sid
,
932 enum lsa_SidType type
)
936 ok
= namemap_cache_set_name2sid(domain_name
, name
, sid
, type
,
937 time(NULL
) + lp_winbind_cache_time());
939 DBG_DEBUG("namemap_cache_set_name2sid failed\n");
943 * Don't store the reverse mapping. The name came from user
944 * input, and we might not have the correct capitalization,
945 * which is important for nsswitch.
949 static void wcache_save_sid_to_name(struct winbindd_domain
*domain
, NTSTATUS status
,
950 const struct dom_sid
*sid
, const char *domain_name
, const char *name
, enum lsa_SidType type
)
954 ok
= namemap_cache_set_sid2name(sid
, domain_name
, name
, type
,
955 time(NULL
) + lp_winbind_cache_time());
957 DBG_DEBUG("namemap_cache_set_sid2name failed\n");
960 if (type
!= SID_NAME_UNKNOWN
) {
961 ok
= namemap_cache_set_name2sid(
962 domain_name
, name
, sid
, type
,
963 time(NULL
) + lp_winbind_cache_time());
965 DBG_DEBUG("namemap_cache_set_name2sid failed\n");
970 static void wcache_save_lockout_policy(struct winbindd_domain
*domain
,
972 struct samr_DomInfo12
*lockout_policy
)
974 struct cache_entry
*centry
;
976 centry
= centry_start(domain
, status
);
980 centry_put_nttime(centry
, lockout_policy
->lockout_duration
);
981 centry_put_nttime(centry
, lockout_policy
->lockout_window
);
982 centry_put_uint16(centry
, lockout_policy
->lockout_threshold
);
984 centry_end(centry
, "LOC_POL/%s", domain
->name
);
986 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain
->name
));
993 static void wcache_save_password_policy(struct winbindd_domain
*domain
,
995 struct samr_DomInfo1
*policy
)
997 struct cache_entry
*centry
;
999 centry
= centry_start(domain
, status
);
1003 centry_put_uint16(centry
, policy
->min_password_length
);
1004 centry_put_uint16(centry
, policy
->password_history_length
);
1005 centry_put_uint32(centry
, policy
->password_properties
);
1006 centry_put_nttime(centry
, policy
->max_password_age
);
1007 centry_put_nttime(centry
, policy
->min_password_age
);
1009 centry_end(centry
, "PWD_POL/%s", domain
->name
);
1011 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
1013 centry_free(centry
);
1016 /***************************************************************************
1017 ***************************************************************************/
1019 static void wcache_save_username_alias(struct winbindd_domain
*domain
,
1021 const char *name
, const char *alias
)
1023 struct cache_entry
*centry
;
1026 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1029 centry_put_string( centry
, alias
);
1031 fstrcpy(uname
, name
);
1032 (void)strupper_m(uname
);
1033 centry_end(centry
, "NSS/NA/%s", uname
);
1035 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name
, alias
));
1037 centry_free(centry
);
1040 static void wcache_save_alias_username(struct winbindd_domain
*domain
,
1042 const char *alias
, const char *name
)
1044 struct cache_entry
*centry
;
1047 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1050 centry_put_string( centry
, name
);
1052 fstrcpy(uname
, alias
);
1053 (void)strupper_m(uname
);
1054 centry_end(centry
, "NSS/AN/%s", uname
);
1056 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias
, name
));
1058 centry_free(centry
);
1061 /***************************************************************************
1062 ***************************************************************************/
1064 NTSTATUS
resolve_username_to_alias( TALLOC_CTX
*mem_ctx
,
1065 struct winbindd_domain
*domain
,
1066 const char *name
, char **alias
)
1068 struct winbind_cache
*cache
= get_cache(domain
);
1069 struct cache_entry
*centry
= NULL
;
1073 if ( domain
->internal
)
1074 return NT_STATUS_NOT_SUPPORTED
;
1079 upper_name
= talloc_strdup_upper(mem_ctx
, name
);
1080 if (upper_name
== NULL
) {
1081 return NT_STATUS_NO_MEMORY
;
1084 centry
= wcache_fetch(cache
, domain
, "NSS/NA/%s", upper_name
);
1086 talloc_free(upper_name
);
1091 status
= centry
->status
;
1093 if (!NT_STATUS_IS_OK(status
)) {
1094 centry_free(centry
);
1098 *alias
= centry_string( centry
, mem_ctx
);
1100 centry_free(centry
);
1102 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1103 name
, *alias
? *alias
: "(none)"));
1105 return (*alias
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1109 /* If its not in cache and we are offline, then fail */
1111 if (is_domain_offline(domain
)) {
1112 DEBUG(8,("resolve_username_to_alias: rejecting query "
1113 "in offline mode\n"));
1114 return NT_STATUS_NOT_FOUND
;
1117 status
= nss_map_to_alias( mem_ctx
, domain
->name
, name
, alias
);
1119 if ( NT_STATUS_IS_OK( status
) ) {
1120 wcache_save_username_alias(domain
, status
, name
, *alias
);
1123 if ( NT_STATUS_EQUAL( status
, NT_STATUS_NONE_MAPPED
) ) {
1124 wcache_save_username_alias(domain
, status
, name
, "(NULL)");
1127 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1128 nt_errstr(status
)));
1130 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1131 set_domain_offline( domain
);
1137 /***************************************************************************
1138 ***************************************************************************/
1140 NTSTATUS
resolve_alias_to_username( TALLOC_CTX
*mem_ctx
,
1141 struct winbindd_domain
*domain
,
1142 const char *alias
, char **name
)
1144 struct winbind_cache
*cache
= get_cache(domain
);
1145 struct cache_entry
*centry
= NULL
;
1149 if ( domain
->internal
)
1150 return NT_STATUS_NOT_SUPPORTED
;
1155 upper_name
= talloc_strdup(mem_ctx
, alias
);
1156 if (upper_name
== NULL
) {
1157 return NT_STATUS_NO_MEMORY
;
1159 if (!strupper_m(upper_name
)) {
1160 talloc_free(upper_name
);
1161 return NT_STATUS_INVALID_PARAMETER
;
1164 centry
= wcache_fetch(cache
, domain
, "NSS/AN/%s", upper_name
);
1166 talloc_free(upper_name
);
1171 status
= centry
->status
;
1173 if (!NT_STATUS_IS_OK(status
)) {
1174 centry_free(centry
);
1178 *name
= centry_string( centry
, mem_ctx
);
1180 centry_free(centry
);
1182 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1183 alias
, *name
? *name
: "(none)"));
1185 return (*name
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1189 /* If its not in cache and we are offline, then fail */
1191 if (is_domain_offline(domain
)) {
1192 DEBUG(8,("resolve_alias_to_username: rejecting query "
1193 "in offline mode\n"));
1194 return NT_STATUS_NOT_FOUND
;
1197 /* an alias cannot contain a domain prefix or '@' */
1199 if (strchr(alias
, '\\') || strchr(alias
, '@')) {
1200 DEBUG(10,("resolve_alias_to_username: skipping fully "
1201 "qualified name %s\n", alias
));
1202 return NT_STATUS_OBJECT_NAME_INVALID
;
1205 status
= nss_map_from_alias( mem_ctx
, domain
->name
, alias
, name
);
1207 if ( NT_STATUS_IS_OK( status
) ) {
1208 wcache_save_alias_username( domain
, status
, alias
, *name
);
1211 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1212 wcache_save_alias_username(domain
, status
, alias
, "(NULL)");
1215 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1216 nt_errstr(status
)));
1218 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1219 set_domain_offline( domain
);
1225 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
1227 struct winbind_cache
*cache
= get_cache(domain
);
1229 struct dom_sid_buf tmp
;
1234 return NT_STATUS_INTERNAL_DB_ERROR
;
1237 if (is_null_sid(sid
)) {
1238 return NT_STATUS_INVALID_SID
;
1241 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1242 return NT_STATUS_INVALID_SID
;
1245 fstr_sprintf(key_str
, "CRED/%s", dom_sid_str_buf(sid
, &tmp
));
1247 ret
= tdb_exists(cache
->tdb
, string_tdb_data(key_str
));
1249 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1252 return NT_STATUS_OK
;
1255 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1256 as new salted ones. */
1258 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
1259 TALLOC_CTX
*mem_ctx
,
1260 const struct dom_sid
*sid
,
1261 const uint8_t **cached_nt_pass
,
1262 const uint8_t **cached_salt
)
1264 struct winbind_cache
*cache
= get_cache(domain
);
1265 struct cache_entry
*centry
= NULL
;
1268 struct dom_sid_buf sidstr
;
1271 return NT_STATUS_INTERNAL_DB_ERROR
;
1274 if (is_null_sid(sid
)) {
1275 return NT_STATUS_INVALID_SID
;
1278 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1279 return NT_STATUS_INVALID_SID
;
1282 /* Try and get a salted cred first. If we can't
1283 fall back to an unsalted cred. */
1285 centry
= wcache_fetch(cache
, domain
, "CRED/%s",
1286 dom_sid_str_buf(sid
, &sidstr
));
1288 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1289 dom_sid_str_buf(sid
, &sidstr
)));
1290 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1294 * We don't use the time element at this moment,
1295 * but we have to consume it, so that we don't
1296 * neet to change the disk format of the cache.
1298 (void)centry_time(centry
);
1300 /* In the salted case this isn't actually the nt_hash itself,
1301 but the MD5 of the salt + nt_hash. Let the caller
1302 sort this out. It can tell as we only return the cached_salt
1303 if we are returning a salted cred. */
1305 *cached_nt_pass
= (const uint8_t *)centry_hash16(centry
, mem_ctx
);
1306 if (*cached_nt_pass
== NULL
) {
1308 dom_sid_str_buf(sid
, &sidstr
);
1310 /* Bad (old) cred cache. Delete and pretend we
1312 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1314 wcache_delete("CRED/%s", sidstr
.buf
);
1315 centry_free(centry
);
1316 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1319 /* We only have 17 bytes more data in the salted cred case. */
1320 if (centry
->len
- centry
->ofs
== 17) {
1321 *cached_salt
= (const uint8_t *)centry_hash16(centry
, mem_ctx
);
1323 *cached_salt
= NULL
;
1326 dump_data_pw("cached_nt_pass", *cached_nt_pass
, NT_HASH_LEN
);
1328 dump_data_pw("cached_salt", *cached_salt
, NT_HASH_LEN
);
1331 status
= centry
->status
;
1333 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1334 dom_sid_str_buf(sid
, &sidstr
),
1335 nt_errstr(status
) ));
1337 centry_free(centry
);
1341 /* Store creds for a SID - only writes out new salted ones. */
1343 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1344 const struct dom_sid
*sid
,
1345 const uint8_t nt_pass
[NT_HASH_LEN
])
1347 struct cache_entry
*centry
;
1348 struct dom_sid_buf sid_str
;
1350 uint8_t cred_salt
[NT_HASH_LEN
];
1351 uint8_t salted_hash
[NT_HASH_LEN
];
1352 gnutls_hash_hd_t hash_hnd
= NULL
;
1355 if (is_null_sid(sid
)) {
1356 return NT_STATUS_INVALID_SID
;
1359 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1360 return NT_STATUS_INVALID_SID
;
1363 centry
= centry_start(domain
, NT_STATUS_OK
);
1365 return NT_STATUS_INTERNAL_DB_ERROR
;
1368 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1370 centry_put_time(centry
, time(NULL
));
1372 /* Create a salt and then salt the hash. */
1373 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1375 rc
= gnutls_hash_init(&hash_hnd
, GNUTLS_DIG_MD5
);
1377 centry_free(centry
);
1378 return gnutls_error_to_ntstatus(rc
, NT_STATUS_HASH_NOT_SUPPORTED
);
1381 rc
= gnutls_hash(hash_hnd
, cred_salt
, 16);
1383 gnutls_hash_deinit(hash_hnd
, NULL
);
1384 centry_free(centry
);
1385 return gnutls_error_to_ntstatus(rc
, NT_STATUS_HASH_NOT_SUPPORTED
);
1387 rc
= gnutls_hash(hash_hnd
, nt_pass
, 16);
1389 gnutls_hash_deinit(hash_hnd
, NULL
);
1390 centry_free(centry
);
1391 return gnutls_error_to_ntstatus(rc
, NT_STATUS_HASH_NOT_SUPPORTED
);
1393 gnutls_hash_deinit(hash_hnd
, salted_hash
);
1395 centry_put_hash16(centry
, salted_hash
);
1396 centry_put_hash16(centry
, cred_salt
);
1397 centry_end(centry
, "CRED/%s", dom_sid_str_buf(sid
, &sid_str
));
1399 DEBUG(10,("wcache_save_creds: %s\n", sid_str
.buf
));
1401 centry_free(centry
);
1403 return NT_STATUS_OK
;
1407 /* Query display info. This is the basic user list fn */
1408 NTSTATUS
wb_cache_query_user_list(struct winbindd_domain
*domain
,
1409 TALLOC_CTX
*mem_ctx
,
1412 struct winbind_cache
*cache
= get_cache(domain
);
1413 struct cache_entry
*centry
= NULL
;
1414 uint32_t num_rids
= 0;
1415 uint32_t *rids
= NULL
;
1417 unsigned int i
, retry
;
1418 bool old_status
= domain
->online
;
1425 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1430 num_rids
= centry_uint32(centry
);
1432 if (num_rids
== 0) {
1436 rids
= talloc_array(mem_ctx
, uint32_t, num_rids
);
1438 centry_free(centry
);
1439 return NT_STATUS_NO_MEMORY
;
1442 for (i
=0; i
<num_rids
; i
++) {
1443 rids
[i
] = centry_uint32(centry
);
1447 status
= centry
->status
;
1449 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1450 domain
->name
, nt_errstr(status
) ));
1452 centry_free(centry
);
1457 /* Put the query_user_list() in a retry loop. There appears to be
1458 * some bug either with Windows 2000 or Samba's handling of large
1459 * rpc replies. This manifests itself as sudden disconnection
1460 * at a random point in the enumeration of a large (60k) user list.
1461 * The retry loop simply tries the operation again. )-: It's not
1462 * pretty but an acceptable workaround until we work out what the
1463 * real problem is. */
1468 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1472 status
= domain
->backend
->query_user_list(domain
, mem_ctx
,
1474 num_rids
= talloc_array_length(rids
);
1476 if (!NT_STATUS_IS_OK(status
)) {
1477 DEBUG(3, ("query_user_list: returned 0x%08x, "
1478 "retrying\n", NT_STATUS_V(status
)));
1480 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1481 DEBUG(3, ("query_user_list: flushing "
1482 "connection cache\n"));
1483 invalidate_cm_connection(domain
);
1485 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1486 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1487 if (!domain
->internal
&& old_status
) {
1488 set_domain_offline(domain
);
1490 /* store partial response. */
1493 * humm, what about the status used for cache?
1494 * Should it be NT_STATUS_OK?
1499 * domain is offline now, and there is no user entries,
1500 * try to fetch from cache again.
1502 if (cache
->tdb
&& !domain
->online
&& !domain
->internal
&& old_status
) {
1503 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1504 /* partial response... */
1508 goto do_fetch_cache
;
1515 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1519 refresh_sequence_number(domain
);
1520 if (!NT_STATUS_IS_OK(status
)) {
1523 centry
= centry_start(domain
, status
);
1526 centry_put_uint32(centry
, num_rids
);
1527 for (i
=0; i
<num_rids
; i
++) {
1528 centry_put_uint32(centry
, rids
[i
]);
1530 centry_end(centry
, "UL/%s", domain
->name
);
1531 centry_free(centry
);
1539 /* list all domain groups */
1540 NTSTATUS
wb_cache_enum_dom_groups(struct winbindd_domain
*domain
,
1541 TALLOC_CTX
*mem_ctx
,
1542 uint32_t *num_entries
,
1543 struct wb_acct_info
**info
)
1545 struct winbind_cache
*cache
= get_cache(domain
);
1546 struct cache_entry
*centry
= NULL
;
1551 old_status
= domain
->online
;
1555 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1560 *num_entries
= centry_uint32(centry
);
1562 if (*num_entries
== 0)
1565 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1567 smb_panic_fn("enum_dom_groups out of memory");
1569 for (i
=0; i
<(*num_entries
); i
++) {
1570 (*info
)[i
].acct_name
= centry_string(centry
, (*info
));
1571 (*info
)[i
].acct_desc
= centry_string(centry
, (*info
));
1572 (*info
)[i
].rid
= centry_uint32(centry
);
1576 status
= centry
->status
;
1578 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1579 domain
->name
, nt_errstr(status
) ));
1581 centry_free(centry
);
1588 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1591 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1593 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1594 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1595 if (!domain
->internal
&& old_status
) {
1596 set_domain_offline(domain
);
1600 !domain
->internal
&&
1602 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1604 goto do_fetch_cache
;
1609 refresh_sequence_number(domain
);
1610 if (!NT_STATUS_IS_OK(status
)) {
1613 centry
= centry_start(domain
, status
);
1616 centry_put_uint32(centry
, *num_entries
);
1617 for (i
=0; i
<(*num_entries
); i
++) {
1618 centry_put_string(centry
, (*info
)[i
].acct_name
);
1619 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1620 centry_put_uint32(centry
, (*info
)[i
].rid
);
1622 centry_end(centry
, "GL/%s/domain", domain
->name
);
1623 centry_free(centry
);
1629 /* list all domain groups */
1630 NTSTATUS
wb_cache_enum_local_groups(struct winbindd_domain
*domain
,
1631 TALLOC_CTX
*mem_ctx
,
1632 uint32_t *num_entries
,
1633 struct wb_acct_info
**info
)
1635 struct winbind_cache
*cache
= get_cache(domain
);
1636 struct cache_entry
*centry
= NULL
;
1641 old_status
= domain
->online
;
1645 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1650 *num_entries
= centry_uint32(centry
);
1652 if (*num_entries
== 0)
1655 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1657 smb_panic_fn("enum_dom_groups out of memory");
1659 for (i
=0; i
<(*num_entries
); i
++) {
1660 (*info
)[i
].acct_name
= centry_string(centry
, (*info
));
1661 (*info
)[i
].acct_desc
= centry_string(centry
, (*info
));
1662 (*info
)[i
].rid
= centry_uint32(centry
);
1667 /* If we are returning cached data and the domain controller
1668 is down then we don't know whether the data is up to date
1669 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1672 if (wcache_server_down(domain
)) {
1673 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1674 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1676 status
= centry
->status
;
1678 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1679 domain
->name
, nt_errstr(status
) ));
1681 centry_free(centry
);
1688 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1691 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1693 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1694 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1695 if (!domain
->internal
&& old_status
) {
1696 set_domain_offline(domain
);
1699 !domain
->internal
&&
1702 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1704 goto do_fetch_cache
;
1709 refresh_sequence_number(domain
);
1710 if (!NT_STATUS_IS_OK(status
)) {
1713 centry
= centry_start(domain
, status
);
1716 centry_put_uint32(centry
, *num_entries
);
1717 for (i
=0; i
<(*num_entries
); i
++) {
1718 centry_put_string(centry
, (*info
)[i
].acct_name
);
1719 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1720 centry_put_uint32(centry
, (*info
)[i
].rid
);
1722 centry_end(centry
, "GL/%s/local", domain
->name
);
1723 centry_free(centry
);
1729 struct wcache_name_to_sid_state
{
1730 struct dom_sid
*sid
;
1731 enum lsa_SidType
*type
;
1736 static void wcache_name_to_sid_fn(const struct dom_sid
*sid
,
1737 enum lsa_SidType type
,
1741 struct wcache_name_to_sid_state
*state
= private_data
;
1744 *state
->type
= type
;
1745 state
->found
= (!expired
|| state
->offline
);
1748 static NTSTATUS
wcache_name_to_sid(struct winbindd_domain
*domain
,
1749 const char *domain_name
,
1751 struct dom_sid
*sid
,
1752 enum lsa_SidType
*type
)
1754 struct wcache_name_to_sid_state state
= {
1755 .sid
= sid
, .type
= type
, .found
= false,
1756 .offline
= is_domain_offline(domain
),
1760 ok
= namemap_cache_find_name(domain_name
, name
, wcache_name_to_sid_fn
,
1763 DBG_DEBUG("namemap_cache_find_name failed\n");
1764 return NT_STATUS_NOT_FOUND
;
1767 DBG_DEBUG("cache entry not found\n");
1768 return NT_STATUS_NOT_FOUND
;
1770 if (*type
== SID_NAME_UNKNOWN
) {
1771 return NT_STATUS_NONE_MAPPED
;
1774 return NT_STATUS_OK
;
1777 /* convert a single name to a sid in a domain */
1778 NTSTATUS
wb_cache_name_to_sid(struct winbindd_domain
*domain
,
1779 TALLOC_CTX
*mem_ctx
,
1780 const char *domain_name
,
1783 struct dom_sid
*sid
,
1784 enum lsa_SidType
*type
)
1788 const char *dom_name
;
1790 old_status
= domain
->online
;
1792 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1793 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1799 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1802 winbindd_domain_init_backend(domain
);
1803 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
,
1804 name
, flags
, &dom_name
, sid
, type
);
1806 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1807 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1808 if (!domain
->internal
&& old_status
) {
1809 set_domain_offline(domain
);
1811 if (!domain
->internal
&&
1814 NTSTATUS cache_status
;
1815 cache_status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1816 return cache_status
;
1821 if (domain
->online
&&
1822 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1823 enum lsa_SidType save_type
= *type
;
1825 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1826 save_type
= SID_NAME_UNKNOWN
;
1829 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
,
1832 /* Only save the reverse mapping if this was not a UPN */
1833 if (!strchr(name
, '@')) {
1834 if (!strupper_m(discard_const_p(char, domain_name
))) {
1835 return NT_STATUS_INVALID_PARAMETER
;
1837 (void)strlower_m(discard_const_p(char, name
));
1838 wcache_save_sid_to_name(domain
, status
, sid
,
1839 dom_name
, name
, save_type
);
1846 struct wcache_sid_to_name_state
{
1847 TALLOC_CTX
*mem_ctx
;
1850 enum lsa_SidType
*type
;
1855 static void wcache_sid_to_name_fn(const char *domain
,
1857 enum lsa_SidType type
,
1861 struct wcache_sid_to_name_state
*state
= private_data
;
1863 *state
->domain_name
= talloc_strdup(state
->mem_ctx
, domain
);
1864 if (*state
->domain_name
== NULL
) {
1867 *state
->name
= talloc_strdup(state
->mem_ctx
, name
);
1868 if (*state
->name
== NULL
) {
1871 *state
->type
= type
;
1872 state
->found
= (!expired
|| state
->offline
);
1875 static NTSTATUS
wcache_sid_to_name(struct winbindd_domain
*domain
,
1876 const struct dom_sid
*sid
,
1877 TALLOC_CTX
*mem_ctx
,
1880 enum lsa_SidType
*type
)
1882 struct wcache_sid_to_name_state state
= {
1883 .mem_ctx
= mem_ctx
, .found
= false,
1884 .domain_name
= domain_name
, .name
= name
, .type
= type
,
1885 .offline
= is_domain_offline(domain
)
1889 ok
= namemap_cache_find_sid(sid
, wcache_sid_to_name_fn
, &state
);
1891 DBG_DEBUG("namemap_cache_find_name failed\n");
1892 return NT_STATUS_NOT_FOUND
;
1895 DBG_DEBUG("cache entry not found\n");
1896 return NT_STATUS_NOT_FOUND
;
1898 if (*type
== SID_NAME_UNKNOWN
) {
1899 return NT_STATUS_NONE_MAPPED
;
1902 return NT_STATUS_OK
;
1905 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1907 NTSTATUS
wb_cache_sid_to_name(struct winbindd_domain
*domain
,
1908 TALLOC_CTX
*mem_ctx
,
1909 const struct dom_sid
*sid
,
1912 enum lsa_SidType
*type
)
1917 old_status
= domain
->online
;
1918 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
1920 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1925 *domain_name
= NULL
;
1927 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1930 winbindd_domain_init_backend(domain
);
1932 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1934 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1935 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1936 if (!domain
->internal
&& old_status
) {
1937 set_domain_offline(domain
);
1939 if (!domain
->internal
&&
1942 NTSTATUS cache_status
;
1943 cache_status
= wcache_sid_to_name(domain
, sid
, mem_ctx
,
1944 domain_name
, name
, type
);
1945 return cache_status
;
1949 if (!NT_STATUS_IS_OK(status
)) {
1952 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
1954 /* We can't save the name to sid mapping here, as with sid history a
1955 * later name2sid would give the wrong sid. */
1960 NTSTATUS
wb_cache_rids_to_names(struct winbindd_domain
*domain
,
1961 TALLOC_CTX
*mem_ctx
,
1962 const struct dom_sid
*domain_sid
,
1967 enum lsa_SidType
**types
)
1969 struct winbind_cache
*cache
= get_cache(domain
);
1971 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1976 old_status
= domain
->online
;
1977 *domain_name
= NULL
;
1985 if (num_rids
== 0) {
1986 return NT_STATUS_OK
;
1989 *names
= talloc_array(mem_ctx
, char *, num_rids
);
1990 *types
= talloc_array(mem_ctx
, enum lsa_SidType
, num_rids
);
1992 if ((*names
== NULL
) || (*types
== NULL
)) {
1993 result
= NT_STATUS_NO_MEMORY
;
1997 have_mapped
= have_unmapped
= false;
1999 for (i
=0; i
<num_rids
; i
++) {
2002 enum lsa_SidType type
;
2005 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2006 result
= NT_STATUS_INTERNAL_ERROR
;
2010 status
= wcache_sid_to_name(domain
, &sid
, *names
, &dom
,
2013 (*types
)[i
] = SID_NAME_UNKNOWN
;
2014 (*names
)[i
] = talloc_strdup(*names
, "");
2016 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2021 if (NT_STATUS_IS_OK(status
)) {
2025 if (*domain_name
== NULL
) {
2033 } else if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
2034 have_unmapped
= true;
2036 /* something's definitely wrong */
2043 return NT_STATUS_NONE_MAPPED
;
2045 if (!have_unmapped
) {
2046 return NT_STATUS_OK
;
2048 return STATUS_SOME_UNMAPPED
;
2052 TALLOC_FREE(*names
);
2053 TALLOC_FREE(*types
);
2055 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
2056 rids
, num_rids
, domain_name
,
2059 if (NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
2060 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2061 if (!domain
->internal
&& old_status
) {
2062 set_domain_offline(domain
);
2065 !domain
->internal
&&
2068 have_mapped
= have_unmapped
= false;
2070 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2071 if (*names
== NULL
) {
2072 result
= NT_STATUS_NO_MEMORY
;
2076 *types
= talloc_array(mem_ctx
, enum lsa_SidType
,
2078 if (*types
== NULL
) {
2079 result
= NT_STATUS_NO_MEMORY
;
2083 for (i
=0; i
<num_rids
; i
++) {
2086 enum lsa_SidType type
;
2089 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2090 result
= NT_STATUS_INTERNAL_ERROR
;
2094 status
= wcache_sid_to_name(domain
, &sid
,
2098 (*types
)[i
] = SID_NAME_UNKNOWN
;
2099 (*names
)[i
] = talloc_strdup(*names
, "");
2101 if (NT_STATUS_IS_OK(status
)) {
2105 if (*domain_name
== NULL
) {
2113 } else if (NT_STATUS_EQUAL(
2115 NT_STATUS_NONE_MAPPED
)) {
2116 have_unmapped
= true;
2118 /* something's definitely wrong */
2125 return NT_STATUS_NONE_MAPPED
;
2127 if (!have_unmapped
) {
2128 return NT_STATUS_OK
;
2130 return STATUS_SOME_UNMAPPED
;
2134 None of the queried rids has been found so save all negative entries
2136 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
2137 for (i
= 0; i
< num_rids
; i
++) {
2139 const char *name
= "";
2140 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
2141 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
2143 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2144 return NT_STATUS_INTERNAL_ERROR
;
2147 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2155 Some or all of the queried rids have been found.
2157 if (!NT_STATUS_IS_OK(result
) &&
2158 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
2162 refresh_sequence_number(domain
);
2164 for (i
=0; i
<num_rids
; i
++) {
2168 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2169 result
= NT_STATUS_INTERNAL_ERROR
;
2173 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
2174 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
2176 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2177 (*names
)[i
], (*types
)[i
]);
2183 TALLOC_FREE(*names
);
2184 TALLOC_FREE(*types
);
2188 static NTSTATUS
wcache_query_user(struct winbindd_domain
*domain
,
2189 TALLOC_CTX
*mem_ctx
,
2190 const struct dom_sid
*user_sid
,
2191 struct wbint_userinfo
*info
)
2193 struct winbind_cache
*cache
= get_cache(domain
);
2194 struct cache_entry
*centry
= NULL
;
2196 struct dom_sid_buf sid_string
;
2198 if (cache
->tdb
== NULL
) {
2199 return NT_STATUS_NOT_FOUND
;
2202 centry
= wcache_fetch(
2203 cache
, domain
, "U/%s", dom_sid_str_buf(user_sid
, &sid_string
));
2204 if (centry
== NULL
) {
2205 return NT_STATUS_NOT_FOUND
;
2208 /* if status is not ok then this is a negative hit
2209 and the rest of the data doesn't matter */
2210 status
= centry
->status
;
2211 if (NT_STATUS_IS_OK(status
)) {
2212 info
->domain_name
= centry_string(centry
, mem_ctx
);
2213 info
->acct_name
= centry_string(centry
, mem_ctx
);
2214 info
->full_name
= centry_string(centry
, mem_ctx
);
2215 info
->homedir
= centry_string(centry
, mem_ctx
);
2216 info
->shell
= centry_string(centry
, mem_ctx
);
2217 info
->uid
= centry_uint32(centry
);
2218 info
->primary_gid
= centry_uint32(centry
);
2219 info
->primary_group_name
= centry_string(centry
, mem_ctx
);
2220 centry_sid(centry
, &info
->user_sid
);
2221 centry_sid(centry
, &info
->group_sid
);
2224 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2225 "%s\n", domain
->name
, nt_errstr(status
) ));
2227 centry_free(centry
);
2233 * @brief Query a fullname from the username cache (for further gecos processing)
2235 * @param domain A pointer to the winbindd_domain struct.
2236 * @param mem_ctx The talloc context.
2237 * @param user_sid The user sid.
2238 * @param full_name A pointer to the full_name string.
2240 * @return NTSTATUS code
2242 NTSTATUS
wcache_query_user_fullname(struct winbindd_domain
*domain
,
2243 TALLOC_CTX
*mem_ctx
,
2244 const struct dom_sid
*user_sid
,
2245 const char **full_name
)
2248 struct wbint_userinfo info
;
2250 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, &info
);
2251 if (!NT_STATUS_IS_OK(status
)) {
2255 if (info
.full_name
!= NULL
) {
2256 *full_name
= talloc_strdup(mem_ctx
, info
.full_name
);
2257 if (*full_name
== NULL
) {
2258 return NT_STATUS_NO_MEMORY
;
2262 return NT_STATUS_OK
;
2265 static NTSTATUS
wcache_lookup_usergroups(struct winbindd_domain
*domain
,
2266 TALLOC_CTX
*mem_ctx
,
2267 const struct dom_sid
*user_sid
,
2268 uint32_t *pnum_sids
,
2269 struct dom_sid
**psids
)
2271 struct winbind_cache
*cache
= get_cache(domain
);
2272 struct cache_entry
*centry
= NULL
;
2274 uint32_t i
, num_sids
;
2275 struct dom_sid
*sids
;
2276 struct dom_sid_buf sid_string
;
2278 if (cache
->tdb
== NULL
) {
2279 return NT_STATUS_NOT_FOUND
;
2282 centry
= wcache_fetch(
2286 dom_sid_str_buf(user_sid
, &sid_string
));
2287 if (centry
== NULL
) {
2288 return NT_STATUS_NOT_FOUND
;
2291 num_sids
= centry_uint32(centry
);
2292 sids
= talloc_array(mem_ctx
, struct dom_sid
, num_sids
);
2294 centry_free(centry
);
2295 return NT_STATUS_NO_MEMORY
;
2298 for (i
=0; i
<num_sids
; i
++) {
2299 centry_sid(centry
, &sids
[i
]);
2302 status
= centry
->status
;
2304 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2305 "status: %s\n", domain
->name
, nt_errstr(status
)));
2307 centry_free(centry
);
2309 *pnum_sids
= num_sids
;
2314 /* Lookup groups a user is a member of. */
2315 NTSTATUS
wb_cache_lookup_usergroups(struct winbindd_domain
*domain
,
2316 TALLOC_CTX
*mem_ctx
,
2317 const struct dom_sid
*user_sid
,
2318 uint32_t *num_groups
,
2319 struct dom_sid
**user_gids
)
2321 struct cache_entry
*centry
= NULL
;
2324 struct dom_sid_buf sid_string
;
2327 old_status
= domain
->online
;
2328 status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2329 num_groups
, user_gids
);
2330 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2335 (*user_gids
) = NULL
;
2337 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2340 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
2342 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2343 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2344 if (!domain
->internal
&& old_status
) {
2345 set_domain_offline(domain
);
2347 if (!domain
->internal
&&
2350 NTSTATUS cache_status
;
2351 cache_status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2352 num_groups
, user_gids
);
2353 return cache_status
;
2356 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
2360 refresh_sequence_number(domain
);
2361 if (!NT_STATUS_IS_OK(status
)) {
2364 centry
= centry_start(domain
, status
);
2368 centry_put_uint32(centry
, *num_groups
);
2369 for (i
=0; i
<(*num_groups
); i
++) {
2370 centry_put_sid(centry
, &(*user_gids
)[i
]);
2373 centry_end(centry
, "UG/%s", dom_sid_str_buf(user_sid
, &sid_string
));
2374 centry_free(centry
);
2380 static char *wcache_make_sidlist(TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2381 const struct dom_sid
*sids
)
2386 sidlist
= talloc_strdup(mem_ctx
, "");
2387 if (sidlist
== NULL
) {
2390 for (i
=0; i
<num_sids
; i
++) {
2391 struct dom_sid_buf tmp
;
2392 sidlist
= talloc_asprintf_append_buffer(
2395 dom_sid_str_buf(&sids
[i
], &tmp
));
2396 if (sidlist
== NULL
) {
2403 static NTSTATUS
wcache_lookup_useraliases(struct winbindd_domain
*domain
,
2404 TALLOC_CTX
*mem_ctx
,
2406 const struct dom_sid
*sids
,
2407 uint32_t *pnum_aliases
,
2408 uint32_t **paliases
)
2410 struct winbind_cache
*cache
= get_cache(domain
);
2411 struct cache_entry
*centry
= NULL
;
2412 uint32_t i
, num_aliases
;
2417 if (cache
->tdb
== NULL
) {
2418 return NT_STATUS_NOT_FOUND
;
2421 if (num_sids
== 0) {
2424 return NT_STATUS_OK
;
2427 /* We need to cache indexed by the whole list of SIDs, the aliases
2428 * resulting might come from any of the SIDs. */
2430 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2431 if (sidlist
== NULL
) {
2432 return NT_STATUS_NO_MEMORY
;
2435 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2436 TALLOC_FREE(sidlist
);
2437 if (centry
== NULL
) {
2438 return NT_STATUS_NOT_FOUND
;
2441 num_aliases
= centry_uint32(centry
);
2442 aliases
= talloc_array(mem_ctx
, uint32_t, num_aliases
);
2443 if (aliases
== NULL
) {
2444 centry_free(centry
);
2445 return NT_STATUS_NO_MEMORY
;
2448 for (i
=0; i
<num_aliases
; i
++) {
2449 aliases
[i
] = centry_uint32(centry
);
2452 status
= centry
->status
;
2454 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2455 "status %s\n", domain
->name
, nt_errstr(status
)));
2457 centry_free(centry
);
2459 *pnum_aliases
= num_aliases
;
2460 *paliases
= aliases
;
2465 NTSTATUS
wb_cache_lookup_useraliases(struct winbindd_domain
*domain
,
2466 TALLOC_CTX
*mem_ctx
,
2468 const struct dom_sid
*sids
,
2469 uint32_t *num_aliases
,
2470 uint32_t **alias_rids
)
2472 struct cache_entry
*centry
= NULL
;
2478 old_status
= domain
->online
;
2479 status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
2480 num_aliases
, alias_rids
);
2481 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2486 (*alias_rids
) = NULL
;
2488 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2489 "for domain %s\n", domain
->name
));
2491 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2492 if (sidlist
== NULL
) {
2493 return NT_STATUS_NO_MEMORY
;
2496 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2498 num_aliases
, alias_rids
);
2500 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2501 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2502 if (!domain
->internal
&& old_status
) {
2503 set_domain_offline(domain
);
2505 if (!domain
->internal
&&
2508 NTSTATUS cache_status
;
2509 cache_status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
,
2510 sids
, num_aliases
, alias_rids
);
2511 return cache_status
;
2515 refresh_sequence_number(domain
);
2516 if (!NT_STATUS_IS_OK(status
)) {
2519 centry
= centry_start(domain
, status
);
2522 centry_put_uint32(centry
, *num_aliases
);
2523 for (i
=0; i
<(*num_aliases
); i
++)
2524 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2525 centry_end(centry
, "UA%s", sidlist
);
2526 centry_free(centry
);
2532 static NTSTATUS
wcache_lookup_groupmem(struct winbindd_domain
*domain
,
2533 TALLOC_CTX
*mem_ctx
,
2534 const struct dom_sid
*group_sid
,
2535 uint32_t *num_names
,
2536 struct dom_sid
**sid_mem
, char ***names
,
2537 uint32_t **name_types
)
2539 struct winbind_cache
*cache
= get_cache(domain
);
2540 struct cache_entry
*centry
= NULL
;
2543 struct dom_sid_buf sid_string
;
2545 if (cache
->tdb
== NULL
) {
2546 return NT_STATUS_NOT_FOUND
;
2549 centry
= wcache_fetch(
2553 dom_sid_str_buf(group_sid
, &sid_string
));
2554 if (centry
== NULL
) {
2555 return NT_STATUS_NOT_FOUND
;
2562 *num_names
= centry_uint32(centry
);
2563 if (*num_names
== 0) {
2564 centry_free(centry
);
2565 return NT_STATUS_OK
;
2568 *sid_mem
= talloc_array(mem_ctx
, struct dom_sid
, *num_names
);
2569 *names
= talloc_array(mem_ctx
, char *, *num_names
);
2570 *name_types
= talloc_array(mem_ctx
, uint32_t, *num_names
);
2572 if ((*sid_mem
== NULL
) || (*names
== NULL
) || (*name_types
== NULL
)) {
2573 TALLOC_FREE(*sid_mem
);
2574 TALLOC_FREE(*names
);
2575 TALLOC_FREE(*name_types
);
2576 centry_free(centry
);
2577 return NT_STATUS_NO_MEMORY
;
2580 for (i
=0; i
<(*num_names
); i
++) {
2581 centry_sid(centry
, &(*sid_mem
)[i
]);
2582 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2583 (*name_types
)[i
] = centry_uint32(centry
);
2586 status
= centry
->status
;
2588 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2589 "status: %s\n", domain
->name
, nt_errstr(status
)));
2591 centry_free(centry
);
2595 NTSTATUS
wb_cache_lookup_groupmem(struct winbindd_domain
*domain
,
2596 TALLOC_CTX
*mem_ctx
,
2597 const struct dom_sid
*group_sid
,
2598 enum lsa_SidType type
,
2599 uint32_t *num_names
,
2600 struct dom_sid
**sid_mem
,
2602 uint32_t **name_types
)
2604 struct cache_entry
*centry
= NULL
;
2607 struct dom_sid_buf sid_string
;
2610 old_status
= domain
->online
;
2611 status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2612 sid_mem
, names
, name_types
);
2613 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2620 (*name_types
) = NULL
;
2622 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2625 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
,
2627 sid_mem
, names
, name_types
);
2629 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2630 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2631 if (!domain
->internal
&& old_status
) {
2632 set_domain_offline(domain
);
2634 if (!domain
->internal
&&
2637 NTSTATUS cache_status
;
2638 cache_status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
,
2639 num_names
, sid_mem
, names
,
2641 return cache_status
;
2645 refresh_sequence_number(domain
);
2646 if (!NT_STATUS_IS_OK(status
)) {
2649 centry
= centry_start(domain
, status
);
2652 centry_put_uint32(centry
, *num_names
);
2653 for (i
=0; i
<(*num_names
); i
++) {
2654 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2655 centry_put_string(centry
, (*names
)[i
]);
2656 centry_put_uint32(centry
, (*name_types
)[i
]);
2660 dom_sid_str_buf(group_sid
, &sid_string
));
2661 centry_free(centry
);
2667 /* find the sequence number for a domain */
2668 NTSTATUS
wb_cache_sequence_number(struct winbindd_domain
*domain
,
2671 refresh_sequence_number(domain
);
2673 *seq
= domain
->sequence_number
;
2675 return NT_STATUS_OK
;
2678 /* enumerate trusted domains
2679 * (we need to have the list of trustdoms in the cache when we go offline) -
2681 NTSTATUS
wb_cache_trusted_domains(struct winbindd_domain
*domain
,
2682 TALLOC_CTX
*mem_ctx
,
2683 struct netr_DomainTrustList
*trusts
)
2686 struct winbind_cache
*cache
;
2687 struct winbindd_tdc_domain
*dom_list
= NULL
;
2688 size_t num_domains
= 0;
2689 bool retval
= false;
2693 old_status
= domain
->online
;
2695 trusts
->array
= NULL
;
2697 cache
= get_cache(domain
);
2698 if (!cache
|| !cache
->tdb
) {
2702 if (domain
->online
) {
2706 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2707 if (!retval
|| !num_domains
|| !dom_list
) {
2708 TALLOC_FREE(dom_list
);
2713 trusts
->array
= talloc_zero_array(mem_ctx
, struct netr_DomainTrust
, num_domains
);
2714 if (!trusts
->array
) {
2715 TALLOC_FREE(dom_list
);
2716 return NT_STATUS_NO_MEMORY
;
2719 for (i
= 0; i
< num_domains
; i
++) {
2720 struct netr_DomainTrust
*trust
;
2721 struct dom_sid
*sid
;
2722 struct winbindd_domain
*dom
;
2724 dom
= find_domain_from_name_noinit(dom_list
[i
].domain_name
);
2725 if (dom
&& dom
->internal
) {
2729 trust
= &trusts
->array
[trusts
->count
];
2730 trust
->netbios_name
= talloc_strdup(trusts
->array
, dom_list
[i
].domain_name
);
2731 trust
->dns_name
= talloc_strdup(trusts
->array
, dom_list
[i
].dns_name
);
2732 sid
= talloc(trusts
->array
, struct dom_sid
);
2733 if (!trust
->netbios_name
|| !trust
->dns_name
||
2735 TALLOC_FREE(dom_list
);
2736 TALLOC_FREE(trusts
->array
);
2737 return NT_STATUS_NO_MEMORY
;
2740 trust
->trust_flags
= dom_list
[i
].trust_flags
;
2741 trust
->trust_attributes
= dom_list
[i
].trust_attribs
;
2742 trust
->trust_type
= dom_list
[i
].trust_type
;
2743 sid_copy(sid
, &dom_list
[i
].sid
);
2748 TALLOC_FREE(dom_list
);
2749 return NT_STATUS_OK
;
2752 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2755 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, trusts
);
2757 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2758 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2759 if (!domain
->internal
&& old_status
) {
2760 set_domain_offline(domain
);
2762 if (!domain
->internal
&&
2765 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2766 if (retval
&& num_domains
&& dom_list
) {
2767 TALLOC_FREE(trusts
->array
);
2769 goto do_fetch_cache
;
2773 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2774 * so that the generic centry handling still applies correctly -
2777 if (!NT_STATUS_IS_ERR(status
)) {
2778 status
= NT_STATUS_OK
;
2783 /* get lockout policy */
2784 NTSTATUS
wb_cache_lockout_policy(struct winbindd_domain
*domain
,
2785 TALLOC_CTX
*mem_ctx
,
2786 struct samr_DomInfo12
*policy
)
2788 struct winbind_cache
*cache
= get_cache(domain
);
2789 struct cache_entry
*centry
= NULL
;
2793 old_status
= domain
->online
;
2797 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2803 policy
->lockout_duration
= centry_nttime(centry
);
2804 policy
->lockout_window
= centry_nttime(centry
);
2805 policy
->lockout_threshold
= centry_uint16(centry
);
2807 status
= centry
->status
;
2809 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2810 domain
->name
, nt_errstr(status
) ));
2812 centry_free(centry
);
2816 ZERO_STRUCTP(policy
);
2818 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2821 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2823 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2824 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2825 if (!domain
->internal
&& old_status
) {
2826 set_domain_offline(domain
);
2829 !domain
->internal
&&
2832 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2834 goto do_fetch_cache
;
2839 refresh_sequence_number(domain
);
2840 if (!NT_STATUS_IS_OK(status
)) {
2843 wcache_save_lockout_policy(domain
, status
, policy
);
2848 /* get password policy */
2849 NTSTATUS
wb_cache_password_policy(struct winbindd_domain
*domain
,
2850 TALLOC_CTX
*mem_ctx
,
2851 struct samr_DomInfo1
*policy
)
2853 struct winbind_cache
*cache
= get_cache(domain
);
2854 struct cache_entry
*centry
= NULL
;
2858 old_status
= domain
->online
;
2862 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2868 policy
->min_password_length
= centry_uint16(centry
);
2869 policy
->password_history_length
= centry_uint16(centry
);
2870 policy
->password_properties
= centry_uint32(centry
);
2871 policy
->max_password_age
= centry_nttime(centry
);
2872 policy
->min_password_age
= centry_nttime(centry
);
2874 status
= centry
->status
;
2876 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2877 domain
->name
, nt_errstr(status
) ));
2879 centry_free(centry
);
2883 ZERO_STRUCTP(policy
);
2885 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2888 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
2890 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2891 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2892 if (!domain
->internal
&& old_status
) {
2893 set_domain_offline(domain
);
2896 !domain
->internal
&&
2899 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2901 goto do_fetch_cache
;
2906 refresh_sequence_number(domain
);
2907 if (!NT_STATUS_IS_OK(status
)) {
2910 wcache_save_password_policy(domain
, status
, policy
);
2916 /* Invalidate cached user and group lists coherently */
2918 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2921 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
2922 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
2923 tdb_delete(the_tdb
, kbuf
);
2928 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2930 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
2931 const struct dom_sid
*sid
)
2934 struct dom_sid_buf sid_string
;
2935 struct winbind_cache
*cache
;
2937 /* don't clear cached U/SID and UG/SID entries when we want to logon
2940 if (lp_winbind_offline_logon()) {
2947 cache
= get_cache(domain
);
2953 /* Clear U/SID cache entry */
2954 fstr_sprintf(key_str
, "U/%s", dom_sid_str_buf(sid
, &sid_string
));
2955 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
2956 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
2958 /* Clear UG/SID cache entry */
2959 fstr_sprintf(key_str
, "UG/%s", dom_sid_str_buf(sid
, &sid_string
));
2960 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
2961 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
2963 /* Samba/winbindd never needs this. */
2964 netsamlogon_clear_cached_user(sid
);
2967 bool wcache_invalidate_cache(void)
2969 struct winbindd_domain
*domain
;
2971 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
2972 struct winbind_cache
*cache
= get_cache(domain
);
2974 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2975 "entries for %s\n", domain
->name
));
2978 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
2987 bool wcache_invalidate_cache_noinit(void)
2989 struct winbindd_domain
*domain
;
2991 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
2992 struct winbind_cache
*cache
;
2994 /* Skip uninitialized domains. */
2995 if (!domain
->initialized
&& !domain
->internal
) {
2999 cache
= get_cache(domain
);
3001 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3002 "entries for %s\n", domain
->name
));
3005 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3007 * Flushing cache has nothing to with domains.
3008 * return here if we successfully flushed once.
3009 * To avoid unnecessary traversing the cache.
3020 static bool init_wcache(void)
3024 if (wcache
== NULL
) {
3025 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
3026 ZERO_STRUCTP(wcache
);
3029 if (wcache
->tdb
!= NULL
)
3032 db_path
= wcache_path();
3033 if (db_path
== NULL
) {
3037 /* when working offline we must not clear the cache on restart */
3038 wcache
->tdb
= tdb_open_log(db_path
,
3039 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3040 TDB_INCOMPATIBLE_HASH
|
3041 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3042 O_RDWR
|O_CREAT
, 0600);
3043 TALLOC_FREE(db_path
);
3044 if (wcache
->tdb
== NULL
) {
3045 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3052 /************************************************************************
3053 This is called by the parent to initialize the cache file.
3054 We don't need sophisticated locking here as we know we're the
3056 ************************************************************************/
3058 bool initialize_winbindd_cache(void)
3060 bool cache_bad
= false;
3064 if (!init_wcache()) {
3065 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3069 /* Check version number. */
3070 ok
= tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
);
3072 DBG_DEBUG("Failed to get cache version\n");
3075 if (vers
!= WINBINDD_CACHE_VERSION
) {
3076 DBG_DEBUG("Invalid cache version %u != %u\n",
3078 WINBINDD_CACHE_VERSION
);
3085 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3086 "and re-creating with version number %d\n",
3087 WINBINDD_CACHE_VERSION
));
3089 tdb_close(wcache
->tdb
);
3092 db_path
= wcache_path();
3093 if (db_path
== NULL
) {
3097 if (unlink(db_path
) == -1) {
3098 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3101 TALLOC_FREE(db_path
);
3104 TALLOC_FREE(db_path
);
3105 if (!init_wcache()) {
3106 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3107 "init_wcache failed.\n"));
3111 /* Write the version. */
3112 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
3113 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3114 tdb_errorstr(wcache
->tdb
) ));
3119 tdb_close(wcache
->tdb
);
3124 void close_winbindd_cache(void)
3130 tdb_close(wcache
->tdb
);
3135 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*sid
,
3136 char **domain_name
, char **name
,
3137 enum lsa_SidType
*type
)
3139 struct winbindd_domain
*domain
;
3142 domain
= find_lookup_domain_from_sid(sid
);
3143 if (domain
== NULL
) {
3146 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
3148 return NT_STATUS_IS_OK(status
);
3151 bool lookup_cached_name(const char *namespace,
3152 const char *domain_name
,
3154 struct dom_sid
*sid
,
3155 enum lsa_SidType
*type
)
3157 struct winbindd_domain
*domain
;
3159 bool original_online_state
;
3161 domain
= find_lookup_domain_from_name(namespace);
3162 if (domain
== NULL
) {
3166 /* If we are doing a cached logon, temporarily set the domain
3167 offline so the cache won't expire the entry */
3169 original_online_state
= domain
->online
;
3170 domain
->online
= false;
3171 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
3172 domain
->online
= original_online_state
;
3174 return NT_STATUS_IS_OK(status
);
3178 * Cache a name to sid without checking the sequence number.
3179 * Used when caching from a trusted PAC.
3182 void cache_name2sid_trusted(struct winbindd_domain
*domain
,
3183 const char *domain_name
,
3185 enum lsa_SidType type
,
3186 const struct dom_sid
*sid
)
3189 * Ensure we store the mapping with the
3190 * existing sequence number from the cache.
3193 (void)fetch_cache_seqnum(domain
, time(NULL
));
3194 wcache_save_name_to_sid(domain
,
3202 void cache_name2sid(struct winbindd_domain
*domain
,
3203 const char *domain_name
, const char *name
,
3204 enum lsa_SidType type
, const struct dom_sid
*sid
)
3206 refresh_sequence_number(domain
);
3207 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
3212 * The original idea that this cache only contains centries has
3213 * been blurred - now other stuff gets put in here. Ensure we
3214 * ignore these things on cleanup.
3217 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
3218 TDB_DATA dbuf
, void *state
)
3220 struct cache_entry
*centry
;
3222 if (is_non_centry_key(kbuf
)) {
3226 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
3231 if (!NT_STATUS_IS_OK(centry
->status
)) {
3232 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
3233 tdb_delete(the_tdb
, kbuf
);
3236 centry_free(centry
);
3240 /* flush the cache */
3241 static void wcache_flush_cache(void)
3248 tdb_close(wcache
->tdb
);
3251 if (!winbindd_use_cache()) {
3255 db_path
= wcache_path();
3256 if (db_path
== NULL
) {
3260 /* when working offline we must not clear the cache on restart */
3261 wcache
->tdb
= tdb_open_log(db_path
,
3262 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3263 TDB_INCOMPATIBLE_HASH
|
3264 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3265 O_RDWR
|O_CREAT
, 0600);
3266 TALLOC_FREE(db_path
);
3268 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3272 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
3274 DEBUG(10,("wcache_flush_cache success\n"));
3277 /* Count cached creds */
3279 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3282 int *cred_count
= (int*)state
;
3284 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3290 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
3292 struct winbind_cache
*cache
= get_cache(domain
);
3297 return NT_STATUS_INTERNAL_DB_ERROR
;
3300 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
3302 return NT_STATUS_OK
;
3306 struct cred_list
*prev
, *next
;
3311 static struct cred_list
*wcache_cred_list
;
3313 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3316 struct cred_list
*cred
;
3318 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3320 cred
= SMB_MALLOC_P(struct cred_list
);
3322 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3328 /* save a copy of the key */
3330 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
3331 DLIST_ADD(wcache_cred_list
, cred
);
3337 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
3339 struct winbind_cache
*cache
= get_cache(domain
);
3342 struct cred_list
*cred
, *next
, *oldest
= NULL
;
3345 return NT_STATUS_INTERNAL_DB_ERROR
;
3348 /* we possibly already have an entry */
3349 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
3352 struct dom_sid_buf tmp
;
3354 DEBUG(11,("we already have an entry, deleting that\n"));
3356 fstr_sprintf(key_str
, "CRED/%s", dom_sid_str_buf(sid
, &tmp
));
3358 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3360 return NT_STATUS_OK
;
3363 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
3365 return NT_STATUS_OK
;
3366 } else if ((ret
< 0) || (wcache_cred_list
== NULL
)) {
3367 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3370 ZERO_STRUCTP(oldest
);
3372 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
3377 data
= tdb_fetch(cache
->tdb
, string_tdb_data(cred
->name
));
3379 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3381 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3385 t
= IVAL(data
.dptr
, 0);
3386 SAFE_FREE(data
.dptr
);
3389 oldest
= SMB_MALLOC_P(struct cred_list
);
3390 if (oldest
== NULL
) {
3391 status
= NT_STATUS_NO_MEMORY
;
3395 fstrcpy(oldest
->name
, cred
->name
);
3396 oldest
->created
= t
;
3400 if (t
< oldest
->created
) {
3401 fstrcpy(oldest
->name
, cred
->name
);
3402 oldest
->created
= t
;
3406 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3407 status
= NT_STATUS_OK
;
3409 status
= NT_STATUS_UNSUCCESSFUL
;
3412 for (cred
= wcache_cred_list
; cred
; cred
= next
) {
3414 DLIST_REMOVE(wcache_cred_list
, cred
);
3422 /* Change the global online/offline state. */
3423 bool set_global_winbindd_state_offline(void)
3426 uint8_t buf
[4] = {0};
3429 .dsize
= sizeof(buf
)
3433 DBG_ERR("Offline requested\n");
3435 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3436 DBG_ERR("Winbind cache doesn't exist yet\n");
3440 if (!lp_winbind_offline_logon()) {
3441 DBG_DEBUG("Rejecting request to set winbind offline, "
3442 "offline logons are disabled in smb.conf\n");
3446 ok
= get_global_winbindd_state_offline();
3451 PUSH_LE_U32(buf
, 0, time(NULL
));
3453 rc
= tdb_store_bystring(wcache
->tdb
,
3465 void set_global_winbindd_state_online(void)
3467 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3469 if (!lp_winbind_offline_logon()) {
3470 DBG_DEBUG("Rejecting request to set winbind online, "
3471 "offline logons are disabled in smb.conf.\n");
3479 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3480 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3483 bool get_global_winbindd_state_offline(void)
3487 data
= tdb_fetch_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3488 if (data
.dptr
== NULL
|| data
.dsize
!= 4) {
3489 DBG_DEBUG("Offline state not set.\n");
3490 SAFE_FREE(data
.dptr
);
3497 /***********************************************************************
3498 Validate functions for all possible cache tdb keys.
3499 ***********************************************************************/
3501 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3502 struct tdb_validation_status
*state
)
3504 struct cache_entry
*centry
;
3506 centry
= SMB_XMALLOC_P(struct cache_entry
);
3507 centry
->data
= (unsigned char *)smb_memdup(data
.dptr
, data
.dsize
);
3508 if (!centry
->data
) {
3512 centry
->len
= data
.dsize
;
3515 if (centry
->len
< 16) {
3516 /* huh? corrupt cache? */
3517 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3518 "(len < 16) ?\n", kstr
));
3519 centry_free(centry
);
3520 state
->bad_entry
= true;
3521 state
->success
= false;
3525 centry
->status
= NT_STATUS(centry_uint32(centry
));
3526 centry
->sequence_number
= centry_uint32(centry
);
3527 centry
->timeout
= centry_uint64_t(centry
);
3531 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3532 struct tdb_validation_status
*state
)
3534 if (dbuf
.dsize
!= 8) {
3535 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3536 keystr
, (unsigned int)dbuf
.dsize
));
3537 state
->bad_entry
= true;
3543 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3544 struct tdb_validation_status
*state
)
3546 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3553 (void)centry_string(centry
, mem_ctx
);
3554 (void)centry_string(centry
, mem_ctx
);
3555 (void)centry_string(centry
, mem_ctx
);
3556 (void)centry_string(centry
, mem_ctx
);
3557 (void)centry_string(centry
, mem_ctx
);
3558 (void)centry_uint32(centry
);
3559 (void)centry_uint32(centry
);
3560 (void)centry_string(centry
, mem_ctx
);
3561 (void)centry_sid(centry
, &sid
);
3562 (void)centry_sid(centry
, &sid
);
3564 centry_free(centry
);
3566 if (!(state
->success
)) {
3569 DEBUG(10,("validate_u: %s ok\n", keystr
));
3573 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3574 struct tdb_validation_status
*state
)
3576 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3582 (void)centry_nttime(centry
);
3583 (void)centry_nttime(centry
);
3584 (void)centry_uint16(centry
);
3586 centry_free(centry
);
3588 if (!(state
->success
)) {
3591 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3595 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3596 struct tdb_validation_status
*state
)
3598 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3604 (void)centry_uint16(centry
);
3605 (void)centry_uint16(centry
);
3606 (void)centry_uint32(centry
);
3607 (void)centry_nttime(centry
);
3608 (void)centry_nttime(centry
);
3610 centry_free(centry
);
3612 if (!(state
->success
)) {
3615 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3619 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3620 struct tdb_validation_status
*state
)
3622 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3628 (void)centry_time(centry
);
3629 (void)centry_hash16(centry
, mem_ctx
);
3631 /* We only have 17 bytes more data in the salted cred case. */
3632 if (centry
->len
- centry
->ofs
== 17) {
3633 (void)centry_hash16(centry
, mem_ctx
);
3636 centry_free(centry
);
3638 if (!(state
->success
)) {
3641 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3645 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3646 struct tdb_validation_status
*state
)
3648 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3649 int32_t num_entries
, i
;
3655 num_entries
= (int32_t)centry_uint32(centry
);
3657 for (i
=0; i
< num_entries
; i
++) {
3658 (void)centry_uint32(centry
);
3661 centry_free(centry
);
3663 if (!(state
->success
)) {
3666 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3670 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3671 struct tdb_validation_status
*state
)
3673 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3674 int32_t num_entries
, i
;
3680 num_entries
= centry_uint32(centry
);
3682 for (i
=0; i
< num_entries
; i
++) {
3683 (void)centry_string(centry
, mem_ctx
);
3684 (void)centry_string(centry
, mem_ctx
);
3685 (void)centry_uint32(centry
);
3688 centry_free(centry
);
3690 if (!(state
->success
)) {
3693 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3697 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3698 struct tdb_validation_status
*state
)
3700 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3701 int32_t num_groups
, i
;
3707 num_groups
= centry_uint32(centry
);
3709 for (i
=0; i
< num_groups
; i
++) {
3711 centry_sid(centry
, &sid
);
3714 centry_free(centry
);
3716 if (!(state
->success
)) {
3719 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3723 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3724 struct tdb_validation_status
*state
)
3726 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3727 int32_t num_aliases
, i
;
3733 num_aliases
= centry_uint32(centry
);
3735 for (i
=0; i
< num_aliases
; i
++) {
3736 (void)centry_uint32(centry
);
3739 centry_free(centry
);
3741 if (!(state
->success
)) {
3744 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3748 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3749 struct tdb_validation_status
*state
)
3751 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3752 int32_t num_names
, i
;
3758 num_names
= centry_uint32(centry
);
3760 for (i
=0; i
< num_names
; i
++) {
3762 centry_sid(centry
, &sid
);
3763 (void)centry_string(centry
, mem_ctx
);
3764 (void)centry_uint32(centry
);
3767 centry_free(centry
);
3769 if (!(state
->success
)) {
3772 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3776 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3777 struct tdb_validation_status
*state
)
3779 /* Can't say anything about this other than must be nonzero. */
3780 if (dbuf
.dsize
== 0) {
3781 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3783 state
->bad_entry
= true;
3784 state
->success
= false;
3788 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3792 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3793 struct tdb_validation_status
*state
)
3795 /* Can't say anything about this other than must be nonzero. */
3796 if (dbuf
.dsize
== 0) {
3797 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3799 state
->bad_entry
= true;
3800 state
->success
= false;
3804 DEBUG(10,("validate_de: %s ok\n", keystr
));
3808 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3810 struct tdb_validation_status
*state
)
3812 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3818 (void)centry_string( centry
, mem_ctx
);
3820 centry_free(centry
);
3822 if (!(state
->success
)) {
3825 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3829 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3831 struct tdb_validation_status
*state
)
3833 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3839 (void)centry_string( centry
, mem_ctx
);
3841 centry_free(centry
);
3843 if (!(state
->success
)) {
3846 DBG_DEBUG("%s ok\n", keystr
);
3850 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3852 struct tdb_validation_status
*state
)
3854 if (dbuf
.dsize
== 0) {
3855 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3856 "key %s (len ==0) ?\n", keystr
));
3857 state
->bad_entry
= true;
3858 state
->success
= false;
3862 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3863 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3867 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3868 struct tdb_validation_status
*state
)
3870 if (dbuf
.dsize
!= 4) {
3871 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3872 keystr
, (unsigned int)dbuf
.dsize
));
3873 state
->bad_entry
= true;
3874 state
->success
= false;
3877 DEBUG(10,("validate_offline: %s ok\n", keystr
));
3881 static int validate_ndr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3882 struct tdb_validation_status
*state
)
3885 * Ignore validation for now. The proper way to do this is with a
3886 * checksum. Just pure parsing does not really catch much.
3891 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3892 struct tdb_validation_status
*state
)
3894 if (dbuf
.dsize
!= 4) {
3895 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3896 "key %s (len %u != 4) ?\n",
3897 keystr
, (unsigned int)dbuf
.dsize
));
3898 state
->bad_entry
= true;
3899 state
->success
= false;
3903 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
3907 /***********************************************************************
3908 A list of all possible cache tdb keys with associated validation
3910 ***********************************************************************/
3912 struct key_val_struct
{
3913 const char *keyname
;
3914 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
3916 {"SEQNUM/", validate_seqnum
},
3918 {"LOC_POL/", validate_loc_pol
},
3919 {"PWD_POL/", validate_pwd_pol
},
3920 {"CRED/", validate_cred
},
3921 {"UL/", validate_ul
},
3922 {"GL/", validate_gl
},
3923 {"UG/", validate_ug
},
3924 {"UA", validate_ua
},
3925 {"GM/", validate_gm
},
3926 {"DR/", validate_dr
},
3927 {"DE/", validate_de
},
3928 {"TRUSTDOMCACHE/", validate_trustdomcache
},
3929 {"NSS/NA/", validate_nss_na
},
3930 {"NSS/AN/", validate_nss_an
},
3931 {"WINBINDD_OFFLINE", validate_offline
},
3932 {"NDR/", validate_ndr
},
3933 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
3937 /***********************************************************************
3938 Function to look at every entry in the tdb and validate it as far as
3940 ***********************************************************************/
3942 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
3945 unsigned int max_key_len
= 1024;
3946 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
3948 /* Paranoia check. */
3949 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0 ||
3950 strncmp("NDR/", (const char *)kbuf
.dptr
, 4) == 0) {
3951 max_key_len
= 1024 * 1024;
3953 if (kbuf
.dsize
> max_key_len
) {
3954 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
3956 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
3960 for (i
= 0; key_val
[i
].keyname
; i
++) {
3961 size_t namelen
= strlen(key_val
[i
].keyname
);
3962 if (kbuf
.dsize
>= namelen
&& (
3963 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
3964 TALLOC_CTX
*mem_ctx
;
3968 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
3972 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
3973 keystr
[kbuf
.dsize
] = '\0';
3975 mem_ctx
= talloc_init("validate_ctx");
3981 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
3985 talloc_destroy(mem_ctx
);
3990 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
3991 dump_data(0, (uint8_t *)kbuf
.dptr
, kbuf
.dsize
);
3992 DEBUG(0,("data :\n"));
3993 dump_data(0, (uint8_t *)dbuf
.dptr
, dbuf
.dsize
);
3994 v_state
->unknown_key
= true;
3995 v_state
->success
= false;
3996 return 1; /* terminate. */
3999 static void validate_panic(const char *const why
)
4001 DEBUG(0,("validating cache: would panic %s\n", why
));
4002 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4006 static int wbcache_update_centry_fn(TDB_CONTEXT
*tdb
,
4014 if (is_non_centry_key(key
)) {
4018 if (data
.dptr
== NULL
|| data
.dsize
== 0) {
4019 if (tdb_delete(tdb
, key
) < 0) {
4020 DEBUG(0, ("tdb_delete for [%s] failed!\n",
4026 /* add timeout to blob (uint64_t) */
4027 blob
.dsize
= data
.dsize
+ 8;
4029 blob
.dptr
= SMB_XMALLOC_ARRAY(uint8_t, blob
.dsize
);
4030 if (blob
.dptr
== NULL
) {
4033 memset(blob
.dptr
, 0, blob
.dsize
);
4035 /* copy status and seqnum */
4036 memcpy(blob
.dptr
, data
.dptr
, 8);
4039 ctimeout
= lp_winbind_cache_time() + time(NULL
);
4040 SBVAL(blob
.dptr
, 8, ctimeout
);
4043 memcpy(blob
.dptr
+ 16, data
.dptr
+ 8, data
.dsize
- 8);
4045 if (tdb_store(tdb
, key
, blob
, TDB_REPLACE
) < 0) {
4046 DEBUG(0, ("tdb_store to update [%s] failed!\n",
4048 SAFE_FREE(blob
.dptr
);
4052 SAFE_FREE(blob
.dptr
);
4056 static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT
*tdb
)
4060 DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
4062 rc
= tdb_traverse(tdb
, wbcache_update_centry_fn
, NULL
);
4070 /***********************************************************************
4071 Try and validate every entry in the winbindd cache. If we fail here,
4072 delete the cache tdb and return non-zero.
4073 ***********************************************************************/
4075 int winbindd_validate_cache(void)
4078 char *tdb_path
= NULL
;
4079 TDB_CONTEXT
*tdb
= NULL
;
4083 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4084 smb_panic_fn
= validate_panic
;
4086 tdb_path
= wcache_path();
4087 if (tdb_path
== NULL
) {
4091 tdb
= tdb_open_log(tdb_path
,
4092 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
4093 TDB_INCOMPATIBLE_HASH
|
4094 ( lp_winbind_offline_logon()
4096 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
4100 DEBUG(0, ("winbindd_validate_cache: "
4101 "error opening/initializing tdb\n"));
4105 /* Version check and upgrade code. */
4106 if (!tdb_fetch_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers_id
)) {
4107 DEBUG(10, ("Fresh database\n"));
4108 tdb_store_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
);
4109 vers_id
= WINBINDD_CACHE_VERSION
;
4112 if (vers_id
!= WINBINDD_CACHE_VERSION
) {
4113 if (vers_id
== WINBINDD_CACHE_VER1
) {
4114 ok
= wbcache_upgrade_v1_to_v2(tdb
);
4116 DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
4121 tdb_store_uint32(tdb
,
4122 WINBINDD_CACHE_VERSION_KEYSTR
,
4123 WINBINDD_CACHE_VERSION
);
4124 vers_id
= WINBINDD_CACHE_VER2
;
4130 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
4133 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4134 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
4139 TALLOC_FREE(tdb_path
);
4140 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4141 smb_panic_fn
= smb_panic
;
4145 /***********************************************************************
4146 Try and validate every entry in the winbindd cache.
4147 ***********************************************************************/
4149 int winbindd_validate_cache_nobackup(void)
4154 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4155 smb_panic_fn
= validate_panic
;
4157 tdb_path
= wcache_path();
4158 if (tdb_path
== NULL
) {
4159 goto err_panic_restore
;
4162 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
4163 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
4165 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
4169 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4173 TALLOC_FREE(tdb_path
);
4175 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4177 smb_panic_fn
= smb_panic
;
4181 bool winbindd_cache_validate_and_initialize(void)
4183 close_winbindd_cache();
4185 if (lp_winbind_offline_logon()) {
4186 if (winbindd_validate_cache() < 0) {
4187 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4188 "could be restored.\n"));
4192 return initialize_winbindd_cache();
4195 /*********************************************************************
4196 ********************************************************************/
4198 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
4199 struct winbindd_tdc_domain
**domains
,
4200 size_t *num_domains
)
4202 struct winbindd_tdc_domain
*list
= NULL
;
4204 bool set_only
= false;
4206 /* don't allow duplicates */
4211 for ( i
=0; i
< (*num_domains
); i
++ ) {
4212 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
4213 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4224 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, 1 );
4227 list
= talloc_realloc( *domains
, *domains
,
4228 struct winbindd_tdc_domain
,
4233 ZERO_STRUCT( list
[idx
] );
4239 list
[idx
].domain_name
= talloc_strdup(list
, new_dom
->name
);
4240 if (list
[idx
].domain_name
== NULL
) {
4243 if (new_dom
->alt_name
!= NULL
) {
4244 list
[idx
].dns_name
= talloc_strdup(list
, new_dom
->alt_name
);
4245 if (list
[idx
].dns_name
== NULL
) {
4250 if ( !is_null_sid( &new_dom
->sid
) ) {
4251 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
4253 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
4256 if ( new_dom
->domain_flags
!= 0x0 )
4257 list
[idx
].trust_flags
= new_dom
->domain_flags
;
4259 if ( new_dom
->domain_type
!= 0x0 )
4260 list
[idx
].trust_type
= new_dom
->domain_type
;
4262 if ( new_dom
->domain_trust_attribs
!= 0x0 )
4263 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
4267 *num_domains
= idx
+ 1;
4273 /*********************************************************************
4274 ********************************************************************/
4276 static TDB_DATA
make_tdc_key( const char *domain_name
)
4278 char *keystr
= NULL
;
4279 TDB_DATA key
= { NULL
, 0 };
4281 if ( !domain_name
) {
4282 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4286 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
4289 key
= string_term_tdb_data(keystr
);
4294 /*********************************************************************
4295 ********************************************************************/
4297 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
4299 unsigned char **buf
)
4301 unsigned char *buffer
= NULL
;
4306 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4314 /* Store the number of array items first */
4315 len
+= tdb_pack( buffer
? buffer
+len
: NULL
,
4316 buffer
? buflen
-len
: 0, "d",
4319 /* now pack each domain trust record */
4320 for ( i
=0; i
<num_domains
; i
++ ) {
4322 struct dom_sid_buf tmp
;
4325 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4326 domains
[i
].domain_name
,
4327 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
4330 len
+= tdb_pack( buffer
? buffer
+len
: NULL
,
4331 buffer
? buflen
-len
: 0, "fffddd",
4332 domains
[i
].domain_name
,
4333 domains
[i
].dns_name
? domains
[i
].dns_name
: "",
4334 dom_sid_str_buf(&domains
[i
].sid
, &tmp
),
4335 domains
[i
].trust_flags
,
4336 domains
[i
].trust_attribs
,
4337 domains
[i
].trust_type
);
4340 if ( buflen
< len
) {
4342 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
4343 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4357 /*********************************************************************
4358 ********************************************************************/
4360 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
4361 struct winbindd_tdc_domain
**domains
)
4363 fstring domain_name
, dns_name
, sid_string
;
4364 uint32_t type
, attribs
, flags
;
4368 struct winbindd_tdc_domain
*list
= NULL
;
4370 /* get the number of domains */
4371 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
4373 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4377 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, num_domains
);
4379 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4383 for ( i
=0; i
<num_domains
; i
++ ) {
4386 this_len
= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
4394 if ( this_len
== -1 ) {
4395 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4396 TALLOC_FREE( list
);
4401 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4402 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4403 domain_name
, dns_name
, sid_string
,
4404 flags
, attribs
, type
));
4406 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
4407 list
[i
].dns_name
= NULL
;
4408 if (dns_name
[0] != '\0') {
4409 list
[i
].dns_name
= talloc_strdup(list
, dns_name
);
4411 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
4412 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4415 list
[i
].trust_flags
= flags
;
4416 list
[i
].trust_attribs
= attribs
;
4417 list
[i
].trust_type
= type
;
4425 /*********************************************************************
4426 ********************************************************************/
4428 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
4430 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4431 TDB_DATA data
= { NULL
, 0 };
4437 /* See if we were asked to delete the cache entry */
4440 ret
= tdb_delete( wcache
->tdb
, key
);
4444 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4451 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4454 SAFE_FREE( data
.dptr
);
4455 SAFE_FREE( key
.dptr
);
4457 return ( ret
== 0 );
4460 /*********************************************************************
4461 ********************************************************************/
4463 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4465 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4466 TDB_DATA data
= { NULL
, 0 };
4474 data
= tdb_fetch( wcache
->tdb
, key
);
4476 SAFE_FREE( key
.dptr
);
4481 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4483 SAFE_FREE( data
.dptr
);
4491 /*********************************************************************
4492 ********************************************************************/
4494 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4496 struct winbindd_tdc_domain
*dom_list
= NULL
;
4497 size_t num_domains
= 0;
4499 struct dom_sid_buf buf
;
4501 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4502 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4503 domain
->name
, domain
->alt_name
,
4504 dom_sid_str_buf(&domain
->sid
, &buf
),
4505 domain
->domain_flags
,
4506 domain
->domain_trust_attribs
,
4507 domain
->domain_type
));
4509 if ( !init_wcache() ) {
4513 /* fetch the list */
4515 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4517 /* add the new domain */
4519 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4523 /* pack the domain */
4525 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4533 TALLOC_FREE( dom_list
);
4538 static struct winbindd_tdc_domain
*wcache_tdc_dup_domain(
4539 TALLOC_CTX
*mem_ctx
, const struct winbindd_tdc_domain
*src
)
4541 struct winbindd_tdc_domain
*dst
;
4543 dst
= talloc(mem_ctx
, struct winbindd_tdc_domain
);
4547 dst
->domain_name
= talloc_strdup(dst
, src
->domain_name
);
4548 if (dst
->domain_name
== NULL
) {
4552 dst
->dns_name
= NULL
;
4553 if (src
->dns_name
!= NULL
) {
4554 dst
->dns_name
= talloc_strdup(dst
, src
->dns_name
);
4555 if (dst
->dns_name
== NULL
) {
4560 sid_copy(&dst
->sid
, &src
->sid
);
4561 dst
->trust_flags
= src
->trust_flags
;
4562 dst
->trust_type
= src
->trust_type
;
4563 dst
->trust_attribs
= src
->trust_attribs
;
4570 /*********************************************************************
4571 ********************************************************************/
4573 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4575 struct winbindd_tdc_domain
*dom_list
= NULL
;
4576 size_t num_domains
= 0;
4578 struct winbindd_tdc_domain
*d
= NULL
;
4580 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4582 if ( !init_wcache() ) {
4586 /* fetch the list */
4588 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4590 for ( i
=0; i
<num_domains
; i
++ ) {
4591 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4592 strequal(name
, dom_list
[i
].dns_name
) )
4594 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4597 d
= wcache_tdc_dup_domain(ctx
, &dom_list
[i
]);
4602 TALLOC_FREE( dom_list
);
4607 /*********************************************************************
4608 ********************************************************************/
4610 void wcache_tdc_clear( void )
4612 if ( !init_wcache() )
4615 wcache_tdc_store_list( NULL
, 0 );
4620 static bool wcache_ndr_key(TALLOC_CTX
*mem_ctx
, const char *domain_name
,
4621 uint32_t opnum
, const DATA_BLOB
*req
,
4627 key
= talloc_asprintf(mem_ctx
, "NDR/%s/%d/", domain_name
, (int)opnum
);
4631 keylen
= talloc_get_size(key
) - 1;
4633 key
= talloc_realloc(mem_ctx
, key
, char, keylen
+ req
->length
);
4637 memcpy(key
+ keylen
, req
->data
, req
->length
);
4639 pkey
->dptr
= (uint8_t *)key
;
4640 pkey
->dsize
= talloc_get_size(key
);
4644 static bool wcache_opnum_cacheable(uint32_t opnum
)
4647 case NDR_WBINT_PING
:
4648 case NDR_WBINT_QUERYSEQUENCENUMBER
:
4649 case NDR_WBINT_ALLOCATEUID
:
4650 case NDR_WBINT_ALLOCATEGID
:
4651 case NDR_WBINT_CHECKMACHINEACCOUNT
:
4652 case NDR_WBINT_CHANGEMACHINEACCOUNT
:
4653 case NDR_WBINT_PINGDC
:
4659 bool wcache_fetch_ndr(TALLOC_CTX
*mem_ctx
, struct winbindd_domain
*domain
,
4660 uint32_t opnum
, const DATA_BLOB
*req
, DATA_BLOB
*resp
)
4665 if (!wcache_opnum_cacheable(opnum
) ||
4666 is_my_own_sam_domain(domain
) ||
4667 is_builtin_domain(domain
)) {
4671 if (wcache
->tdb
== NULL
) {
4675 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4678 data
= tdb_fetch(wcache
->tdb
, key
);
4679 TALLOC_FREE(key
.dptr
);
4681 if (data
.dptr
== NULL
) {
4684 if (data
.dsize
< 12) {
4688 if (is_domain_online(domain
)) {
4689 uint32_t entry_seqnum
, dom_seqnum
, last_check
;
4690 uint64_t entry_timeout
;
4692 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
,
4696 entry_seqnum
= IVAL(data
.dptr
, 0);
4697 if (entry_seqnum
!= dom_seqnum
) {
4698 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4699 (int)entry_seqnum
));
4702 entry_timeout
= BVAL(data
.dptr
, 4);
4703 if (time(NULL
) > (time_t)entry_timeout
) {
4704 DEBUG(10, ("Entry has timed out\n"));
4709 resp
->data
= (uint8_t *)talloc_memdup(mem_ctx
, data
.dptr
+ 12,
4711 if (resp
->data
== NULL
) {
4712 DEBUG(10, ("talloc failed\n"));
4715 resp
->length
= data
.dsize
- 12;
4719 SAFE_FREE(data
.dptr
);
4723 void wcache_store_ndr(struct winbindd_domain
*domain
, uint32_t opnum
,
4724 const DATA_BLOB
*req
, const DATA_BLOB
*resp
)
4727 uint32_t dom_seqnum
, last_check
;
4730 if (!wcache_opnum_cacheable(opnum
) ||
4731 is_my_own_sam_domain(domain
) ||
4732 is_builtin_domain(domain
)) {
4736 if (wcache
->tdb
== NULL
) {
4740 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
, &last_check
)) {
4741 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4746 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4750 timeout
= time(NULL
) + lp_winbind_cache_time();
4752 data
.dsize
= resp
->length
+ 12;
4753 data
.dptr
= talloc_array(key
.dptr
, uint8_t, data
.dsize
);
4754 if (data
.dptr
== NULL
) {
4758 SIVAL(data
.dptr
, 0, dom_seqnum
);
4759 SBVAL(data
.dptr
, 4, timeout
);
4760 memcpy(data
.dptr
+ 12, resp
->data
, resp
->length
);
4762 tdb_store(wcache
->tdb
, key
, data
, 0);
4765 TALLOC_FREE(key
.dptr
);