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"
39 #define DBGC_CLASS DBGC_WINBIND
41 #define WINBINDD_CACHE_VER1 1 /* initial db version */
42 #define WINBINDD_CACHE_VER2 2 /* second version with timeouts for NDR entries */
44 #define WINBINDD_CACHE_VERSION WINBINDD_CACHE_VER2
45 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
47 extern struct winbindd_methods reconnect_methods
;
49 extern struct winbindd_methods reconnect_ads_methods
;
51 extern struct winbindd_methods builtin_passdb_methods
;
52 extern struct winbindd_methods sam_passdb_methods
;
55 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
56 * Here are the list of entry types that are *not* stored
57 * as form struct cache_entry in the cache.
60 static const char *non_centry_keys
[] = {
63 WINBINDD_CACHE_VERSION_KEYSTR
,
67 /************************************************************************
68 Is this key a non-centry type ?
69 ************************************************************************/
71 static bool is_non_centry_key(TDB_DATA kbuf
)
75 if (kbuf
.dptr
== NULL
|| kbuf
.dsize
== 0) {
78 for (i
= 0; non_centry_keys
[i
] != NULL
; i
++) {
79 size_t namelen
= strlen(non_centry_keys
[i
]);
80 if (kbuf
.dsize
< namelen
) {
83 if (strncmp(non_centry_keys
[i
], (const char *)kbuf
.dptr
, namelen
) == 0) {
90 /* Global online/offline state - False when online. winbindd starts up online
91 and sets this to true if the first query fails and there's an entry in
92 the cache tdb telling us to stay offline. */
94 static bool global_winbindd_offline_state
;
96 struct winbind_cache
{
102 uint32_t sequence_number
;
108 void (*smb_panic_fn
)(const char *const why
) = smb_panic
;
110 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
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("winbindd_cache.tdb");
123 /* get the winbind_cache structure */
124 static struct winbind_cache
*get_cache(struct winbindd_domain
*domain
)
126 struct winbind_cache
*ret
= wcache
;
128 /* We have to know what type of domain we are dealing with first. */
130 if (domain
->internal
) {
131 domain
->backend
= &builtin_passdb_methods
;
134 if (dom_sid_equal(&domain
->sid
, &global_sid_Builtin
)) {
135 domain
->initialized
= true;
138 if (strequal(domain
->name
, get_global_sam_name()) &&
139 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 OK. Listen up because I'm only going to say this once.
150 We have the following scenarios to consider
151 (a) trusted AD domains on a Samba DC,
152 (b) trusted AD domains and we are joined to a non-kerberos domain
153 (c) trusted AD domains and we are joined to a kerberos (AD) domain
155 For (a) we can always contact the trusted domain using krb5
156 since we have the domain trust account password
158 For (b) we can only use RPC since we have no way of
159 getting a krb5 ticket in our own domain
161 For (c) we can always use krb5 since we have a kerberos trust
166 if (!domain
->backend
) {
168 struct winbindd_domain
*our_domain
= domain
;
170 /* find our domain first so we can figure out if we
171 are joined to a kerberized domain */
173 if ( !domain
->primary
)
174 our_domain
= find_our_domain();
176 if ((our_domain
->active_directory
|| IS_DC
)
177 && domain
->active_directory
178 && !lp_winbind_rpc_only()) {
179 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain
->name
));
180 domain
->backend
= &reconnect_ads_methods
;
182 #endif /* HAVE_ADS */
183 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain
->name
));
184 domain
->backend
= &reconnect_methods
;
187 #endif /* HAVE_ADS */
193 ret
= SMB_XMALLOC_P(struct winbind_cache
);
197 wcache_flush_cache();
203 free a centry structure
205 static void centry_free(struct cache_entry
*centry
)
209 SAFE_FREE(centry
->data
);
213 static bool centry_check_bytes(struct cache_entry
*centry
, size_t nbytes
)
215 if (centry
->len
- centry
->ofs
< nbytes
) {
216 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
217 (unsigned int)nbytes
,
218 centry
->len
- centry
->ofs
));
225 pull a uint64_t from a cache entry
227 static uint64_t centry_uint64_t(struct cache_entry
*centry
)
231 if (!centry_check_bytes(centry
, 8)) {
232 smb_panic_fn("centry_uint64_t");
234 ret
= BVAL(centry
->data
, centry
->ofs
);
240 pull a uint32_t from a cache entry
242 static uint32_t centry_uint32(struct cache_entry
*centry
)
246 if (!centry_check_bytes(centry
, 4)) {
247 smb_panic_fn("centry_uint32");
249 ret
= IVAL(centry
->data
, centry
->ofs
);
255 pull a uint16_t from a cache entry
257 static uint16_t centry_uint16(struct cache_entry
*centry
)
260 if (!centry_check_bytes(centry
, 2)) {
261 smb_panic_fn("centry_uint16");
263 ret
= SVAL(centry
->data
, centry
->ofs
);
269 pull a uint8_t from a cache entry
271 static uint8_t centry_uint8(struct cache_entry
*centry
)
274 if (!centry_check_bytes(centry
, 1)) {
275 smb_panic_fn("centry_uint8");
277 ret
= CVAL(centry
->data
, centry
->ofs
);
283 pull a NTTIME from a cache entry
285 static NTTIME
centry_nttime(struct cache_entry
*centry
)
288 if (!centry_check_bytes(centry
, 8)) {
289 smb_panic_fn("centry_nttime");
291 ret
= IVAL(centry
->data
, centry
->ofs
);
293 ret
+= (uint64_t)IVAL(centry
->data
, centry
->ofs
) << 32;
299 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
301 static time_t centry_time(struct cache_entry
*centry
)
303 return (time_t)centry_nttime(centry
);
306 /* pull a string from a cache entry, using the supplied
309 static char *centry_string(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
314 len
= centry_uint8(centry
);
317 /* a deliberate NULL string */
321 if (!centry_check_bytes(centry
, (size_t)len
)) {
322 smb_panic_fn("centry_string");
325 ret
= talloc_array(mem_ctx
, char, len
+1);
327 smb_panic_fn("centry_string out of memory\n");
329 memcpy(ret
,centry
->data
+ centry
->ofs
, len
);
335 /* pull a hash16 from a cache entry, using the supplied
338 static char *centry_hash16(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
343 len
= centry_uint8(centry
);
346 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
351 if (!centry_check_bytes(centry
, 16)) {
355 ret
= talloc_array(mem_ctx
, char, 16);
357 smb_panic_fn("centry_hash out of memory\n");
359 memcpy(ret
,centry
->data
+ centry
->ofs
, 16);
364 /* pull a sid from a cache entry, using the supplied
367 static bool centry_sid(struct cache_entry
*centry
, struct dom_sid
*sid
)
372 sid_string
= centry_string(centry
, talloc_tos());
373 if (sid_string
== NULL
) {
376 ret
= string_to_sid(sid
, sid_string
);
377 TALLOC_FREE(sid_string
);
383 pull a NTSTATUS from a cache entry
385 static NTSTATUS
centry_ntstatus(struct cache_entry
*centry
)
389 status
= NT_STATUS(centry_uint32(centry
));
394 /* the server is considered down if it can't give us a sequence number */
395 static bool wcache_server_down(struct winbindd_domain
*domain
)
402 ret
= (domain
->sequence_number
== DOM_SEQUENCE_NONE
);
405 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
410 struct wcache_seqnum_state
{
412 uint32_t *last_seq_check
;
415 static int wcache_seqnum_parser(TDB_DATA key
, TDB_DATA data
,
418 struct wcache_seqnum_state
*state
= private_data
;
420 if (data
.dsize
!= 8) {
421 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
426 *state
->seqnum
= IVAL(data
.dptr
, 0);
427 *state
->last_seq_check
= IVAL(data
.dptr
, 4);
431 static bool wcache_fetch_seqnum(const char *domain_name
, uint32_t *seqnum
,
432 uint32_t *last_seq_check
)
434 struct wcache_seqnum_state state
= {
435 .seqnum
= seqnum
, .last_seq_check
= last_seq_check
437 size_t len
= strlen(domain_name
);
439 TDB_DATA key
= { .dptr
= (uint8_t *)keystr
, .dsize
= sizeof(keystr
) };
442 if (wcache
->tdb
== NULL
) {
443 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
447 snprintf(keystr
, sizeof(keystr
), "SEQNUM/%s", domain_name
);
449 ret
= tdb_parse_record(wcache
->tdb
, key
, wcache_seqnum_parser
,
454 static NTSTATUS
fetch_cache_seqnum( struct winbindd_domain
*domain
, time_t now
)
456 uint32_t last_check
, time_diff
;
458 if (!wcache_fetch_seqnum(domain
->name
, &domain
->sequence_number
,
460 return NT_STATUS_UNSUCCESSFUL
;
462 domain
->last_seq_check
= last_check
;
464 /* have we expired? */
466 time_diff
= now
- domain
->last_seq_check
;
467 if ( time_diff
> lp_winbind_cache_time() ) {
468 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
469 domain
->name
, domain
->sequence_number
,
470 (uint32_t)domain
->last_seq_check
));
471 return NT_STATUS_UNSUCCESSFUL
;
474 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
475 domain
->name
, domain
->sequence_number
,
476 (uint32_t)domain
->last_seq_check
));
481 bool wcache_store_seqnum(const char *domain_name
, uint32_t seqnum
,
482 time_t last_seq_check
)
484 size_t len
= strlen(domain_name
);
486 TDB_DATA key
= { .dptr
= (uint8_t *)keystr
, .dsize
= sizeof(keystr
) };
490 if (wcache
->tdb
== NULL
) {
491 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
495 snprintf(keystr
, sizeof(keystr
), "SEQNUM/%s", domain_name
);
497 SIVAL(buf
, 0, seqnum
);
498 SIVAL(buf
, 4, last_seq_check
);
500 ret
= tdb_store(wcache
->tdb
, key
, make_tdb_data(buf
, sizeof(buf
)),
503 DEBUG(10, ("tdb_store_bystring failed: %s\n",
504 tdb_errorstr(wcache
->tdb
)));
508 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
509 domain_name
, seqnum
, (unsigned)last_seq_check
));
514 static bool store_cache_seqnum( struct winbindd_domain
*domain
)
516 return wcache_store_seqnum(domain
->name
, domain
->sequence_number
,
517 domain
->last_seq_check
);
521 refresh the domain sequence number on timeout.
524 static void refresh_sequence_number(struct winbindd_domain
*domain
)
528 time_t t
= time(NULL
);
529 unsigned cache_time
= lp_winbind_cache_time();
531 if (is_domain_offline(domain
)) {
537 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
538 /* trying to reconnect is expensive, don't do it too often */
539 if (domain
->sequence_number
== DOM_SEQUENCE_NONE
) {
544 time_diff
= t
- domain
->last_seq_check
;
546 /* see if we have to refetch the domain sequence number */
547 if ((time_diff
< cache_time
) &&
548 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
549 NT_STATUS_IS_OK(domain
->last_status
)) {
550 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain
->name
));
554 /* try to get the sequence number from the tdb cache first */
555 /* this will update the timestamp as well */
557 status
= fetch_cache_seqnum( domain
, t
);
558 if (NT_STATUS_IS_OK(status
) &&
559 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
560 NT_STATUS_IS_OK(domain
->last_status
)) {
564 /* important! make sure that we know if this is a native
565 mode domain or not. And that we can contact it. */
567 if ( winbindd_can_contact_domain( domain
) ) {
568 status
= domain
->backend
->sequence_number(domain
,
569 &domain
->sequence_number
);
571 /* just use the current time */
572 status
= NT_STATUS_OK
;
573 domain
->sequence_number
= time(NULL
);
577 /* the above call could have set our domain->backend to NULL when
578 * coming from offline to online mode, make sure to reinitialize the
579 * backend - Guenther */
582 if (!NT_STATUS_IS_OK(status
)) {
583 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status
)));
584 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
587 domain
->last_status
= status
;
588 domain
->last_seq_check
= time(NULL
);
590 /* save the new sequence number in the cache */
591 store_cache_seqnum( domain
);
594 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
595 domain
->name
, domain
->sequence_number
));
601 decide if a cache entry has expired
603 static bool centry_expired(struct winbindd_domain
*domain
, const char *keystr
, struct cache_entry
*centry
)
605 /* If we've been told to be offline - stay in that state... */
606 if (lp_winbind_offline_logon() && global_winbindd_offline_state
) {
607 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
608 keystr
, domain
->name
));
612 /* when the domain is offline return the cached entry.
613 * This deals with transient offline states... */
615 if (!domain
->online
) {
616 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
617 keystr
, domain
->name
));
621 /* if the server is OK and our cache entry came from when it was down then
622 the entry is invalid */
623 if ((domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
624 (centry
->sequence_number
== DOM_SEQUENCE_NONE
)) {
625 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
626 keystr
, domain
->name
));
630 /* if the server is down or the cache entry is not older than the
631 current sequence number or it did not timeout then it is OK */
632 if (wcache_server_down(domain
)
633 || ((centry
->sequence_number
== domain
->sequence_number
)
634 && (centry
->timeout
> time(NULL
)))) {
635 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
636 keystr
, domain
->name
));
640 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
641 keystr
, domain
->name
));
647 static struct cache_entry
*wcache_fetch_raw(char *kstr
)
650 struct cache_entry
*centry
;
653 key
= string_tdb_data(kstr
);
654 data
= tdb_fetch(wcache
->tdb
, key
);
660 centry
= SMB_XMALLOC_P(struct cache_entry
);
661 centry
->data
= (unsigned char *)data
.dptr
;
662 centry
->len
= data
.dsize
;
665 if (centry
->len
< 16) {
666 /* huh? corrupt cache? */
667 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s "
668 "(len < 16)?\n", kstr
));
673 centry
->status
= centry_ntstatus(centry
);
674 centry
->sequence_number
= centry_uint32(centry
);
675 centry
->timeout
= centry_uint64_t(centry
);
680 static bool is_my_own_sam_domain(struct winbindd_domain
*domain
)
682 if (strequal(domain
->name
, get_global_sam_name()) &&
683 sid_check_is_our_sam(&domain
->sid
)) {
690 static bool is_builtin_domain(struct winbindd_domain
*domain
)
692 if (strequal(domain
->name
, "BUILTIN") &&
693 sid_check_is_builtin(&domain
->sid
)) {
701 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
702 number and return status
704 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
705 struct winbindd_domain
*domain
,
706 const char *format
, ...) PRINTF_ATTRIBUTE(3,4);
707 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
708 struct winbindd_domain
*domain
,
709 const char *format
, ...)
713 struct cache_entry
*centry
;
715 if (!winbindd_use_cache() ||
716 is_my_own_sam_domain(domain
) ||
717 is_builtin_domain(domain
)) {
721 refresh_sequence_number(domain
);
723 va_start(ap
, format
);
724 smb_xvasprintf(&kstr
, format
, ap
);
727 centry
= wcache_fetch_raw(kstr
);
728 if (centry
== NULL
) {
733 if (centry_expired(domain
, kstr
, centry
)) {
735 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
736 kstr
, domain
->name
));
743 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
744 kstr
, domain
->name
));
750 static void wcache_delete(const char *format
, ...) PRINTF_ATTRIBUTE(1,2);
751 static void wcache_delete(const char *format
, ...)
757 va_start(ap
, format
);
758 smb_xvasprintf(&kstr
, format
, ap
);
761 key
= string_tdb_data(kstr
);
763 tdb_delete(wcache
->tdb
, key
);
768 make sure we have at least len bytes available in a centry
770 static void centry_expand(struct cache_entry
*centry
, uint32_t len
)
772 if (centry
->len
- centry
->ofs
>= len
)
775 centry
->data
= SMB_REALLOC_ARRAY(centry
->data
, unsigned char,
778 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry
->len
));
779 smb_panic_fn("out of memory in centry_expand");
784 push a uint64_t into a centry
786 static void centry_put_uint64_t(struct cache_entry
*centry
, uint64_t v
)
788 centry_expand(centry
, 8);
789 SBVAL(centry
->data
, centry
->ofs
, v
);
794 push a uint32_t into a centry
796 static void centry_put_uint32(struct cache_entry
*centry
, uint32_t v
)
798 centry_expand(centry
, 4);
799 SIVAL(centry
->data
, centry
->ofs
, v
);
804 push a uint16_t into a centry
806 static void centry_put_uint16(struct cache_entry
*centry
, uint16_t v
)
808 centry_expand(centry
, 2);
809 SSVAL(centry
->data
, centry
->ofs
, v
);
814 push a uint8_t into a centry
816 static void centry_put_uint8(struct cache_entry
*centry
, uint8_t v
)
818 centry_expand(centry
, 1);
819 SCVAL(centry
->data
, centry
->ofs
, v
);
824 push a string into a centry
826 static void centry_put_string(struct cache_entry
*centry
, const char *s
)
831 /* null strings are marked as len 0xFFFF */
832 centry_put_uint8(centry
, 0xFF);
837 /* can't handle more than 254 char strings. Truncating is probably best */
839 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len
));
842 centry_put_uint8(centry
, len
);
843 centry_expand(centry
, len
);
844 memcpy(centry
->data
+ centry
->ofs
, s
, len
);
849 push a 16 byte hash into a centry - treat as 16 byte string.
851 static void centry_put_hash16(struct cache_entry
*centry
, const uint8_t val
[16])
853 centry_put_uint8(centry
, 16);
854 centry_expand(centry
, 16);
855 memcpy(centry
->data
+ centry
->ofs
, val
, 16);
859 static void centry_put_sid(struct cache_entry
*centry
, const struct dom_sid
*sid
)
862 centry_put_string(centry
, sid_to_fstring(sid_string
, sid
));
867 put NTSTATUS into a centry
869 static void centry_put_ntstatus(struct cache_entry
*centry
, NTSTATUS status
)
871 uint32_t status_value
= NT_STATUS_V(status
);
872 centry_put_uint32(centry
, status_value
);
877 push a NTTIME into a centry
879 static void centry_put_nttime(struct cache_entry
*centry
, NTTIME nt
)
881 centry_expand(centry
, 8);
882 SIVAL(centry
->data
, centry
->ofs
, nt
& 0xFFFFFFFF);
884 SIVAL(centry
->data
, centry
->ofs
, nt
>> 32);
889 push a time_t into a centry - use a 64 bit size.
890 NTTIME here is being used as a convenient 64-bit size.
892 static void centry_put_time(struct cache_entry
*centry
, time_t t
)
894 NTTIME nt
= (NTTIME
)t
;
895 centry_put_nttime(centry
, nt
);
899 start a centry for output. When finished, call centry_end()
901 static struct cache_entry
*centry_start(struct winbindd_domain
*domain
,
904 struct cache_entry
*centry
;
909 centry
= SMB_XMALLOC_P(struct cache_entry
);
911 centry
->len
= 8192; /* reasonable default */
912 centry
->data
= SMB_XMALLOC_ARRAY(uint8_t, centry
->len
);
914 centry
->sequence_number
= domain
->sequence_number
;
915 centry
->timeout
= lp_winbind_cache_time() + time(NULL
);
916 centry_put_ntstatus(centry
, status
);
917 centry_put_uint32(centry
, centry
->sequence_number
);
918 centry_put_uint64_t(centry
, centry
->timeout
);
923 finish a centry and write it to the tdb
925 static void centry_end(struct cache_entry
*centry
, const char *format
, ...) PRINTF_ATTRIBUTE(2,3);
926 static void centry_end(struct cache_entry
*centry
, const char *format
, ...)
932 if (!winbindd_use_cache()) {
936 va_start(ap
, format
);
937 smb_xvasprintf(&kstr
, format
, ap
);
940 key
= string_tdb_data(kstr
);
941 data
.dptr
= centry
->data
;
942 data
.dsize
= centry
->ofs
;
944 tdb_store(wcache
->tdb
, key
, data
, TDB_REPLACE
);
948 static void wcache_save_name_to_sid(struct winbindd_domain
*domain
,
949 NTSTATUS status
, const char *domain_name
,
950 const char *name
, const struct dom_sid
*sid
,
951 enum lsa_SidType type
)
953 struct cache_entry
*centry
;
956 centry
= centry_start(domain
, status
);
960 if ((domain_name
== NULL
) || (domain_name
[0] == '\0')) {
961 struct winbindd_domain
*mydomain
=
962 find_domain_from_sid_noinit(sid
);
963 if (mydomain
!= NULL
) {
964 domain_name
= mydomain
->name
;
968 centry_put_uint32(centry
, type
);
969 centry_put_sid(centry
, sid
);
970 fstrcpy(uname
, name
);
971 (void)strupper_m(uname
);
972 centry_end(centry
, "NS/%s/%s", domain_name
, uname
);
973 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name
,
974 uname
, sid_string_dbg(sid
), nt_errstr(status
)));
978 static void wcache_save_sid_to_name(struct winbindd_domain
*domain
, NTSTATUS status
,
979 const struct dom_sid
*sid
, const char *domain_name
, const char *name
, enum lsa_SidType type
)
981 struct cache_entry
*centry
;
984 centry
= centry_start(domain
, status
);
988 if ((domain_name
== NULL
) || (domain_name
[0] == '\0')) {
989 struct winbindd_domain
*mydomain
=
990 find_domain_from_sid_noinit(sid
);
991 if (mydomain
!= NULL
) {
992 domain_name
= mydomain
->name
;
996 if (NT_STATUS_IS_OK(status
)) {
997 centry_put_uint32(centry
, type
);
998 centry_put_string(centry
, domain_name
);
999 centry_put_string(centry
, name
);
1002 centry_end(centry
, "SN/%s", sid_to_fstring(sid_string
, sid
));
1003 DEBUG(10,("wcache_save_sid_to_name: %s -> %s\\%s (%s)\n", sid_string
,
1004 domain_name
, name
, nt_errstr(status
)));
1005 centry_free(centry
);
1009 static void wcache_save_user(struct winbindd_domain
*domain
, NTSTATUS status
,
1010 struct wbint_userinfo
*info
)
1012 struct cache_entry
*centry
;
1015 if (is_null_sid(&info
->user_sid
)) {
1019 centry
= centry_start(domain
, status
);
1022 centry_put_string(centry
, info
->acct_name
);
1023 centry_put_string(centry
, info
->full_name
);
1024 centry_put_string(centry
, info
->homedir
);
1025 centry_put_string(centry
, info
->shell
);
1026 centry_put_uint32(centry
, info
->primary_gid
);
1027 centry_put_sid(centry
, &info
->user_sid
);
1028 centry_put_sid(centry
, &info
->group_sid
);
1029 centry_end(centry
, "U/%s", sid_to_fstring(sid_string
,
1031 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string
, info
->acct_name
));
1032 centry_free(centry
);
1035 static void wcache_save_lockout_policy(struct winbindd_domain
*domain
,
1037 struct samr_DomInfo12
*lockout_policy
)
1039 struct cache_entry
*centry
;
1041 centry
= centry_start(domain
, status
);
1045 centry_put_nttime(centry
, lockout_policy
->lockout_duration
);
1046 centry_put_nttime(centry
, lockout_policy
->lockout_window
);
1047 centry_put_uint16(centry
, lockout_policy
->lockout_threshold
);
1049 centry_end(centry
, "LOC_POL/%s", domain
->name
);
1051 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain
->name
));
1053 centry_free(centry
);
1058 static void wcache_save_password_policy(struct winbindd_domain
*domain
,
1060 struct samr_DomInfo1
*policy
)
1062 struct cache_entry
*centry
;
1064 centry
= centry_start(domain
, status
);
1068 centry_put_uint16(centry
, policy
->min_password_length
);
1069 centry_put_uint16(centry
, policy
->password_history_length
);
1070 centry_put_uint32(centry
, policy
->password_properties
);
1071 centry_put_nttime(centry
, policy
->max_password_age
);
1072 centry_put_nttime(centry
, policy
->min_password_age
);
1074 centry_end(centry
, "PWD_POL/%s", domain
->name
);
1076 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
1078 centry_free(centry
);
1081 /***************************************************************************
1082 ***************************************************************************/
1084 static void wcache_save_username_alias(struct winbindd_domain
*domain
,
1086 const char *name
, const char *alias
)
1088 struct cache_entry
*centry
;
1091 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1094 centry_put_string( centry
, alias
);
1096 fstrcpy(uname
, name
);
1097 (void)strupper_m(uname
);
1098 centry_end(centry
, "NSS/NA/%s", uname
);
1100 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name
, alias
));
1102 centry_free(centry
);
1105 static void wcache_save_alias_username(struct winbindd_domain
*domain
,
1107 const char *alias
, const char *name
)
1109 struct cache_entry
*centry
;
1112 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1115 centry_put_string( centry
, name
);
1117 fstrcpy(uname
, alias
);
1118 (void)strupper_m(uname
);
1119 centry_end(centry
, "NSS/AN/%s", uname
);
1121 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias
, name
));
1123 centry_free(centry
);
1126 /***************************************************************************
1127 ***************************************************************************/
1129 NTSTATUS
resolve_username_to_alias( TALLOC_CTX
*mem_ctx
,
1130 struct winbindd_domain
*domain
,
1131 const char *name
, char **alias
)
1133 struct winbind_cache
*cache
= get_cache(domain
);
1134 struct cache_entry
*centry
= NULL
;
1138 if ( domain
->internal
)
1139 return NT_STATUS_NOT_SUPPORTED
;
1144 upper_name
= talloc_strdup(mem_ctx
, name
);
1145 if (upper_name
== NULL
) {
1146 return NT_STATUS_NO_MEMORY
;
1148 if (!strupper_m(upper_name
)) {
1149 talloc_free(upper_name
);
1150 return NT_STATUS_INVALID_PARAMETER
;
1153 centry
= wcache_fetch(cache
, domain
, "NSS/NA/%s", upper_name
);
1155 talloc_free(upper_name
);
1160 status
= centry
->status
;
1162 if (!NT_STATUS_IS_OK(status
)) {
1163 centry_free(centry
);
1167 *alias
= centry_string( centry
, mem_ctx
);
1169 centry_free(centry
);
1171 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1172 name
, *alias
? *alias
: "(none)"));
1174 return (*alias
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1178 /* If its not in cache and we are offline, then fail */
1180 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1181 DEBUG(8,("resolve_username_to_alias: rejecting query "
1182 "in offline mode\n"));
1183 return NT_STATUS_NOT_FOUND
;
1186 status
= nss_map_to_alias( mem_ctx
, domain
->name
, name
, alias
);
1188 if ( NT_STATUS_IS_OK( status
) ) {
1189 wcache_save_username_alias(domain
, status
, name
, *alias
);
1192 if ( NT_STATUS_EQUAL( status
, NT_STATUS_NONE_MAPPED
) ) {
1193 wcache_save_username_alias(domain
, status
, name
, "(NULL)");
1196 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1197 nt_errstr(status
)));
1199 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1200 set_domain_offline( domain
);
1206 /***************************************************************************
1207 ***************************************************************************/
1209 NTSTATUS
resolve_alias_to_username( TALLOC_CTX
*mem_ctx
,
1210 struct winbindd_domain
*domain
,
1211 const char *alias
, char **name
)
1213 struct winbind_cache
*cache
= get_cache(domain
);
1214 struct cache_entry
*centry
= NULL
;
1218 if ( domain
->internal
)
1219 return NT_STATUS_NOT_SUPPORTED
;
1224 upper_name
= talloc_strdup(mem_ctx
, alias
);
1225 if (upper_name
== NULL
) {
1226 return NT_STATUS_NO_MEMORY
;
1228 if (!strupper_m(upper_name
)) {
1229 talloc_free(upper_name
);
1230 return NT_STATUS_INVALID_PARAMETER
;
1233 centry
= wcache_fetch(cache
, domain
, "NSS/AN/%s", upper_name
);
1235 talloc_free(upper_name
);
1240 status
= centry
->status
;
1242 if (!NT_STATUS_IS_OK(status
)) {
1243 centry_free(centry
);
1247 *name
= centry_string( centry
, mem_ctx
);
1249 centry_free(centry
);
1251 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1252 alias
, *name
? *name
: "(none)"));
1254 return (*name
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1258 /* If its not in cache and we are offline, then fail */
1260 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1261 DEBUG(8,("resolve_alias_to_username: rejecting query "
1262 "in offline mode\n"));
1263 return NT_STATUS_NOT_FOUND
;
1266 /* an alias cannot contain a domain prefix or '@' */
1268 if (strchr(alias
, '\\') || strchr(alias
, '@')) {
1269 DEBUG(10,("resolve_alias_to_username: skipping fully "
1270 "qualified name %s\n", alias
));
1271 return NT_STATUS_OBJECT_NAME_INVALID
;
1274 status
= nss_map_from_alias( mem_ctx
, domain
->name
, alias
, name
);
1276 if ( NT_STATUS_IS_OK( status
) ) {
1277 wcache_save_alias_username( domain
, status
, alias
, *name
);
1280 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1281 wcache_save_alias_username(domain
, status
, alias
, "(NULL)");
1284 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1285 nt_errstr(status
)));
1287 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1288 set_domain_offline( domain
);
1294 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
1296 struct winbind_cache
*cache
= get_cache(domain
);
1298 fstring key_str
, tmp
;
1302 return NT_STATUS_INTERNAL_DB_ERROR
;
1305 if (is_null_sid(sid
)) {
1306 return NT_STATUS_INVALID_SID
;
1309 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1310 return NT_STATUS_INVALID_SID
;
1313 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
1315 data
= tdb_fetch(cache
->tdb
, string_tdb_data(key_str
));
1317 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1320 SAFE_FREE(data
.dptr
);
1321 return NT_STATUS_OK
;
1324 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1325 as new salted ones. */
1327 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
1328 TALLOC_CTX
*mem_ctx
,
1329 const struct dom_sid
*sid
,
1330 const uint8_t **cached_nt_pass
,
1331 const uint8_t **cached_salt
)
1333 struct winbind_cache
*cache
= get_cache(domain
);
1334 struct cache_entry
*centry
= NULL
;
1340 return NT_STATUS_INTERNAL_DB_ERROR
;
1343 if (is_null_sid(sid
)) {
1344 return NT_STATUS_INVALID_SID
;
1347 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1348 return NT_STATUS_INVALID_SID
;
1351 /* Try and get a salted cred first. If we can't
1352 fall back to an unsalted cred. */
1354 centry
= wcache_fetch(cache
, domain
, "CRED/%s",
1355 sid_to_fstring(tmp
, sid
));
1357 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1358 sid_string_dbg(sid
)));
1359 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1363 * We don't use the time element at this moment,
1364 * but we have to consume it, so that we don't
1365 * neet to change the disk format of the cache.
1367 (void)centry_time(centry
);
1369 /* In the salted case this isn't actually the nt_hash itself,
1370 but the MD5 of the salt + nt_hash. Let the caller
1371 sort this out. It can tell as we only return the cached_salt
1372 if we are returning a salted cred. */
1374 *cached_nt_pass
= (const uint8_t *)centry_hash16(centry
, mem_ctx
);
1375 if (*cached_nt_pass
== NULL
) {
1378 sid_to_fstring(sidstr
, sid
);
1380 /* Bad (old) cred cache. Delete and pretend we
1382 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1384 wcache_delete("CRED/%s", sidstr
);
1385 centry_free(centry
);
1386 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1389 /* We only have 17 bytes more data in the salted cred case. */
1390 if (centry
->len
- centry
->ofs
== 17) {
1391 *cached_salt
= (const uint8_t *)centry_hash16(centry
, mem_ctx
);
1393 *cached_salt
= NULL
;
1396 dump_data_pw("cached_nt_pass", *cached_nt_pass
, NT_HASH_LEN
);
1398 dump_data_pw("cached_salt", *cached_salt
, NT_HASH_LEN
);
1401 status
= centry
->status
;
1403 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1404 sid_string_dbg(sid
), nt_errstr(status
) ));
1406 centry_free(centry
);
1410 /* Store creds for a SID - only writes out new salted ones. */
1412 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1413 const struct dom_sid
*sid
,
1414 const uint8_t nt_pass
[NT_HASH_LEN
])
1416 struct cache_entry
*centry
;
1419 uint8_t cred_salt
[NT_HASH_LEN
];
1420 uint8_t salted_hash
[NT_HASH_LEN
];
1422 if (is_null_sid(sid
)) {
1423 return NT_STATUS_INVALID_SID
;
1426 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1427 return NT_STATUS_INVALID_SID
;
1430 centry
= centry_start(domain
, NT_STATUS_OK
);
1432 return NT_STATUS_INTERNAL_DB_ERROR
;
1435 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1437 centry_put_time(centry
, time(NULL
));
1439 /* Create a salt and then salt the hash. */
1440 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1441 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1443 centry_put_hash16(centry
, salted_hash
);
1444 centry_put_hash16(centry
, cred_salt
);
1445 centry_end(centry
, "CRED/%s", sid_to_fstring(sid_string
, sid
));
1447 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1449 centry_free(centry
);
1451 return NT_STATUS_OK
;
1455 /* Query display info. This is the basic user list fn */
1456 NTSTATUS
wb_cache_query_user_list(struct winbindd_domain
*domain
,
1457 TALLOC_CTX
*mem_ctx
,
1458 uint32_t *num_entries
,
1459 struct wbint_userinfo
**info
)
1461 struct winbind_cache
*cache
= get_cache(domain
);
1462 struct cache_entry
*centry
= NULL
;
1464 unsigned int i
, retry
;
1465 bool old_status
= domain
->online
;
1470 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1475 *num_entries
= centry_uint32(centry
);
1477 if (*num_entries
== 0)
1480 (*info
) = talloc_array(mem_ctx
, struct wbint_userinfo
, *num_entries
);
1482 smb_panic_fn("query_user_list out of memory");
1484 for (i
=0; i
<(*num_entries
); i
++) {
1485 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
1486 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
1487 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
1488 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
1489 centry_sid(centry
, &(*info
)[i
].user_sid
);
1490 centry_sid(centry
, &(*info
)[i
].group_sid
);
1494 status
= centry
->status
;
1496 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1497 domain
->name
, nt_errstr(status
) ));
1499 centry_free(centry
);
1506 /* Return status value returned by seq number check */
1508 if (!NT_STATUS_IS_OK(domain
->last_status
))
1509 return domain
->last_status
;
1511 /* Put the query_user_list() in a retry loop. There appears to be
1512 * some bug either with Windows 2000 or Samba's handling of large
1513 * rpc replies. This manifests itself as sudden disconnection
1514 * at a random point in the enumeration of a large (60k) user list.
1515 * The retry loop simply tries the operation again. )-: It's not
1516 * pretty but an acceptable workaround until we work out what the
1517 * real problem is. */
1522 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1525 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
1526 if (!NT_STATUS_IS_OK(status
)) {
1527 DEBUG(3, ("query_user_list: returned 0x%08x, "
1528 "retrying\n", NT_STATUS_V(status
)));
1530 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1531 DEBUG(3, ("query_user_list: flushing "
1532 "connection cache\n"));
1533 invalidate_cm_connection(domain
);
1535 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1536 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1537 if (!domain
->internal
&& old_status
) {
1538 set_domain_offline(domain
);
1540 /* store partial response. */
1541 if (*num_entries
> 0) {
1543 * humm, what about the status used for cache?
1544 * Should it be NT_STATUS_OK?
1549 * domain is offline now, and there is no user entries,
1550 * try to fetch from cache again.
1552 if (cache
->tdb
&& !domain
->online
&& !domain
->internal
&& old_status
) {
1553 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1554 /* partial response... */
1558 goto do_fetch_cache
;
1565 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1569 refresh_sequence_number(domain
);
1570 if (!NT_STATUS_IS_OK(status
)) {
1573 centry
= centry_start(domain
, status
);
1576 centry_put_uint32(centry
, *num_entries
);
1577 for (i
=0; i
<(*num_entries
); i
++) {
1578 centry_put_string(centry
, (*info
)[i
].acct_name
);
1579 centry_put_string(centry
, (*info
)[i
].full_name
);
1580 centry_put_string(centry
, (*info
)[i
].homedir
);
1581 centry_put_string(centry
, (*info
)[i
].shell
);
1582 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1583 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1584 if (domain
->backend
&& domain
->backend
->consistent
) {
1585 /* when the backend is consistent we can pre-prime some mappings */
1586 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1588 (*info
)[i
].acct_name
,
1589 &(*info
)[i
].user_sid
,
1591 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1592 &(*info
)[i
].user_sid
,
1594 (*info
)[i
].acct_name
,
1596 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1599 centry_end(centry
, "UL/%s", domain
->name
);
1600 centry_free(centry
);
1606 /* list all domain groups */
1607 NTSTATUS
wb_cache_enum_dom_groups(struct winbindd_domain
*domain
,
1608 TALLOC_CTX
*mem_ctx
,
1609 uint32_t *num_entries
,
1610 struct wb_acct_info
**info
)
1612 struct winbind_cache
*cache
= get_cache(domain
);
1613 struct cache_entry
*centry
= NULL
;
1618 old_status
= domain
->online
;
1622 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1627 *num_entries
= centry_uint32(centry
);
1629 if (*num_entries
== 0)
1632 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1634 smb_panic_fn("enum_dom_groups out of memory");
1636 for (i
=0; i
<(*num_entries
); i
++) {
1637 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1638 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1639 (*info
)[i
].rid
= centry_uint32(centry
);
1643 status
= centry
->status
;
1645 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1646 domain
->name
, nt_errstr(status
) ));
1648 centry_free(centry
);
1655 /* Return status value returned by seq number check */
1657 if (!NT_STATUS_IS_OK(domain
->last_status
))
1658 return domain
->last_status
;
1660 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1663 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1665 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1666 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1667 if (!domain
->internal
&& old_status
) {
1668 set_domain_offline(domain
);
1672 !domain
->internal
&&
1674 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1676 goto do_fetch_cache
;
1681 refresh_sequence_number(domain
);
1682 if (!NT_STATUS_IS_OK(status
)) {
1685 centry
= centry_start(domain
, status
);
1688 centry_put_uint32(centry
, *num_entries
);
1689 for (i
=0; i
<(*num_entries
); i
++) {
1690 centry_put_string(centry
, (*info
)[i
].acct_name
);
1691 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1692 centry_put_uint32(centry
, (*info
)[i
].rid
);
1694 centry_end(centry
, "GL/%s/domain", domain
->name
);
1695 centry_free(centry
);
1701 /* list all domain groups */
1702 NTSTATUS
wb_cache_enum_local_groups(struct winbindd_domain
*domain
,
1703 TALLOC_CTX
*mem_ctx
,
1704 uint32_t *num_entries
,
1705 struct wb_acct_info
**info
)
1707 struct winbind_cache
*cache
= get_cache(domain
);
1708 struct cache_entry
*centry
= NULL
;
1713 old_status
= domain
->online
;
1717 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1722 *num_entries
= centry_uint32(centry
);
1724 if (*num_entries
== 0)
1727 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1729 smb_panic_fn("enum_dom_groups out of memory");
1731 for (i
=0; i
<(*num_entries
); i
++) {
1732 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1733 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1734 (*info
)[i
].rid
= centry_uint32(centry
);
1739 /* If we are returning cached data and the domain controller
1740 is down then we don't know whether the data is up to date
1741 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1744 if (wcache_server_down(domain
)) {
1745 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1746 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1748 status
= centry
->status
;
1750 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1751 domain
->name
, nt_errstr(status
) ));
1753 centry_free(centry
);
1760 /* Return status value returned by seq number check */
1762 if (!NT_STATUS_IS_OK(domain
->last_status
))
1763 return domain
->last_status
;
1765 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1768 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1770 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1771 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1772 if (!domain
->internal
&& old_status
) {
1773 set_domain_offline(domain
);
1776 !domain
->internal
&&
1779 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1781 goto do_fetch_cache
;
1786 refresh_sequence_number(domain
);
1787 if (!NT_STATUS_IS_OK(status
)) {
1790 centry
= centry_start(domain
, status
);
1793 centry_put_uint32(centry
, *num_entries
);
1794 for (i
=0; i
<(*num_entries
); i
++) {
1795 centry_put_string(centry
, (*info
)[i
].acct_name
);
1796 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1797 centry_put_uint32(centry
, (*info
)[i
].rid
);
1799 centry_end(centry
, "GL/%s/local", domain
->name
);
1800 centry_free(centry
);
1806 NTSTATUS
wcache_name_to_sid(struct winbindd_domain
*domain
,
1807 const char *domain_name
,
1809 struct dom_sid
*sid
,
1810 enum lsa_SidType
*type
)
1812 struct winbind_cache
*cache
= get_cache(domain
);
1813 struct cache_entry
*centry
;
1817 if (cache
->tdb
== NULL
) {
1818 return NT_STATUS_NOT_FOUND
;
1821 uname
= talloc_strdup_upper(talloc_tos(), name
);
1822 if (uname
== NULL
) {
1823 return NT_STATUS_NO_MEMORY
;
1826 if ((domain_name
== NULL
) || (domain_name
[0] == '\0')) {
1827 domain_name
= domain
->name
;
1830 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1832 if (centry
== NULL
) {
1833 return NT_STATUS_NOT_FOUND
;
1836 status
= centry
->status
;
1837 if (NT_STATUS_IS_OK(status
)) {
1838 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1839 centry_sid(centry
, sid
);
1842 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1843 "%s\n", domain
->name
, nt_errstr(status
) ));
1845 centry_free(centry
);
1849 /* convert a single name to a sid in a domain */
1850 NTSTATUS
wb_cache_name_to_sid(struct winbindd_domain
*domain
,
1851 TALLOC_CTX
*mem_ctx
,
1852 const char *domain_name
,
1855 struct dom_sid
*sid
,
1856 enum lsa_SidType
*type
)
1861 old_status
= domain
->online
;
1863 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1864 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1870 /* If the seq number check indicated that there is a problem
1871 * with this DC, then return that status... except for
1872 * access_denied. This is special because the dc may be in
1873 * "restrict anonymous = 1" mode, in which case it will deny
1874 * most unauthenticated operations, but *will* allow the LSA
1875 * name-to-sid that we try as a fallback. */
1877 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1878 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1879 return domain
->last_status
;
1881 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1884 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
,
1885 name
, flags
, sid
, type
);
1887 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1888 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1889 if (!domain
->internal
&& old_status
) {
1890 set_domain_offline(domain
);
1892 if (!domain
->internal
&&
1895 NTSTATUS cache_status
;
1896 cache_status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1897 return cache_status
;
1901 refresh_sequence_number(domain
);
1903 if (domain
->online
&&
1904 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1905 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1907 /* Only save the reverse mapping if this was not a UPN */
1908 if (!strchr(name
, '@')) {
1909 if (!strupper_m(discard_const_p(char, domain_name
))) {
1910 return NT_STATUS_INVALID_PARAMETER
;
1912 (void)strlower_m(discard_const_p(char, name
));
1913 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1920 static NTSTATUS
wcache_sid_to_name(struct winbindd_domain
*domain
,
1921 const struct dom_sid
*sid
,
1922 TALLOC_CTX
*mem_ctx
,
1925 enum lsa_SidType
*type
)
1927 struct winbind_cache
*cache
= get_cache(domain
);
1928 struct cache_entry
*centry
;
1932 if (cache
->tdb
== NULL
) {
1933 return NT_STATUS_NOT_FOUND
;
1936 sid_string
= sid_string_tos(sid
);
1937 if (sid_string
== NULL
) {
1938 return NT_STATUS_NO_MEMORY
;
1941 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_string
);
1942 TALLOC_FREE(sid_string
);
1943 if (centry
== NULL
) {
1944 return NT_STATUS_NOT_FOUND
;
1947 if (NT_STATUS_IS_OK(centry
->status
)) {
1948 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1949 *domain_name
= centry_string(centry
, mem_ctx
);
1950 *name
= centry_string(centry
, mem_ctx
);
1953 status
= centry
->status
;
1954 centry_free(centry
);
1956 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1957 "%s\n", domain
->name
, nt_errstr(status
) ));
1962 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1964 NTSTATUS
wb_cache_sid_to_name(struct winbindd_domain
*domain
,
1965 TALLOC_CTX
*mem_ctx
,
1966 const struct dom_sid
*sid
,
1969 enum lsa_SidType
*type
)
1974 old_status
= domain
->online
;
1975 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
1977 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1982 *domain_name
= NULL
;
1984 /* If the seq number check indicated that there is a problem
1985 * with this DC, then return that status... except for
1986 * access_denied. This is special because the dc may be in
1987 * "restrict anonymous = 1" mode, in which case it will deny
1988 * most unauthenticated operations, but *will* allow the LSA
1989 * sid-to-name that we try as a fallback. */
1991 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1992 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1993 return domain
->last_status
;
1995 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1998 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
2000 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2001 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2002 if (!domain
->internal
&& old_status
) {
2003 set_domain_offline(domain
);
2005 if (!domain
->internal
&&
2008 NTSTATUS cache_status
;
2009 cache_status
= wcache_sid_to_name(domain
, sid
, mem_ctx
,
2010 domain_name
, name
, type
);
2011 return cache_status
;
2015 refresh_sequence_number(domain
);
2016 if (!NT_STATUS_IS_OK(status
)) {
2019 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
2021 /* We can't save the name to sid mapping here, as with sid history a
2022 * later name2sid would give the wrong sid. */
2027 NTSTATUS
wb_cache_rids_to_names(struct winbindd_domain
*domain
,
2028 TALLOC_CTX
*mem_ctx
,
2029 const struct dom_sid
*domain_sid
,
2034 enum lsa_SidType
**types
)
2036 struct winbind_cache
*cache
= get_cache(domain
);
2038 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
2043 old_status
= domain
->online
;
2044 *domain_name
= NULL
;
2052 if (num_rids
== 0) {
2053 return NT_STATUS_OK
;
2056 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2057 *types
= talloc_array(mem_ctx
, enum lsa_SidType
, num_rids
);
2059 if ((*names
== NULL
) || (*types
== NULL
)) {
2060 result
= NT_STATUS_NO_MEMORY
;
2064 have_mapped
= have_unmapped
= false;
2066 for (i
=0; i
<num_rids
; i
++) {
2068 struct cache_entry
*centry
;
2071 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2072 result
= NT_STATUS_INTERNAL_ERROR
;
2076 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2077 sid_to_fstring(tmp
, &sid
));
2082 (*types
)[i
] = SID_NAME_UNKNOWN
;
2083 (*names
)[i
] = talloc_strdup(*names
, "");
2085 if (NT_STATUS_IS_OK(centry
->status
)) {
2088 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2090 dom
= centry_string(centry
, mem_ctx
);
2091 if (*domain_name
== NULL
) {
2097 (*names
)[i
] = centry_string(centry
, *names
);
2099 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)
2100 || NT_STATUS_EQUAL(centry
->status
, STATUS_SOME_UNMAPPED
)) {
2101 have_unmapped
= true;
2104 /* something's definitely wrong */
2105 result
= centry
->status
;
2106 centry_free(centry
);
2110 centry_free(centry
);
2114 return NT_STATUS_NONE_MAPPED
;
2116 if (!have_unmapped
) {
2117 return NT_STATUS_OK
;
2119 return STATUS_SOME_UNMAPPED
;
2123 TALLOC_FREE(*names
);
2124 TALLOC_FREE(*types
);
2126 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
2127 rids
, num_rids
, domain_name
,
2130 if (NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
2131 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2132 if (!domain
->internal
&& old_status
) {
2133 set_domain_offline(domain
);
2136 !domain
->internal
&&
2139 have_mapped
= have_unmapped
= false;
2141 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2142 if (*names
== NULL
) {
2143 result
= NT_STATUS_NO_MEMORY
;
2147 *types
= talloc_array(mem_ctx
, enum lsa_SidType
,
2149 if (*types
== NULL
) {
2150 result
= NT_STATUS_NO_MEMORY
;
2154 for (i
=0; i
<num_rids
; i
++) {
2156 struct cache_entry
*centry
;
2159 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2160 result
= NT_STATUS_INTERNAL_ERROR
;
2164 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2165 sid_to_fstring(tmp
, &sid
));
2167 (*types
)[i
] = SID_NAME_UNKNOWN
;
2168 (*names
)[i
] = talloc_strdup(*names
, "");
2172 (*types
)[i
] = SID_NAME_UNKNOWN
;
2173 (*names
)[i
] = talloc_strdup(*names
, "");
2175 if (NT_STATUS_IS_OK(centry
->status
)) {
2178 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2180 dom
= centry_string(centry
, mem_ctx
);
2181 if (*domain_name
== NULL
) {
2187 (*names
)[i
] = centry_string(centry
, *names
);
2189 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)) {
2190 have_unmapped
= true;
2193 /* something's definitely wrong */
2194 result
= centry
->status
;
2195 centry_free(centry
);
2199 centry_free(centry
);
2203 return NT_STATUS_NONE_MAPPED
;
2205 if (!have_unmapped
) {
2206 return NT_STATUS_OK
;
2208 return STATUS_SOME_UNMAPPED
;
2212 None of the queried rids has been found so save all negative entries
2214 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
2215 for (i
= 0; i
< num_rids
; i
++) {
2217 const char *name
= "";
2218 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
2219 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
2221 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2222 return NT_STATUS_INTERNAL_ERROR
;
2225 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2233 Some or all of the queried rids have been found.
2235 if (!NT_STATUS_IS_OK(result
) &&
2236 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
2240 refresh_sequence_number(domain
);
2242 for (i
=0; i
<num_rids
; i
++) {
2246 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2247 result
= NT_STATUS_INTERNAL_ERROR
;
2251 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
2252 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
2254 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2255 (*names
)[i
], (*types
)[i
]);
2261 TALLOC_FREE(*names
);
2262 TALLOC_FREE(*types
);
2266 NTSTATUS
wcache_query_user(struct winbindd_domain
*domain
,
2267 TALLOC_CTX
*mem_ctx
,
2268 const struct dom_sid
*user_sid
,
2269 struct wbint_userinfo
*info
)
2271 struct winbind_cache
*cache
= get_cache(domain
);
2272 struct cache_entry
*centry
= NULL
;
2276 if (cache
->tdb
== NULL
) {
2277 return NT_STATUS_NOT_FOUND
;
2280 sid_string
= sid_string_tos(user_sid
);
2281 if (sid_string
== NULL
) {
2282 return NT_STATUS_NO_MEMORY
;
2285 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string
);
2286 TALLOC_FREE(sid_string
);
2287 if (centry
== NULL
) {
2288 return NT_STATUS_NOT_FOUND
;
2292 * If we have an access denied cache entry and a cached info3
2293 * in the samlogon cache then do a query. This will force the
2294 * rpc back end to return the info3 data.
2297 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
) &&
2298 netsamlogon_cache_have(user_sid
)) {
2299 DEBUG(10, ("query_user: cached access denied and have cached "
2301 domain
->last_status
= NT_STATUS_OK
;
2302 centry_free(centry
);
2303 return NT_STATUS_NOT_FOUND
;
2306 /* if status is not ok then this is a negative hit
2307 and the rest of the data doesn't matter */
2308 status
= centry
->status
;
2309 if (NT_STATUS_IS_OK(status
)) {
2310 info
->acct_name
= centry_string(centry
, mem_ctx
);
2311 info
->full_name
= centry_string(centry
, mem_ctx
);
2312 info
->homedir
= centry_string(centry
, mem_ctx
);
2313 info
->shell
= centry_string(centry
, mem_ctx
);
2314 info
->primary_gid
= centry_uint32(centry
);
2315 centry_sid(centry
, &info
->user_sid
);
2316 centry_sid(centry
, &info
->group_sid
);
2319 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2320 "%s\n", domain
->name
, nt_errstr(status
) ));
2322 centry_free(centry
);
2328 * @brief Query a fullname from the username cache (for further gecos processing)
2330 * @param domain A pointer to the winbindd_domain struct.
2331 * @param mem_ctx The talloc context.
2332 * @param user_sid The user sid.
2333 * @param full_name A pointer to the full_name string.
2335 * @return NTSTATUS code
2337 NTSTATUS
wcache_query_user_fullname(struct winbindd_domain
*domain
,
2338 TALLOC_CTX
*mem_ctx
,
2339 const struct dom_sid
*user_sid
,
2340 const char **full_name
)
2343 struct wbint_userinfo info
;
2345 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, &info
);
2346 if (!NT_STATUS_IS_OK(status
)) {
2350 if (info
.full_name
!= NULL
) {
2351 *full_name
= talloc_strdup(mem_ctx
, info
.full_name
);
2352 if (*full_name
== NULL
) {
2353 return NT_STATUS_NO_MEMORY
;
2357 return NT_STATUS_OK
;
2360 /* Lookup user information from a rid */
2361 NTSTATUS
wb_cache_query_user(struct winbindd_domain
*domain
,
2362 TALLOC_CTX
*mem_ctx
,
2363 const struct dom_sid
*user_sid
,
2364 struct wbint_userinfo
*info
)
2369 old_status
= domain
->online
;
2370 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2371 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2377 /* Return status value returned by seq number check */
2379 if (!NT_STATUS_IS_OK(domain
->last_status
))
2380 return domain
->last_status
;
2382 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2385 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
2387 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2388 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2389 if (!domain
->internal
&& old_status
) {
2390 set_domain_offline(domain
);
2392 if (!domain
->internal
&&
2395 NTSTATUS cache_status
;
2396 cache_status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2397 return cache_status
;
2401 refresh_sequence_number(domain
);
2402 if (!NT_STATUS_IS_OK(status
)) {
2405 wcache_save_user(domain
, status
, info
);
2410 NTSTATUS
wcache_lookup_usergroups(struct winbindd_domain
*domain
,
2411 TALLOC_CTX
*mem_ctx
,
2412 const struct dom_sid
*user_sid
,
2413 uint32_t *pnum_sids
,
2414 struct dom_sid
**psids
)
2416 struct winbind_cache
*cache
= get_cache(domain
);
2417 struct cache_entry
*centry
= NULL
;
2419 uint32_t i
, num_sids
;
2420 struct dom_sid
*sids
;
2423 if (cache
->tdb
== NULL
) {
2424 return NT_STATUS_NOT_FOUND
;
2427 centry
= wcache_fetch(cache
, domain
, "UG/%s",
2428 sid_to_fstring(sid_string
, user_sid
));
2429 if (centry
== NULL
) {
2430 return NT_STATUS_NOT_FOUND
;
2433 /* If we have an access denied cache entry and a cached info3 in the
2434 samlogon cache then do a query. This will force the rpc back end
2435 to return the info3 data. */
2437 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)
2438 && netsamlogon_cache_have(user_sid
)) {
2439 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2441 domain
->last_status
= NT_STATUS_OK
;
2442 centry_free(centry
);
2443 return NT_STATUS_NOT_FOUND
;
2446 num_sids
= centry_uint32(centry
);
2447 sids
= talloc_array(mem_ctx
, struct dom_sid
, num_sids
);
2449 centry_free(centry
);
2450 return NT_STATUS_NO_MEMORY
;
2453 for (i
=0; i
<num_sids
; i
++) {
2454 centry_sid(centry
, &sids
[i
]);
2457 status
= centry
->status
;
2459 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2460 "status: %s\n", domain
->name
, nt_errstr(status
)));
2462 centry_free(centry
);
2464 *pnum_sids
= num_sids
;
2469 /* Lookup groups a user is a member of. */
2470 NTSTATUS
wb_cache_lookup_usergroups(struct winbindd_domain
*domain
,
2471 TALLOC_CTX
*mem_ctx
,
2472 const struct dom_sid
*user_sid
,
2473 uint32_t *num_groups
,
2474 struct dom_sid
**user_gids
)
2476 struct cache_entry
*centry
= NULL
;
2482 old_status
= domain
->online
;
2483 status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2484 num_groups
, user_gids
);
2485 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2490 (*user_gids
) = NULL
;
2492 /* Return status value returned by seq number check */
2494 if (!NT_STATUS_IS_OK(domain
->last_status
))
2495 return domain
->last_status
;
2497 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2500 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
2502 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2503 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2504 if (!domain
->internal
&& old_status
) {
2505 set_domain_offline(domain
);
2507 if (!domain
->internal
&&
2510 NTSTATUS cache_status
;
2511 cache_status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2512 num_groups
, user_gids
);
2513 return cache_status
;
2516 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
2520 refresh_sequence_number(domain
);
2521 if (!NT_STATUS_IS_OK(status
)) {
2524 centry
= centry_start(domain
, status
);
2528 centry_put_uint32(centry
, *num_groups
);
2529 for (i
=0; i
<(*num_groups
); i
++) {
2530 centry_put_sid(centry
, &(*user_gids
)[i
]);
2533 centry_end(centry
, "UG/%s", sid_to_fstring(sid_string
, user_sid
));
2534 centry_free(centry
);
2540 static char *wcache_make_sidlist(TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2541 const struct dom_sid
*sids
)
2546 sidlist
= talloc_strdup(mem_ctx
, "");
2547 if (sidlist
== NULL
) {
2550 for (i
=0; i
<num_sids
; i
++) {
2552 sidlist
= talloc_asprintf_append_buffer(
2553 sidlist
, "/%s", sid_to_fstring(tmp
, &sids
[i
]));
2554 if (sidlist
== NULL
) {
2561 NTSTATUS
wcache_lookup_useraliases(struct winbindd_domain
*domain
,
2562 TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2563 const struct dom_sid
*sids
,
2564 uint32_t *pnum_aliases
, uint32_t **paliases
)
2566 struct winbind_cache
*cache
= get_cache(domain
);
2567 struct cache_entry
*centry
= NULL
;
2568 uint32_t num_aliases
;
2574 if (cache
->tdb
== NULL
) {
2575 return NT_STATUS_NOT_FOUND
;
2578 if (num_sids
== 0) {
2581 return NT_STATUS_OK
;
2584 /* We need to cache indexed by the whole list of SIDs, the aliases
2585 * resulting might come from any of the SIDs. */
2587 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2588 if (sidlist
== NULL
) {
2589 return NT_STATUS_NO_MEMORY
;
2592 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2593 TALLOC_FREE(sidlist
);
2594 if (centry
== NULL
) {
2595 return NT_STATUS_NOT_FOUND
;
2598 num_aliases
= centry_uint32(centry
);
2599 aliases
= talloc_array(mem_ctx
, uint32_t, num_aliases
);
2600 if (aliases
== NULL
) {
2601 centry_free(centry
);
2602 return NT_STATUS_NO_MEMORY
;
2605 for (i
=0; i
<num_aliases
; i
++) {
2606 aliases
[i
] = centry_uint32(centry
);
2609 status
= centry
->status
;
2611 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2612 "status %s\n", domain
->name
, nt_errstr(status
)));
2614 centry_free(centry
);
2616 *pnum_aliases
= num_aliases
;
2617 *paliases
= aliases
;
2622 NTSTATUS
wb_cache_lookup_useraliases(struct winbindd_domain
*domain
,
2623 TALLOC_CTX
*mem_ctx
,
2625 const struct dom_sid
*sids
,
2626 uint32_t *num_aliases
,
2627 uint32_t **alias_rids
)
2629 struct cache_entry
*centry
= NULL
;
2635 old_status
= domain
->online
;
2636 status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
2637 num_aliases
, alias_rids
);
2638 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2643 (*alias_rids
) = NULL
;
2645 if (!NT_STATUS_IS_OK(domain
->last_status
))
2646 return domain
->last_status
;
2648 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2649 "for domain %s\n", domain
->name
));
2651 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2652 if (sidlist
== NULL
) {
2653 return NT_STATUS_NO_MEMORY
;
2656 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2658 num_aliases
, alias_rids
);
2660 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2661 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2662 if (!domain
->internal
&& old_status
) {
2663 set_domain_offline(domain
);
2665 if (!domain
->internal
&&
2668 NTSTATUS cache_status
;
2669 cache_status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
,
2670 sids
, num_aliases
, alias_rids
);
2671 return cache_status
;
2675 refresh_sequence_number(domain
);
2676 if (!NT_STATUS_IS_OK(status
)) {
2679 centry
= centry_start(domain
, status
);
2682 centry_put_uint32(centry
, *num_aliases
);
2683 for (i
=0; i
<(*num_aliases
); i
++)
2684 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2685 centry_end(centry
, "UA%s", sidlist
);
2686 centry_free(centry
);
2692 NTSTATUS
wcache_lookup_groupmem(struct winbindd_domain
*domain
,
2693 TALLOC_CTX
*mem_ctx
,
2694 const struct dom_sid
*group_sid
,
2695 uint32_t *num_names
,
2696 struct dom_sid
**sid_mem
, char ***names
,
2697 uint32_t **name_types
)
2699 struct winbind_cache
*cache
= get_cache(domain
);
2700 struct cache_entry
*centry
= NULL
;
2705 if (cache
->tdb
== NULL
) {
2706 return NT_STATUS_NOT_FOUND
;
2709 sid_string
= sid_string_tos(group_sid
);
2710 if (sid_string
== NULL
) {
2711 return NT_STATUS_NO_MEMORY
;
2714 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_string
);
2715 TALLOC_FREE(sid_string
);
2716 if (centry
== NULL
) {
2717 return NT_STATUS_NOT_FOUND
;
2724 *num_names
= centry_uint32(centry
);
2725 if (*num_names
== 0) {
2726 centry_free(centry
);
2727 return NT_STATUS_OK
;
2730 *sid_mem
= talloc_array(mem_ctx
, struct dom_sid
, *num_names
);
2731 *names
= talloc_array(mem_ctx
, char *, *num_names
);
2732 *name_types
= talloc_array(mem_ctx
, uint32_t, *num_names
);
2734 if ((*sid_mem
== NULL
) || (*names
== NULL
) || (*name_types
== NULL
)) {
2735 TALLOC_FREE(*sid_mem
);
2736 TALLOC_FREE(*names
);
2737 TALLOC_FREE(*name_types
);
2738 centry_free(centry
);
2739 return NT_STATUS_NO_MEMORY
;
2742 for (i
=0; i
<(*num_names
); i
++) {
2743 centry_sid(centry
, &(*sid_mem
)[i
]);
2744 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2745 (*name_types
)[i
] = centry_uint32(centry
);
2748 status
= centry
->status
;
2750 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2751 "status: %s\n", domain
->name
, nt_errstr(status
)));
2753 centry_free(centry
);
2757 NTSTATUS
wb_cache_lookup_groupmem(struct winbindd_domain
*domain
,
2758 TALLOC_CTX
*mem_ctx
,
2759 const struct dom_sid
*group_sid
,
2760 enum lsa_SidType type
,
2761 uint32_t *num_names
,
2762 struct dom_sid
**sid_mem
,
2764 uint32_t **name_types
)
2766 struct cache_entry
*centry
= NULL
;
2772 old_status
= domain
->online
;
2773 status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2774 sid_mem
, names
, name_types
);
2775 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2782 (*name_types
) = NULL
;
2784 /* Return status value returned by seq number check */
2786 if (!NT_STATUS_IS_OK(domain
->last_status
))
2787 return domain
->last_status
;
2789 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2792 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
,
2794 sid_mem
, names
, name_types
);
2796 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2797 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2798 if (!domain
->internal
&& old_status
) {
2799 set_domain_offline(domain
);
2801 if (!domain
->internal
&&
2804 NTSTATUS cache_status
;
2805 cache_status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
,
2806 num_names
, sid_mem
, names
,
2808 return cache_status
;
2812 refresh_sequence_number(domain
);
2813 if (!NT_STATUS_IS_OK(status
)) {
2816 centry
= centry_start(domain
, status
);
2819 centry_put_uint32(centry
, *num_names
);
2820 for (i
=0; i
<(*num_names
); i
++) {
2821 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2822 centry_put_string(centry
, (*names
)[i
]);
2823 centry_put_uint32(centry
, (*name_types
)[i
]);
2825 centry_end(centry
, "GM/%s", sid_to_fstring(sid_string
, group_sid
));
2826 centry_free(centry
);
2832 /* find the sequence number for a domain */
2833 NTSTATUS
wb_cache_sequence_number(struct winbindd_domain
*domain
,
2836 refresh_sequence_number(domain
);
2838 *seq
= domain
->sequence_number
;
2840 return NT_STATUS_OK
;
2843 /* enumerate trusted domains
2844 * (we need to have the list of trustdoms in the cache when we go offline) -
2846 NTSTATUS
wb_cache_trusted_domains(struct winbindd_domain
*domain
,
2847 TALLOC_CTX
*mem_ctx
,
2848 struct netr_DomainTrustList
*trusts
)
2851 struct winbind_cache
*cache
;
2852 struct winbindd_tdc_domain
*dom_list
= NULL
;
2853 size_t num_domains
= 0;
2854 bool retval
= false;
2858 old_status
= domain
->online
;
2860 trusts
->array
= NULL
;
2862 cache
= get_cache(domain
);
2863 if (!cache
|| !cache
->tdb
) {
2867 if (domain
->online
) {
2871 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2872 if (!retval
|| !num_domains
|| !dom_list
) {
2873 TALLOC_FREE(dom_list
);
2878 trusts
->array
= talloc_zero_array(mem_ctx
, struct netr_DomainTrust
, num_domains
);
2879 if (!trusts
->array
) {
2880 TALLOC_FREE(dom_list
);
2881 return NT_STATUS_NO_MEMORY
;
2884 for (i
= 0; i
< num_domains
; i
++) {
2885 struct netr_DomainTrust
*trust
;
2886 struct dom_sid
*sid
;
2887 struct winbindd_domain
*dom
;
2889 dom
= find_domain_from_name_noinit(dom_list
[i
].domain_name
);
2890 if (dom
&& dom
->internal
) {
2894 trust
= &trusts
->array
[trusts
->count
];
2895 trust
->netbios_name
= talloc_strdup(trusts
->array
, dom_list
[i
].domain_name
);
2896 trust
->dns_name
= talloc_strdup(trusts
->array
, dom_list
[i
].dns_name
);
2897 sid
= talloc(trusts
->array
, struct dom_sid
);
2898 if (!trust
->netbios_name
|| !trust
->dns_name
||
2900 TALLOC_FREE(dom_list
);
2901 TALLOC_FREE(trusts
->array
);
2902 return NT_STATUS_NO_MEMORY
;
2905 trust
->trust_flags
= dom_list
[i
].trust_flags
;
2906 trust
->trust_attributes
= dom_list
[i
].trust_attribs
;
2907 trust
->trust_type
= dom_list
[i
].trust_type
;
2908 sid_copy(sid
, &dom_list
[i
].sid
);
2913 TALLOC_FREE(dom_list
);
2914 return NT_STATUS_OK
;
2917 /* Return status value returned by seq number check */
2919 if (!NT_STATUS_IS_OK(domain
->last_status
))
2920 return domain
->last_status
;
2922 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2925 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, trusts
);
2927 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2928 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2929 if (!domain
->internal
&& old_status
) {
2930 set_domain_offline(domain
);
2932 if (!domain
->internal
&&
2935 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2936 if (retval
&& num_domains
&& dom_list
) {
2937 TALLOC_FREE(trusts
->array
);
2939 goto do_fetch_cache
;
2943 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2944 * so that the generic centry handling still applies correctly -
2947 if (!NT_STATUS_IS_ERR(status
)) {
2948 status
= NT_STATUS_OK
;
2953 /* get lockout policy */
2954 NTSTATUS
wb_cache_lockout_policy(struct winbindd_domain
*domain
,
2955 TALLOC_CTX
*mem_ctx
,
2956 struct samr_DomInfo12
*policy
)
2958 struct winbind_cache
*cache
= get_cache(domain
);
2959 struct cache_entry
*centry
= NULL
;
2963 old_status
= domain
->online
;
2967 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2973 policy
->lockout_duration
= centry_nttime(centry
);
2974 policy
->lockout_window
= centry_nttime(centry
);
2975 policy
->lockout_threshold
= centry_uint16(centry
);
2977 status
= centry
->status
;
2979 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2980 domain
->name
, nt_errstr(status
) ));
2982 centry_free(centry
);
2986 ZERO_STRUCTP(policy
);
2988 /* Return status value returned by seq number check */
2990 if (!NT_STATUS_IS_OK(domain
->last_status
))
2991 return domain
->last_status
;
2993 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2996 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2998 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2999 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
3000 if (!domain
->internal
&& old_status
) {
3001 set_domain_offline(domain
);
3004 !domain
->internal
&&
3007 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
3009 goto do_fetch_cache
;
3014 refresh_sequence_number(domain
);
3015 if (!NT_STATUS_IS_OK(status
)) {
3018 wcache_save_lockout_policy(domain
, status
, policy
);
3023 /* get password policy */
3024 NTSTATUS
wb_cache_password_policy(struct winbindd_domain
*domain
,
3025 TALLOC_CTX
*mem_ctx
,
3026 struct samr_DomInfo1
*policy
)
3028 struct winbind_cache
*cache
= get_cache(domain
);
3029 struct cache_entry
*centry
= NULL
;
3033 old_status
= domain
->online
;
3037 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
3043 policy
->min_password_length
= centry_uint16(centry
);
3044 policy
->password_history_length
= centry_uint16(centry
);
3045 policy
->password_properties
= centry_uint32(centry
);
3046 policy
->max_password_age
= centry_nttime(centry
);
3047 policy
->min_password_age
= centry_nttime(centry
);
3049 status
= centry
->status
;
3051 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
3052 domain
->name
, nt_errstr(status
) ));
3054 centry_free(centry
);
3058 ZERO_STRUCTP(policy
);
3060 /* Return status value returned by seq number check */
3062 if (!NT_STATUS_IS_OK(domain
->last_status
))
3063 return domain
->last_status
;
3065 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
3068 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
3070 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
3071 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
3072 if (!domain
->internal
&& old_status
) {
3073 set_domain_offline(domain
);
3076 !domain
->internal
&&
3079 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
3081 goto do_fetch_cache
;
3086 refresh_sequence_number(domain
);
3087 if (!NT_STATUS_IS_OK(status
)) {
3090 wcache_save_password_policy(domain
, status
, policy
);
3096 /* Invalidate cached user and group lists coherently */
3098 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3101 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
3102 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
3103 tdb_delete(the_tdb
, kbuf
);
3108 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3110 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
3111 const struct dom_sid
*sid
)
3113 fstring key_str
, sid_string
;
3114 struct winbind_cache
*cache
;
3116 /* don't clear cached U/SID and UG/SID entries when we want to logon
3119 if (lp_winbind_offline_logon()) {
3126 cache
= get_cache(domain
);
3132 /* Clear U/SID cache entry */
3133 fstr_sprintf(key_str
, "U/%s", sid_to_fstring(sid_string
, sid
));
3134 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3135 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3137 /* Clear UG/SID cache entry */
3138 fstr_sprintf(key_str
, "UG/%s", sid_to_fstring(sid_string
, sid
));
3139 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3140 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3142 /* Samba/winbindd never needs this. */
3143 netsamlogon_clear_cached_user(sid
);
3146 bool wcache_invalidate_cache(void)
3148 struct winbindd_domain
*domain
;
3150 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3151 struct winbind_cache
*cache
= get_cache(domain
);
3153 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3154 "entries for %s\n", domain
->name
));
3157 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3166 bool wcache_invalidate_cache_noinit(void)
3168 struct winbindd_domain
*domain
;
3170 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3171 struct winbind_cache
*cache
;
3173 /* Skip uninitialized domains. */
3174 if (!domain
->initialized
&& !domain
->internal
) {
3178 cache
= get_cache(domain
);
3180 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3181 "entries for %s\n", domain
->name
));
3184 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3186 * Flushing cache has nothing to with domains.
3187 * return here if we successfully flushed once.
3188 * To avoid unnecessary traversing the cache.
3199 bool init_wcache(void)
3203 if (wcache
== NULL
) {
3204 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
3205 ZERO_STRUCTP(wcache
);
3208 if (wcache
->tdb
!= NULL
)
3211 db_path
= wcache_path();
3212 if (db_path
== NULL
) {
3216 /* when working offline we must not clear the cache on restart */
3217 wcache
->tdb
= tdb_open_log(db_path
,
3218 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3219 TDB_INCOMPATIBLE_HASH
|
3220 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3221 O_RDWR
|O_CREAT
, 0600);
3222 TALLOC_FREE(db_path
);
3223 if (wcache
->tdb
== NULL
) {
3224 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3231 /************************************************************************
3232 This is called by the parent to initialize the cache file.
3233 We don't need sophisticated locking here as we know we're the
3235 ************************************************************************/
3237 bool initialize_winbindd_cache(void)
3239 bool cache_bad
= true;
3242 if (!init_wcache()) {
3243 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3247 /* Check version number. */
3248 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
3249 vers
== WINBINDD_CACHE_VERSION
) {
3256 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3257 "and re-creating with version number %d\n",
3258 WINBINDD_CACHE_VERSION
));
3260 tdb_close(wcache
->tdb
);
3263 db_path
= wcache_path();
3264 if (db_path
== NULL
) {
3268 if (unlink(db_path
) == -1) {
3269 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3272 TALLOC_FREE(db_path
);
3275 TALLOC_FREE(db_path
);
3276 if (!init_wcache()) {
3277 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3278 "init_wcache failed.\n"));
3282 /* Write the version. */
3283 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
3284 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3285 tdb_errorstr(wcache
->tdb
) ));
3290 tdb_close(wcache
->tdb
);
3295 void close_winbindd_cache(void)
3301 tdb_close(wcache
->tdb
);
3306 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*sid
,
3307 char **domain_name
, char **name
,
3308 enum lsa_SidType
*type
)
3310 struct winbindd_domain
*domain
;
3313 domain
= find_lookup_domain_from_sid(sid
);
3314 if (domain
== NULL
) {
3317 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
3319 return NT_STATUS_IS_OK(status
);
3322 bool lookup_cached_name(const char *domain_name
,
3324 struct dom_sid
*sid
,
3325 enum lsa_SidType
*type
)
3327 struct winbindd_domain
*domain
;
3329 bool original_online_state
;
3331 domain
= find_lookup_domain_from_name(domain_name
);
3332 if (domain
== NULL
) {
3336 /* If we are doing a cached logon, temporarily set the domain
3337 offline so the cache won't expire the entry */
3339 original_online_state
= domain
->online
;
3340 domain
->online
= false;
3341 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
3342 domain
->online
= original_online_state
;
3344 return NT_STATUS_IS_OK(status
);
3348 * Cache a name to sid without checking the sequence number.
3349 * Used when caching from a trusted PAC.
3352 void cache_name2sid_trusted(struct winbindd_domain
*domain
,
3353 const char *domain_name
,
3355 enum lsa_SidType type
,
3356 const struct dom_sid
*sid
)
3359 * Ensure we store the mapping with the
3360 * existing sequence number from the cache.
3363 (void)fetch_cache_seqnum(domain
, time(NULL
));
3364 wcache_save_name_to_sid(domain
,
3372 void cache_name2sid(struct winbindd_domain
*domain
,
3373 const char *domain_name
, const char *name
,
3374 enum lsa_SidType type
, const struct dom_sid
*sid
)
3376 refresh_sequence_number(domain
);
3377 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
3382 * The original idea that this cache only contains centries has
3383 * been blurred - now other stuff gets put in here. Ensure we
3384 * ignore these things on cleanup.
3387 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
3388 TDB_DATA dbuf
, void *state
)
3390 struct cache_entry
*centry
;
3392 if (is_non_centry_key(kbuf
)) {
3396 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
3401 if (!NT_STATUS_IS_OK(centry
->status
)) {
3402 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
3403 tdb_delete(the_tdb
, kbuf
);
3406 centry_free(centry
);
3410 /* flush the cache */
3411 void wcache_flush_cache(void)
3418 tdb_close(wcache
->tdb
);
3421 if (!winbindd_use_cache()) {
3425 db_path
= wcache_path();
3426 if (db_path
== NULL
) {
3430 /* when working offline we must not clear the cache on restart */
3431 wcache
->tdb
= tdb_open_log(db_path
,
3432 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3433 TDB_INCOMPATIBLE_HASH
|
3434 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3435 O_RDWR
|O_CREAT
, 0600);
3436 TALLOC_FREE(db_path
);
3438 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3442 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
3444 DEBUG(10,("wcache_flush_cache success\n"));
3447 /* Count cached creds */
3449 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3452 int *cred_count
= (int*)state
;
3454 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3460 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
3462 struct winbind_cache
*cache
= get_cache(domain
);
3467 return NT_STATUS_INTERNAL_DB_ERROR
;
3470 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
3472 return NT_STATUS_OK
;
3476 struct cred_list
*prev
, *next
;
3481 static struct cred_list
*wcache_cred_list
;
3483 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3486 struct cred_list
*cred
;
3488 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3490 cred
= SMB_MALLOC_P(struct cred_list
);
3492 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3498 /* save a copy of the key */
3500 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
3501 DLIST_ADD(wcache_cred_list
, cred
);
3507 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
3509 struct winbind_cache
*cache
= get_cache(domain
);
3512 struct cred_list
*cred
, *next
, *oldest
= NULL
;
3515 return NT_STATUS_INTERNAL_DB_ERROR
;
3518 /* we possibly already have an entry */
3519 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
3521 fstring key_str
, tmp
;
3523 DEBUG(11,("we already have an entry, deleting that\n"));
3525 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
3527 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3529 return NT_STATUS_OK
;
3532 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
3534 return NT_STATUS_OK
;
3535 } else if ((ret
< 0) || (wcache_cred_list
== NULL
)) {
3536 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3539 ZERO_STRUCTP(oldest
);
3541 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
3546 data
= tdb_fetch(cache
->tdb
, string_tdb_data(cred
->name
));
3548 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3550 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3554 t
= IVAL(data
.dptr
, 0);
3555 SAFE_FREE(data
.dptr
);
3558 oldest
= SMB_MALLOC_P(struct cred_list
);
3559 if (oldest
== NULL
) {
3560 status
= NT_STATUS_NO_MEMORY
;
3564 fstrcpy(oldest
->name
, cred
->name
);
3565 oldest
->created
= t
;
3569 if (t
< oldest
->created
) {
3570 fstrcpy(oldest
->name
, cred
->name
);
3571 oldest
->created
= t
;
3575 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3576 status
= NT_STATUS_OK
;
3578 status
= NT_STATUS_UNSUCCESSFUL
;
3581 for (cred
= wcache_cred_list
; cred
; cred
= next
) {
3583 DLIST_REMOVE(wcache_cred_list
, cred
);
3591 /* Change the global online/offline state. */
3592 bool set_global_winbindd_state_offline(void)
3596 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3598 /* Only go offline if someone has created
3599 the key "WINBINDD_OFFLINE" in the cache tdb. */
3601 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3602 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3606 if (!lp_winbind_offline_logon()) {
3607 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3611 if (global_winbindd_offline_state
) {
3612 /* Already offline. */
3616 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
3618 if (!data
.dptr
|| data
.dsize
!= 4) {
3619 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3620 SAFE_FREE(data
.dptr
);
3623 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3624 global_winbindd_offline_state
= true;
3625 SAFE_FREE(data
.dptr
);
3630 void set_global_winbindd_state_online(void)
3632 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3634 if (!lp_winbind_offline_logon()) {
3635 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3639 if (!global_winbindd_offline_state
) {
3640 /* Already online. */
3643 global_winbindd_offline_state
= false;
3649 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3650 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3653 bool get_global_winbindd_state_offline(void)
3655 return global_winbindd_offline_state
;
3658 /***********************************************************************
3659 Validate functions for all possible cache tdb keys.
3660 ***********************************************************************/
3662 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3663 struct tdb_validation_status
*state
)
3665 struct cache_entry
*centry
;
3667 centry
= SMB_XMALLOC_P(struct cache_entry
);
3668 centry
->data
= (unsigned char *)smb_memdup(data
.dptr
, data
.dsize
);
3669 if (!centry
->data
) {
3673 centry
->len
= data
.dsize
;
3676 if (centry
->len
< 16) {
3677 /* huh? corrupt cache? */
3678 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3679 "(len < 16) ?\n", kstr
));
3680 centry_free(centry
);
3681 state
->bad_entry
= true;
3682 state
->success
= false;
3686 centry
->status
= NT_STATUS(centry_uint32(centry
));
3687 centry
->sequence_number
= centry_uint32(centry
);
3688 centry
->timeout
= centry_uint64_t(centry
);
3692 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3693 struct tdb_validation_status
*state
)
3695 if (dbuf
.dsize
!= 8) {
3696 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3697 keystr
, (unsigned int)dbuf
.dsize
));
3698 state
->bad_entry
= true;
3704 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3705 struct tdb_validation_status
*state
)
3707 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3712 (void)centry_uint32(centry
);
3713 if (NT_STATUS_IS_OK(centry
->status
)) {
3715 (void)centry_sid(centry
, &sid
);
3718 centry_free(centry
);
3720 if (!(state
->success
)) {
3723 DEBUG(10,("validate_ns: %s ok\n", keystr
));
3727 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3728 struct tdb_validation_status
*state
)
3730 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3735 if (NT_STATUS_IS_OK(centry
->status
)) {
3736 (void)centry_uint32(centry
);
3737 (void)centry_string(centry
, mem_ctx
);
3738 (void)centry_string(centry
, mem_ctx
);
3741 centry_free(centry
);
3743 if (!(state
->success
)) {
3746 DEBUG(10,("validate_sn: %s ok\n", keystr
));
3750 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3751 struct tdb_validation_status
*state
)
3753 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3760 (void)centry_string(centry
, mem_ctx
);
3761 (void)centry_string(centry
, mem_ctx
);
3762 (void)centry_string(centry
, mem_ctx
);
3763 (void)centry_string(centry
, mem_ctx
);
3764 (void)centry_uint32(centry
);
3765 (void)centry_sid(centry
, &sid
);
3766 (void)centry_sid(centry
, &sid
);
3768 centry_free(centry
);
3770 if (!(state
->success
)) {
3773 DEBUG(10,("validate_u: %s ok\n", keystr
));
3777 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3778 struct tdb_validation_status
*state
)
3780 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3786 (void)centry_nttime(centry
);
3787 (void)centry_nttime(centry
);
3788 (void)centry_uint16(centry
);
3790 centry_free(centry
);
3792 if (!(state
->success
)) {
3795 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3799 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3800 struct tdb_validation_status
*state
)
3802 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3808 (void)centry_uint16(centry
);
3809 (void)centry_uint16(centry
);
3810 (void)centry_uint32(centry
);
3811 (void)centry_nttime(centry
);
3812 (void)centry_nttime(centry
);
3814 centry_free(centry
);
3816 if (!(state
->success
)) {
3819 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3823 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3824 struct tdb_validation_status
*state
)
3826 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3832 (void)centry_time(centry
);
3833 (void)centry_hash16(centry
, mem_ctx
);
3835 /* We only have 17 bytes more data in the salted cred case. */
3836 if (centry
->len
- centry
->ofs
== 17) {
3837 (void)centry_hash16(centry
, mem_ctx
);
3840 centry_free(centry
);
3842 if (!(state
->success
)) {
3845 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3849 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3850 struct tdb_validation_status
*state
)
3852 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3853 int32_t num_entries
, i
;
3859 num_entries
= (int32_t)centry_uint32(centry
);
3861 for (i
=0; i
< num_entries
; i
++) {
3863 (void)centry_string(centry
, mem_ctx
);
3864 (void)centry_string(centry
, mem_ctx
);
3865 (void)centry_string(centry
, mem_ctx
);
3866 (void)centry_string(centry
, mem_ctx
);
3867 (void)centry_sid(centry
, &sid
);
3868 (void)centry_sid(centry
, &sid
);
3871 centry_free(centry
);
3873 if (!(state
->success
)) {
3876 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3880 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3881 struct tdb_validation_status
*state
)
3883 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3884 int32_t num_entries
, i
;
3890 num_entries
= centry_uint32(centry
);
3892 for (i
=0; i
< num_entries
; i
++) {
3893 (void)centry_string(centry
, mem_ctx
);
3894 (void)centry_string(centry
, mem_ctx
);
3895 (void)centry_uint32(centry
);
3898 centry_free(centry
);
3900 if (!(state
->success
)) {
3903 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3907 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3908 struct tdb_validation_status
*state
)
3910 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3911 int32_t num_groups
, i
;
3917 num_groups
= centry_uint32(centry
);
3919 for (i
=0; i
< num_groups
; i
++) {
3921 centry_sid(centry
, &sid
);
3924 centry_free(centry
);
3926 if (!(state
->success
)) {
3929 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3933 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3934 struct tdb_validation_status
*state
)
3936 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3937 int32_t num_aliases
, i
;
3943 num_aliases
= centry_uint32(centry
);
3945 for (i
=0; i
< num_aliases
; i
++) {
3946 (void)centry_uint32(centry
);
3949 centry_free(centry
);
3951 if (!(state
->success
)) {
3954 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3958 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3959 struct tdb_validation_status
*state
)
3961 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3962 int32_t num_names
, i
;
3968 num_names
= centry_uint32(centry
);
3970 for (i
=0; i
< num_names
; i
++) {
3972 centry_sid(centry
, &sid
);
3973 (void)centry_string(centry
, mem_ctx
);
3974 (void)centry_uint32(centry
);
3977 centry_free(centry
);
3979 if (!(state
->success
)) {
3982 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3986 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3987 struct tdb_validation_status
*state
)
3989 /* Can't say anything about this other than must be nonzero. */
3990 if (dbuf
.dsize
== 0) {
3991 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3993 state
->bad_entry
= true;
3994 state
->success
= false;
3998 DEBUG(10,("validate_dr: %s ok\n", keystr
));
4002 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
4003 struct tdb_validation_status
*state
)
4005 /* Can't say anything about this other than must be nonzero. */
4006 if (dbuf
.dsize
== 0) {
4007 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
4009 state
->bad_entry
= true;
4010 state
->success
= false;
4014 DEBUG(10,("validate_de: %s ok\n", keystr
));
4018 static int validate_pwinfo(TALLOC_CTX
*mem_ctx
, const char *keystr
,
4019 TDB_DATA dbuf
, struct tdb_validation_status
*state
)
4021 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
4027 (void)centry_string(centry
, mem_ctx
);
4028 (void)centry_string(centry
, mem_ctx
);
4029 (void)centry_string(centry
, mem_ctx
);
4030 (void)centry_uint32(centry
);
4032 centry_free(centry
);
4034 if (!(state
->success
)) {
4037 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
4041 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
4043 struct tdb_validation_status
*state
)
4045 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
4051 (void)centry_string( centry
, mem_ctx
);
4053 centry_free(centry
);
4055 if (!(state
->success
)) {
4058 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
4062 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
4064 struct tdb_validation_status
*state
)
4066 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
4072 (void)centry_string( centry
, mem_ctx
);
4074 centry_free(centry
);
4076 if (!(state
->success
)) {
4079 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
4083 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
4085 struct tdb_validation_status
*state
)
4087 if (dbuf
.dsize
== 0) {
4088 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
4089 "key %s (len ==0) ?\n", keystr
));
4090 state
->bad_entry
= true;
4091 state
->success
= false;
4095 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
4096 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
4100 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
4101 struct tdb_validation_status
*state
)
4103 if (dbuf
.dsize
!= 4) {
4104 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
4105 keystr
, (unsigned int)dbuf
.dsize
));
4106 state
->bad_entry
= true;
4107 state
->success
= false;
4110 DEBUG(10,("validate_offline: %s ok\n", keystr
));
4114 static int validate_ndr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
4115 struct tdb_validation_status
*state
)
4118 * Ignore validation for now. The proper way to do this is with a
4119 * checksum. Just pure parsing does not really catch much.
4124 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
4125 struct tdb_validation_status
*state
)
4127 if (dbuf
.dsize
!= 4) {
4128 DEBUG(0, ("validate_cache_version: Corrupt cache for "
4129 "key %s (len %u != 4) ?\n",
4130 keystr
, (unsigned int)dbuf
.dsize
));
4131 state
->bad_entry
= true;
4132 state
->success
= false;
4136 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
4140 /***********************************************************************
4141 A list of all possible cache tdb keys with associated validation
4143 ***********************************************************************/
4145 struct key_val_struct
{
4146 const char *keyname
;
4147 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
4149 {"SEQNUM/", validate_seqnum
},
4150 {"NS/", validate_ns
},
4151 {"SN/", validate_sn
},
4153 {"LOC_POL/", validate_loc_pol
},
4154 {"PWD_POL/", validate_pwd_pol
},
4155 {"CRED/", validate_cred
},
4156 {"UL/", validate_ul
},
4157 {"GL/", validate_gl
},
4158 {"UG/", validate_ug
},
4159 {"UA", validate_ua
},
4160 {"GM/", validate_gm
},
4161 {"DR/", validate_dr
},
4162 {"DE/", validate_de
},
4163 {"NSS/PWINFO/", validate_pwinfo
},
4164 {"TRUSTDOMCACHE/", validate_trustdomcache
},
4165 {"NSS/NA/", validate_nss_na
},
4166 {"NSS/AN/", validate_nss_an
},
4167 {"WINBINDD_OFFLINE", validate_offline
},
4168 {"NDR/", validate_ndr
},
4169 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
4173 /***********************************************************************
4174 Function to look at every entry in the tdb and validate it as far as
4176 ***********************************************************************/
4178 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
4181 unsigned int max_key_len
= 1024;
4182 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
4184 /* Paranoia check. */
4185 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0 ||
4186 strncmp("NDR/", (const char *)kbuf
.dptr
, 4) == 0) {
4187 max_key_len
= 1024 * 1024;
4189 if (kbuf
.dsize
> max_key_len
) {
4190 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4192 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
4196 for (i
= 0; key_val
[i
].keyname
; i
++) {
4197 size_t namelen
= strlen(key_val
[i
].keyname
);
4198 if (kbuf
.dsize
>= namelen
&& (
4199 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
4200 TALLOC_CTX
*mem_ctx
;
4204 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
4208 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
4209 keystr
[kbuf
.dsize
] = '\0';
4211 mem_ctx
= talloc_init("validate_ctx");
4217 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
4221 talloc_destroy(mem_ctx
);
4226 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4227 dump_data(0, (uint8_t *)kbuf
.dptr
, kbuf
.dsize
);
4228 DEBUG(0,("data :\n"));
4229 dump_data(0, (uint8_t *)dbuf
.dptr
, dbuf
.dsize
);
4230 v_state
->unknown_key
= true;
4231 v_state
->success
= false;
4232 return 1; /* terminate. */
4235 static void validate_panic(const char *const why
)
4237 DEBUG(0,("validating cache: would panic %s\n", why
));
4238 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4242 static int wbcache_update_centry_fn(TDB_CONTEXT
*tdb
,
4250 if (is_non_centry_key(key
)) {
4254 if (data
.dptr
== NULL
|| data
.dsize
== 0) {
4255 if (tdb_delete(tdb
, key
) < 0) {
4256 DEBUG(0, ("tdb_delete for [%s] failed!\n",
4262 /* add timeout to blob (uint64_t) */
4263 blob
.dsize
= data
.dsize
+ 8;
4265 blob
.dptr
= SMB_XMALLOC_ARRAY(uint8_t, blob
.dsize
);
4266 if (blob
.dptr
== NULL
) {
4269 memset(blob
.dptr
, 0, blob
.dsize
);
4271 /* copy status and seqnum */
4272 memcpy(blob
.dptr
, data
.dptr
, 8);
4275 ctimeout
= lp_winbind_cache_time() + time(NULL
);
4276 SBVAL(blob
.dptr
, 8, ctimeout
);
4279 memcpy(blob
.dptr
+ 16, data
.dptr
+ 8, data
.dsize
- 8);
4281 if (tdb_store(tdb
, key
, blob
, TDB_REPLACE
) < 0) {
4282 DEBUG(0, ("tdb_store to update [%s] failed!\n",
4284 SAFE_FREE(blob
.dptr
);
4288 SAFE_FREE(blob
.dptr
);
4292 static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT
*tdb
)
4296 DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
4298 rc
= tdb_traverse(tdb
, wbcache_update_centry_fn
, NULL
);
4306 /***********************************************************************
4307 Try and validate every entry in the winbindd cache. If we fail here,
4308 delete the cache tdb and return non-zero.
4309 ***********************************************************************/
4311 int winbindd_validate_cache(void)
4314 char *tdb_path
= NULL
;
4315 TDB_CONTEXT
*tdb
= NULL
;
4319 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4320 smb_panic_fn
= validate_panic
;
4322 tdb_path
= wcache_path();
4323 if (tdb_path
== NULL
) {
4327 tdb
= tdb_open_log(tdb_path
,
4328 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
4329 TDB_INCOMPATIBLE_HASH
|
4330 ( lp_winbind_offline_logon()
4332 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
4336 DEBUG(0, ("winbindd_validate_cache: "
4337 "error opening/initializing tdb\n"));
4341 /* Version check and upgrade code. */
4342 if (!tdb_fetch_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers_id
)) {
4343 DEBUG(10, ("Fresh database\n"));
4344 tdb_store_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
);
4345 vers_id
= WINBINDD_CACHE_VERSION
;
4348 if (vers_id
!= WINBINDD_CACHE_VERSION
) {
4349 if (vers_id
== WINBINDD_CACHE_VER1
) {
4350 ok
= wbcache_upgrade_v1_to_v2(tdb
);
4352 DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
4357 tdb_store_uint32(tdb
,
4358 WINBINDD_CACHE_VERSION_KEYSTR
,
4359 WINBINDD_CACHE_VERSION
);
4360 vers_id
= WINBINDD_CACHE_VER2
;
4366 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
4369 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4370 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
4375 TALLOC_FREE(tdb_path
);
4376 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4377 smb_panic_fn
= smb_panic
;
4381 /***********************************************************************
4382 Try and validate every entry in the winbindd cache.
4383 ***********************************************************************/
4385 int winbindd_validate_cache_nobackup(void)
4390 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4391 smb_panic_fn
= validate_panic
;
4393 tdb_path
= wcache_path();
4394 if (tdb_path
== NULL
) {
4395 goto err_panic_restore
;
4398 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
4399 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
4401 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
4405 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4409 TALLOC_FREE(tdb_path
);
4411 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4413 smb_panic_fn
= smb_panic
;
4417 bool winbindd_cache_validate_and_initialize(void)
4419 close_winbindd_cache();
4421 if (lp_winbind_offline_logon()) {
4422 if (winbindd_validate_cache() < 0) {
4423 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4424 "could be restored.\n"));
4428 return initialize_winbindd_cache();
4431 /*********************************************************************
4432 ********************************************************************/
4434 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
4435 struct winbindd_tdc_domain
**domains
,
4436 size_t *num_domains
)
4438 struct winbindd_tdc_domain
*list
= NULL
;
4441 bool set_only
= false;
4443 /* don't allow duplicates */
4448 for ( i
=0; i
< (*num_domains
); i
++ ) {
4449 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
4450 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4461 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, 1 );
4464 list
= talloc_realloc( *domains
, *domains
,
4465 struct winbindd_tdc_domain
,
4470 ZERO_STRUCT( list
[idx
] );
4476 list
[idx
].domain_name
= talloc_strdup(list
, new_dom
->name
);
4477 if (list
[idx
].domain_name
== NULL
) {
4480 if (new_dom
->alt_name
!= NULL
) {
4481 list
[idx
].dns_name
= talloc_strdup(list
, new_dom
->alt_name
);
4482 if (list
[idx
].dns_name
== NULL
) {
4487 if ( !is_null_sid( &new_dom
->sid
) ) {
4488 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
4490 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
4493 if ( new_dom
->domain_flags
!= 0x0 )
4494 list
[idx
].trust_flags
= new_dom
->domain_flags
;
4496 if ( new_dom
->domain_type
!= 0x0 )
4497 list
[idx
].trust_type
= new_dom
->domain_type
;
4499 if ( new_dom
->domain_trust_attribs
!= 0x0 )
4500 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
4504 *num_domains
= idx
+ 1;
4510 /*********************************************************************
4511 ********************************************************************/
4513 static TDB_DATA
make_tdc_key( const char *domain_name
)
4515 char *keystr
= NULL
;
4516 TDB_DATA key
= { NULL
, 0 };
4518 if ( !domain_name
) {
4519 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4523 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
4526 key
= string_term_tdb_data(keystr
);
4531 /*********************************************************************
4532 ********************************************************************/
4534 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
4536 unsigned char **buf
)
4538 unsigned char *buffer
= NULL
;
4543 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4551 /* Store the number of array items first */
4552 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
4555 /* now pack each domain trust record */
4556 for ( i
=0; i
<num_domains
; i
++ ) {
4561 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4562 domains
[i
].domain_name
,
4563 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
4566 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
4567 domains
[i
].domain_name
,
4568 domains
[i
].dns_name
? domains
[i
].dns_name
: "",
4569 sid_to_fstring(tmp
, &domains
[i
].sid
),
4570 domains
[i
].trust_flags
,
4571 domains
[i
].trust_attribs
,
4572 domains
[i
].trust_type
);
4575 if ( buflen
< len
) {
4577 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
4578 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4592 /*********************************************************************
4593 ********************************************************************/
4595 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
4596 struct winbindd_tdc_domain
**domains
)
4598 fstring domain_name
, dns_name
, sid_string
;
4599 uint32_t type
, attribs
, flags
;
4603 struct winbindd_tdc_domain
*list
= NULL
;
4605 /* get the number of domains */
4606 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
4608 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4612 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, num_domains
);
4614 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4618 for ( i
=0; i
<num_domains
; i
++ ) {
4621 this_len
= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
4629 if ( this_len
== -1 ) {
4630 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4631 TALLOC_FREE( list
);
4636 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4637 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4638 domain_name
, dns_name
, sid_string
,
4639 flags
, attribs
, type
));
4641 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
4642 list
[i
].dns_name
= NULL
;
4643 if (dns_name
[0] != '\0') {
4644 list
[i
].dns_name
= talloc_strdup(list
, dns_name
);
4646 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
4647 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4650 list
[i
].trust_flags
= flags
;
4651 list
[i
].trust_attribs
= attribs
;
4652 list
[i
].trust_type
= type
;
4660 /*********************************************************************
4661 ********************************************************************/
4663 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
4665 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4666 TDB_DATA data
= { NULL
, 0 };
4672 /* See if we were asked to delete the cache entry */
4675 ret
= tdb_delete( wcache
->tdb
, key
);
4679 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4686 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4689 SAFE_FREE( data
.dptr
);
4690 SAFE_FREE( key
.dptr
);
4692 return ( ret
== 0 );
4695 /*********************************************************************
4696 ********************************************************************/
4698 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4700 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4701 TDB_DATA data
= { NULL
, 0 };
4709 data
= tdb_fetch( wcache
->tdb
, key
);
4711 SAFE_FREE( key
.dptr
);
4716 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4718 SAFE_FREE( data
.dptr
);
4726 /*********************************************************************
4727 ********************************************************************/
4729 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4731 struct winbindd_tdc_domain
*dom_list
= NULL
;
4732 size_t num_domains
= 0;
4735 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4736 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4737 domain
->name
, domain
->alt_name
,
4738 sid_string_dbg(&domain
->sid
),
4739 domain
->domain_flags
,
4740 domain
->domain_trust_attribs
,
4741 domain
->domain_type
));
4743 if ( !init_wcache() ) {
4747 /* fetch the list */
4749 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4751 /* add the new domain */
4753 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4757 /* pack the domain */
4759 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4767 TALLOC_FREE( dom_list
);
4772 static struct winbindd_tdc_domain
*wcache_tdc_dup_domain(
4773 TALLOC_CTX
*mem_ctx
, const struct winbindd_tdc_domain
*src
)
4775 struct winbindd_tdc_domain
*dst
;
4777 dst
= talloc(mem_ctx
, struct winbindd_tdc_domain
);
4781 dst
->domain_name
= talloc_strdup(dst
, src
->domain_name
);
4782 if (dst
->domain_name
== NULL
) {
4786 dst
->dns_name
= NULL
;
4787 if (src
->dns_name
!= NULL
) {
4788 dst
->dns_name
= talloc_strdup(dst
, src
->dns_name
);
4789 if (dst
->dns_name
== NULL
) {
4794 sid_copy(&dst
->sid
, &src
->sid
);
4795 dst
->trust_flags
= src
->trust_flags
;
4796 dst
->trust_type
= src
->trust_type
;
4797 dst
->trust_attribs
= src
->trust_attribs
;
4804 /*********************************************************************
4805 ********************************************************************/
4807 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4809 struct winbindd_tdc_domain
*dom_list
= NULL
;
4810 size_t num_domains
= 0;
4812 struct winbindd_tdc_domain
*d
= NULL
;
4814 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4816 if ( !init_wcache() ) {
4820 /* fetch the list */
4822 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4824 for ( i
=0; i
<num_domains
; i
++ ) {
4825 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4826 strequal(name
, dom_list
[i
].dns_name
) )
4828 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4831 d
= wcache_tdc_dup_domain(ctx
, &dom_list
[i
]);
4836 TALLOC_FREE( dom_list
);
4841 /*********************************************************************
4842 ********************************************************************/
4844 struct winbindd_tdc_domain
*
4845 wcache_tdc_fetch_domainbysid(TALLOC_CTX
*ctx
,
4846 const struct dom_sid
*sid
)
4848 struct winbindd_tdc_domain
*dom_list
= NULL
;
4849 size_t num_domains
= 0;
4851 struct winbindd_tdc_domain
*d
= NULL
;
4853 DEBUG(10,("wcache_tdc_fetch_domainbysid: Searching for domain %s\n",
4854 sid_string_dbg(sid
)));
4856 if (!init_wcache()) {
4860 /* fetch the list */
4862 wcache_tdc_fetch_list(&dom_list
, &num_domains
);
4864 for (i
= 0; i
<num_domains
; i
++) {
4865 if (dom_sid_equal(sid
, &(dom_list
[i
].sid
))) {
4866 DEBUG(10, ("wcache_tdc_fetch_domainbysid: "
4867 "Found domain %s for SID %s\n",
4868 dom_list
[i
].domain_name
,
4869 sid_string_dbg(sid
)));
4871 d
= wcache_tdc_dup_domain(ctx
, &dom_list
[i
]);
4876 TALLOC_FREE(dom_list
);
4882 /*********************************************************************
4883 ********************************************************************/
4885 void wcache_tdc_clear( void )
4887 if ( !init_wcache() )
4890 wcache_tdc_store_list( NULL
, 0 );
4896 /*********************************************************************
4897 ********************************************************************/
4899 static void wcache_save_user_pwinfo(struct winbindd_domain
*domain
,
4901 const struct dom_sid
*user_sid
,
4902 const char *homedir
,
4907 struct cache_entry
*centry
;
4910 if ( (centry
= centry_start(domain
, status
)) == NULL
)
4913 centry_put_string( centry
, homedir
);
4914 centry_put_string( centry
, shell
);
4915 centry_put_string( centry
, gecos
);
4916 centry_put_uint32( centry
, gid
);
4918 centry_end(centry
, "NSS/PWINFO/%s", sid_to_fstring(tmp
, user_sid
) );
4920 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid
) ));
4922 centry_free(centry
);
4927 NTSTATUS
nss_get_info_cached( struct winbindd_domain
*domain
,
4928 const struct dom_sid
*user_sid
,
4930 const char **homedir
, const char **shell
,
4931 const char **gecos
, gid_t
*p_gid
)
4933 struct winbind_cache
*cache
= get_cache(domain
);
4934 struct cache_entry
*centry
= NULL
;
4941 centry
= wcache_fetch(cache
, domain
, "NSS/PWINFO/%s",
4942 sid_to_fstring(tmp
, user_sid
));
4947 *homedir
= centry_string( centry
, ctx
);
4948 *shell
= centry_string( centry
, ctx
);
4949 *gecos
= centry_string( centry
, ctx
);
4950 *p_gid
= centry_uint32( centry
);
4952 centry_free(centry
);
4954 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4955 sid_string_dbg(user_sid
)));
4957 return NT_STATUS_OK
;
4961 nt_status
= nss_get_info( domain
->name
, user_sid
, ctx
,
4962 homedir
, shell
, gecos
, p_gid
);
4964 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status
)));
4966 if ( NT_STATUS_IS_OK(nt_status
) ) {
4967 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir
));
4968 DEBUGADD(10, ("\tshell = '%s'\n", *shell
));
4969 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos
));
4970 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid
));
4972 wcache_save_user_pwinfo( domain
, nt_status
, user_sid
,
4973 *homedir
, *shell
, *gecos
, *p_gid
);
4976 if ( NT_STATUS_EQUAL( nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
4977 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4979 set_domain_offline( domain
);
4987 static bool wcache_ndr_key(TALLOC_CTX
*mem_ctx
, const char *domain_name
,
4988 uint32_t opnum
, const DATA_BLOB
*req
,
4994 key
= talloc_asprintf(mem_ctx
, "NDR/%s/%d/", domain_name
, (int)opnum
);
4998 keylen
= talloc_get_size(key
) - 1;
5000 key
= talloc_realloc(mem_ctx
, key
, char, keylen
+ req
->length
);
5004 memcpy(key
+ keylen
, req
->data
, req
->length
);
5006 pkey
->dptr
= (uint8_t *)key
;
5007 pkey
->dsize
= talloc_get_size(key
);
5011 static bool wcache_opnum_cacheable(uint32_t opnum
)
5014 case NDR_WBINT_PING
:
5015 case NDR_WBINT_QUERYSEQUENCENUMBER
:
5016 case NDR_WBINT_ALLOCATEUID
:
5017 case NDR_WBINT_ALLOCATEGID
:
5018 case NDR_WBINT_CHECKMACHINEACCOUNT
:
5019 case NDR_WBINT_CHANGEMACHINEACCOUNT
:
5020 case NDR_WBINT_PINGDC
:
5026 bool wcache_fetch_ndr(TALLOC_CTX
*mem_ctx
, struct winbindd_domain
*domain
,
5027 uint32_t opnum
, const DATA_BLOB
*req
, DATA_BLOB
*resp
)
5032 if (!wcache_opnum_cacheable(opnum
) ||
5033 is_my_own_sam_domain(domain
) ||
5034 is_builtin_domain(domain
)) {
5038 if (wcache
->tdb
== NULL
) {
5042 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
5045 data
= tdb_fetch(wcache
->tdb
, key
);
5046 TALLOC_FREE(key
.dptr
);
5048 if (data
.dptr
== NULL
) {
5051 if (data
.dsize
< 12) {
5055 if (!is_domain_offline(domain
)) {
5056 uint32_t entry_seqnum
, dom_seqnum
, last_check
;
5057 uint64_t entry_timeout
;
5059 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
,
5063 entry_seqnum
= IVAL(data
.dptr
, 0);
5064 if (entry_seqnum
!= dom_seqnum
) {
5065 DEBUG(10, ("Entry has wrong sequence number: %d\n",
5066 (int)entry_seqnum
));
5069 entry_timeout
= BVAL(data
.dptr
, 4);
5070 if (time(NULL
) > entry_timeout
) {
5071 DEBUG(10, ("Entry has timed out\n"));
5076 resp
->data
= (uint8_t *)talloc_memdup(mem_ctx
, data
.dptr
+ 12,
5078 if (resp
->data
== NULL
) {
5079 DEBUG(10, ("talloc failed\n"));
5082 resp
->length
= data
.dsize
- 12;
5086 SAFE_FREE(data
.dptr
);
5090 void wcache_store_ndr(struct winbindd_domain
*domain
, uint32_t opnum
,
5091 const DATA_BLOB
*req
, const DATA_BLOB
*resp
)
5094 uint32_t dom_seqnum
, last_check
;
5097 if (!wcache_opnum_cacheable(opnum
) ||
5098 is_my_own_sam_domain(domain
) ||
5099 is_builtin_domain(domain
)) {
5103 if (wcache
->tdb
== NULL
) {
5107 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
, &last_check
)) {
5108 DEBUG(10, ("could not fetch seqnum for domain %s\n",
5113 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
5117 timeout
= time(NULL
) + lp_winbind_cache_time();
5119 data
.dsize
= resp
->length
+ 12;
5120 data
.dptr
= talloc_array(key
.dptr
, uint8_t, data
.dsize
);
5121 if (data
.dptr
== NULL
) {
5125 SIVAL(data
.dptr
, 0, dom_seqnum
);
5126 SBVAL(data
.dptr
, 4, timeout
);
5127 memcpy(data
.dptr
+ 12, resp
->data
, resp
->length
);
5129 tdb_store(wcache
->tdb
, key
, data
, 0);
5132 TALLOC_FREE(key
.dptr
);