2 Unix SMB/CIFS implementation.
4 Winbind cache backend functions
6 Copyright (C) Andrew Tridgell 2001
7 Copyright (C) Gerald Carter 2003-2007
8 Copyright (C) Volker Lendecke 2005
9 Copyright (C) Guenther Deschner 2005
10 Copyright (C) Michael Adam 2007
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include "system/filesys.h"
29 #include "tdb_validate.h"
30 #include "../libcli/auth/libcli_auth.h"
31 #include "../librpc/gen_ndr/ndr_winbind.h"
34 #include "../libcli/security/security.h"
35 #include "passdb/machine_sid.h"
37 #include "libsmb/samlogon_cache.h"
38 #include "lib/namemap_cache.h"
40 #include "lib/crypto/gnutls_helpers.h"
41 #include <gnutls/crypto.h>
44 #define DBGC_CLASS DBGC_WINBIND
46 #define WINBINDD_CACHE_VER1 1 /* initial db version */
47 #define WINBINDD_CACHE_VER2 2 /* second version with timeouts for NDR entries */
49 #define WINBINDD_CACHE_VERSION WINBINDD_CACHE_VER2
50 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
52 extern struct winbindd_methods reconnect_methods
;
54 extern struct winbindd_methods reconnect_ads_methods
;
56 extern struct winbindd_methods builtin_passdb_methods
;
57 extern struct winbindd_methods sam_passdb_methods
;
59 static void wcache_flush_cache(void);
62 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
63 * Here are the list of entry types that are *not* stored
64 * as form struct cache_entry in the cache.
67 static const char *non_centry_keys
[] = {
70 WINBINDD_CACHE_VERSION_KEYSTR
,
74 /************************************************************************
75 Is this key a non-centry type ?
76 ************************************************************************/
78 static bool is_non_centry_key(TDB_DATA kbuf
)
82 if (kbuf
.dptr
== NULL
|| kbuf
.dsize
== 0) {
85 for (i
= 0; non_centry_keys
[i
] != NULL
; i
++) {
86 size_t namelen
= strlen(non_centry_keys
[i
]);
87 if (kbuf
.dsize
< namelen
) {
90 if (strncmp(non_centry_keys
[i
], (const char *)kbuf
.dptr
, namelen
) == 0) {
97 /* Global online/offline state - False when online. winbindd starts up online
98 and sets this to true if the first query fails and there's an entry in
99 the cache tdb telling us to stay offline. */
101 static bool global_winbindd_offline_state
;
103 struct winbind_cache
{
109 uint32_t sequence_number
;
115 void (*smb_panic_fn
)(const char *const why
) = smb_panic
;
117 static struct winbind_cache
*wcache
;
119 static char *wcache_path(void)
122 * Data needs to be kept persistent in state directory for
123 * running with "winbindd offline logon".
125 return state_path(talloc_tos(), "winbindd_cache.tdb");
128 static void winbindd_domain_init_backend(struct winbindd_domain
*domain
)
130 if (domain
->backend
!= NULL
) {
134 if (domain
->internal
) {
135 domain
->backend
= &builtin_passdb_methods
;
138 if (dom_sid_equal(&domain
->sid
, &global_sid_Builtin
)) {
139 domain
->initialized
= true;
142 if (strequal(domain
->name
, get_global_sam_name()) &&
143 sid_check_is_our_sam(&domain
->sid
))
145 domain
->backend
= &sam_passdb_methods
;
148 if (!domain
->initialized
) {
149 /* We do not need a connection to an RW DC for cache operation */
150 init_dc_connection(domain
, false);
154 if (domain
->backend
== NULL
) {
155 struct winbindd_domain
*our_domain
= domain
;
157 /* find our domain first so we can figure out if we
158 are joined to a kerberized domain */
160 if (!domain
->primary
) {
161 our_domain
= find_our_domain();
164 if ((our_domain
->active_directory
|| IS_DC
)
165 && domain
->active_directory
166 && !lp_winbind_rpc_only())
168 DBG_INFO("Setting ADS methods for domain %s\n",
170 domain
->backend
= &reconnect_ads_methods
;
173 #endif /* HAVE_ADS */
175 if (domain
->backend
== NULL
) {
176 DBG_INFO("Setting MS-RPC methods for domain %s\n", domain
->name
);
177 domain
->backend
= &reconnect_methods
;
181 /* get the winbind_cache structure */
182 static struct winbind_cache
*get_cache(struct winbindd_domain
*domain
)
184 struct winbind_cache
*ret
= wcache
;
186 winbindd_domain_init_backend(domain
);
192 ret
= SMB_XMALLOC_P(struct winbind_cache
);
196 wcache_flush_cache();
202 free a centry structure
204 static void centry_free(struct cache_entry
*centry
)
208 SAFE_FREE(centry
->data
);
212 static bool centry_check_bytes(struct cache_entry
*centry
, size_t nbytes
)
214 if (centry
->len
- centry
->ofs
< nbytes
) {
215 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
216 (unsigned int)nbytes
,
217 centry
->len
- centry
->ofs
));
224 pull a uint64_t from a cache entry
226 static uint64_t centry_uint64_t(struct cache_entry
*centry
)
230 if (!centry_check_bytes(centry
, 8)) {
231 smb_panic_fn("centry_uint64_t");
233 ret
= BVAL(centry
->data
, centry
->ofs
);
239 pull a uint32_t from a cache entry
241 static uint32_t centry_uint32(struct cache_entry
*centry
)
245 if (!centry_check_bytes(centry
, 4)) {
246 smb_panic_fn("centry_uint32");
248 ret
= IVAL(centry
->data
, centry
->ofs
);
254 pull a uint16_t from a cache entry
256 static uint16_t centry_uint16(struct cache_entry
*centry
)
259 if (!centry_check_bytes(centry
, 2)) {
260 smb_panic_fn("centry_uint16");
262 ret
= SVAL(centry
->data
, centry
->ofs
);
268 pull a uint8_t from a cache entry
270 static uint8_t centry_uint8(struct cache_entry
*centry
)
273 if (!centry_check_bytes(centry
, 1)) {
274 smb_panic_fn("centry_uint8");
276 ret
= CVAL(centry
->data
, centry
->ofs
);
282 pull a NTTIME from a cache entry
284 static NTTIME
centry_nttime(struct cache_entry
*centry
)
287 if (!centry_check_bytes(centry
, 8)) {
288 smb_panic_fn("centry_nttime");
290 ret
= IVAL(centry
->data
, centry
->ofs
);
292 ret
+= (uint64_t)IVAL(centry
->data
, centry
->ofs
) << 32;
298 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
300 static time_t centry_time(struct cache_entry
*centry
)
302 return (time_t)centry_nttime(centry
);
305 /* pull a string from a cache entry, using the supplied
308 static char *centry_string(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
313 len
= centry_uint8(centry
);
316 /* a deliberate NULL string */
320 if (!centry_check_bytes(centry
, (size_t)len
)) {
321 smb_panic_fn("centry_string");
324 ret
= talloc_array(mem_ctx
, char, len
+1);
326 smb_panic_fn("centry_string out of memory\n");
328 memcpy(ret
,centry
->data
+ centry
->ofs
, len
);
334 /* pull a hash16 from a cache entry, using the supplied
337 static char *centry_hash16(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
342 len
= centry_uint8(centry
);
345 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
350 if (!centry_check_bytes(centry
, 16)) {
354 ret
= talloc_array(mem_ctx
, char, 16);
356 smb_panic_fn("centry_hash out of memory\n");
358 memcpy(ret
,centry
->data
+ centry
->ofs
, 16);
363 /* pull a sid from a cache entry, using the supplied
366 static bool centry_sid(struct cache_entry
*centry
, struct dom_sid
*sid
)
371 sid_string
= centry_string(centry
, talloc_tos());
372 if (sid_string
== NULL
) {
375 ret
= string_to_sid(sid
, sid_string
);
376 TALLOC_FREE(sid_string
);
382 pull a NTSTATUS from a cache entry
384 static NTSTATUS
centry_ntstatus(struct cache_entry
*centry
)
388 status
= NT_STATUS(centry_uint32(centry
));
393 /* the server is considered down if it can't give us a sequence number */
394 static bool wcache_server_down(struct winbindd_domain
*domain
)
401 ret
= (domain
->sequence_number
== DOM_SEQUENCE_NONE
);
404 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
409 struct wcache_seqnum_state
{
411 uint32_t *last_seq_check
;
414 static int wcache_seqnum_parser(TDB_DATA key
, TDB_DATA data
,
417 struct wcache_seqnum_state
*state
= private_data
;
419 if (data
.dsize
!= 8) {
420 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
425 *state
->seqnum
= IVAL(data
.dptr
, 0);
426 *state
->last_seq_check
= IVAL(data
.dptr
, 4);
430 static bool wcache_fetch_seqnum(const char *domain_name
, uint32_t *seqnum
,
431 uint32_t *last_seq_check
)
433 struct wcache_seqnum_state state
= {
434 .seqnum
= seqnum
, .last_seq_check
= last_seq_check
436 size_t len
= strlen(domain_name
);
438 TDB_DATA key
= { .dptr
= (uint8_t *)keystr
, .dsize
= sizeof(keystr
) };
441 if (wcache
->tdb
== NULL
) {
442 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
446 snprintf(keystr
, sizeof(keystr
), "SEQNUM/%s", domain_name
);
448 ret
= tdb_parse_record(wcache
->tdb
, key
, wcache_seqnum_parser
,
453 static NTSTATUS
fetch_cache_seqnum( struct winbindd_domain
*domain
, time_t now
)
455 uint32_t last_check
, time_diff
;
457 if (!wcache_fetch_seqnum(domain
->name
, &domain
->sequence_number
,
459 return NT_STATUS_UNSUCCESSFUL
;
461 domain
->last_seq_check
= last_check
;
463 /* have we expired? */
465 time_diff
= now
- domain
->last_seq_check
;
466 if ((int)time_diff
> lp_winbind_cache_time()) {
467 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
468 domain
->name
, domain
->sequence_number
,
469 (uint32_t)domain
->last_seq_check
));
470 return NT_STATUS_UNSUCCESSFUL
;
473 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
474 domain
->name
, domain
->sequence_number
,
475 (uint32_t)domain
->last_seq_check
));
480 bool wcache_store_seqnum(const char *domain_name
, uint32_t seqnum
,
481 time_t last_seq_check
)
483 size_t len
= strlen(domain_name
);
485 TDB_DATA key
= { .dptr
= (uint8_t *)keystr
, .dsize
= sizeof(keystr
) };
489 if (wcache
->tdb
== NULL
) {
490 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
494 snprintf(keystr
, sizeof(keystr
), "SEQNUM/%s", domain_name
);
496 SIVAL(buf
, 0, seqnum
);
497 SIVAL(buf
, 4, last_seq_check
);
499 ret
= tdb_store(wcache
->tdb
, key
, make_tdb_data(buf
, sizeof(buf
)),
502 DEBUG(10, ("tdb_store_bystring failed: %s\n",
503 tdb_errorstr(wcache
->tdb
)));
507 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
508 domain_name
, seqnum
, (unsigned)last_seq_check
));
513 static bool store_cache_seqnum( struct winbindd_domain
*domain
)
515 return wcache_store_seqnum(domain
->name
, domain
->sequence_number
,
516 domain
->last_seq_check
);
520 refresh the domain sequence number on timeout.
523 static void refresh_sequence_number(struct winbindd_domain
*domain
)
527 time_t t
= time(NULL
);
528 unsigned cache_time
= lp_winbind_cache_time();
530 if (is_domain_offline(domain
)) {
536 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
537 /* trying to reconnect is expensive, don't do it too often */
538 if (domain
->sequence_number
== DOM_SEQUENCE_NONE
) {
543 time_diff
= t
- domain
->last_seq_check
;
545 /* see if we have to refetch the domain sequence number */
546 if ((time_diff
< cache_time
) &&
547 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
548 NT_STATUS_IS_OK(domain
->last_status
)) {
549 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain
->name
));
553 /* try to get the sequence number from the tdb cache first */
554 /* this will update the timestamp as well */
556 status
= fetch_cache_seqnum( domain
, t
);
557 if (NT_STATUS_IS_OK(status
) &&
558 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
559 NT_STATUS_IS_OK(domain
->last_status
)) {
563 /* important! make sure that we know if this is a native
564 mode domain or not. And that we can contact it. */
566 if ( winbindd_can_contact_domain( domain
) ) {
567 status
= domain
->backend
->sequence_number(domain
,
568 &domain
->sequence_number
);
570 /* just use the current time */
571 status
= NT_STATUS_OK
;
572 domain
->sequence_number
= time(NULL
);
576 /* the above call could have set our domain->backend to NULL when
577 * coming from offline to online mode, make sure to reinitialize the
578 * backend - Guenther */
581 if (!NT_STATUS_IS_OK(status
)) {
582 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status
)));
583 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
586 domain
->last_status
= status
;
587 domain
->last_seq_check
= time(NULL
);
589 /* save the new sequence number in the cache */
590 store_cache_seqnum( domain
);
593 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
594 domain
->name
, domain
->sequence_number
));
600 decide if a cache entry has expired
602 static bool centry_expired(struct winbindd_domain
*domain
, const char *keystr
, struct cache_entry
*centry
)
604 /* If we've been told to be offline - stay in that state... */
605 if (lp_winbind_offline_logon() && global_winbindd_offline_state
) {
606 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
607 keystr
, domain
->name
));
611 /* when the domain is offline return the cached entry.
612 * This deals with transient offline states... */
614 if (!domain
->online
) {
615 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
616 keystr
, domain
->name
));
620 /* if the server is OK and our cache entry came from when it was down then
621 the entry is invalid */
622 if ((domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
623 (centry
->sequence_number
== DOM_SEQUENCE_NONE
)) {
624 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
625 keystr
, domain
->name
));
629 /* if the server is down or the cache entry is not older than the
630 current sequence number or it did not timeout then it is OK */
631 if (wcache_server_down(domain
)
632 || ((centry
->sequence_number
== domain
->sequence_number
)
633 && ((time_t)centry
->timeout
> time(NULL
)))) {
634 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
635 keystr
, domain
->name
));
639 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
640 keystr
, domain
->name
));
646 static struct cache_entry
*wcache_fetch_raw(char *kstr
)
649 struct cache_entry
*centry
;
652 key
= string_tdb_data(kstr
);
653 data
= tdb_fetch(wcache
->tdb
, key
);
659 centry
= SMB_XMALLOC_P(struct cache_entry
);
660 centry
->data
= (unsigned char *)data
.dptr
;
661 centry
->len
= data
.dsize
;
664 if (centry
->len
< 16) {
665 /* huh? corrupt cache? */
666 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s "
667 "(len < 16)?\n", kstr
));
672 centry
->status
= centry_ntstatus(centry
);
673 centry
->sequence_number
= centry_uint32(centry
);
674 centry
->timeout
= centry_uint64_t(centry
);
679 static bool is_my_own_sam_domain(struct winbindd_domain
*domain
)
681 if (strequal(domain
->name
, get_global_sam_name()) &&
682 sid_check_is_our_sam(&domain
->sid
)) {
689 static bool is_builtin_domain(struct winbindd_domain
*domain
)
691 if (strequal(domain
->name
, "BUILTIN") &&
692 sid_check_is_builtin(&domain
->sid
)) {
700 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
701 number and return status
703 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
704 struct winbindd_domain
*domain
,
705 const char *format
, ...) PRINTF_ATTRIBUTE(3,4);
706 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
707 struct winbindd_domain
*domain
,
708 const char *format
, ...)
712 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 ret
= vasprintf(&kstr
, format
, ap
);
731 centry
= wcache_fetch_raw(kstr
);
732 if (centry
== NULL
) {
737 if (centry_expired(domain
, kstr
, centry
)) {
739 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
740 kstr
, domain
->name
));
747 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
748 kstr
, domain
->name
));
754 static void wcache_delete(const char *format
, ...) PRINTF_ATTRIBUTE(1,2);
755 static void wcache_delete(const char *format
, ...)
762 va_start(ap
, format
);
763 ret
= vasprintf(&kstr
, format
, ap
);
770 key
= string_tdb_data(kstr
);
772 tdb_delete(wcache
->tdb
, key
);
777 make sure we have at least len bytes available in a centry
779 static void centry_expand(struct cache_entry
*centry
, uint32_t len
)
781 if (centry
->len
- centry
->ofs
>= len
)
784 centry
->data
= SMB_REALLOC_ARRAY(centry
->data
, unsigned char,
787 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry
->len
));
788 smb_panic_fn("out of memory in centry_expand");
793 push a uint64_t into a centry
795 static void centry_put_uint64_t(struct cache_entry
*centry
, uint64_t v
)
797 centry_expand(centry
, 8);
798 SBVAL(centry
->data
, centry
->ofs
, v
);
803 push a uint32_t into a centry
805 static void centry_put_uint32(struct cache_entry
*centry
, uint32_t v
)
807 centry_expand(centry
, 4);
808 SIVAL(centry
->data
, centry
->ofs
, v
);
813 push a uint16_t into a centry
815 static void centry_put_uint16(struct cache_entry
*centry
, uint16_t v
)
817 centry_expand(centry
, 2);
818 SSVAL(centry
->data
, centry
->ofs
, v
);
823 push a uint8_t into a centry
825 static void centry_put_uint8(struct cache_entry
*centry
, uint8_t v
)
827 centry_expand(centry
, 1);
828 SCVAL(centry
->data
, centry
->ofs
, v
);
833 push a string into a centry
835 static void centry_put_string(struct cache_entry
*centry
, const char *s
)
840 /* null strings are marked as len 0xFFFF */
841 centry_put_uint8(centry
, 0xFF);
846 /* can't handle more than 254 char strings. Truncating is probably best */
848 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len
));
851 centry_put_uint8(centry
, len
);
852 centry_expand(centry
, len
);
853 memcpy(centry
->data
+ centry
->ofs
, s
, len
);
858 push a 16 byte hash into a centry - treat as 16 byte string.
860 static void centry_put_hash16(struct cache_entry
*centry
, const uint8_t val
[16])
862 centry_put_uint8(centry
, 16);
863 centry_expand(centry
, 16);
864 memcpy(centry
->data
+ centry
->ofs
, val
, 16);
868 static void centry_put_sid(struct cache_entry
*centry
, const struct dom_sid
*sid
)
870 struct dom_sid_buf sid_string
;
871 centry_put_string(centry
, dom_sid_str_buf(sid
, &sid_string
));
876 put NTSTATUS into a centry
878 static void centry_put_ntstatus(struct cache_entry
*centry
, NTSTATUS status
)
880 uint32_t status_value
= NT_STATUS_V(status
);
881 centry_put_uint32(centry
, status_value
);
886 push a NTTIME into a centry
888 static void centry_put_nttime(struct cache_entry
*centry
, NTTIME nt
)
890 centry_expand(centry
, 8);
891 SIVAL(centry
->data
, centry
->ofs
, nt
& 0xFFFFFFFF);
893 SIVAL(centry
->data
, centry
->ofs
, nt
>> 32);
898 push a time_t into a centry - use a 64 bit size.
899 NTTIME here is being used as a convenient 64-bit size.
901 static void centry_put_time(struct cache_entry
*centry
, time_t t
)
903 NTTIME nt
= (NTTIME
)t
;
904 centry_put_nttime(centry
, nt
);
908 start a centry for output. When finished, call centry_end()
910 static struct cache_entry
*centry_start(struct winbindd_domain
*domain
,
913 struct cache_entry
*centry
;
918 centry
= SMB_XMALLOC_P(struct cache_entry
);
920 centry
->len
= 8192; /* reasonable default */
921 centry
->data
= SMB_XMALLOC_ARRAY(uint8_t, centry
->len
);
923 centry
->sequence_number
= domain
->sequence_number
;
924 centry
->timeout
= lp_winbind_cache_time() + time(NULL
);
925 centry_put_ntstatus(centry
, status
);
926 centry_put_uint32(centry
, centry
->sequence_number
);
927 centry_put_uint64_t(centry
, centry
->timeout
);
932 finish a centry and write it to the tdb
934 static void centry_end(struct cache_entry
*centry
, const char *format
, ...) PRINTF_ATTRIBUTE(2,3);
935 static void centry_end(struct cache_entry
*centry
, const char *format
, ...)
942 if (!winbindd_use_cache()) {
946 va_start(ap
, format
);
947 ret
= vasprintf(&kstr
, format
, ap
);
954 key
= string_tdb_data(kstr
);
955 data
.dptr
= centry
->data
;
956 data
.dsize
= centry
->ofs
;
958 tdb_store(wcache
->tdb
, key
, data
, TDB_REPLACE
);
962 static void wcache_save_name_to_sid(struct winbindd_domain
*domain
,
963 NTSTATUS status
, const char *domain_name
,
964 const char *name
, const struct dom_sid
*sid
,
965 enum lsa_SidType type
)
969 ok
= namemap_cache_set_name2sid(domain_name
, name
, sid
, type
,
970 time(NULL
) + lp_winbind_cache_time());
972 DBG_DEBUG("namemap_cache_set_name2sid failed\n");
976 * Don't store the reverse mapping. The name came from user
977 * input, and we might not have the correct capitalization,
978 * which is important for nsswitch.
982 static void wcache_save_sid_to_name(struct winbindd_domain
*domain
, NTSTATUS status
,
983 const struct dom_sid
*sid
, const char *domain_name
, const char *name
, enum lsa_SidType type
)
987 ok
= namemap_cache_set_sid2name(sid
, domain_name
, name
, type
,
988 time(NULL
) + lp_winbind_cache_time());
990 DBG_DEBUG("namemap_cache_set_sid2name failed\n");
993 if (type
!= SID_NAME_UNKNOWN
) {
994 ok
= namemap_cache_set_name2sid(
995 domain_name
, name
, sid
, type
,
996 time(NULL
) + lp_winbind_cache_time());
998 DBG_DEBUG("namemap_cache_set_name2sid failed\n");
1003 static void wcache_save_lockout_policy(struct winbindd_domain
*domain
,
1005 struct samr_DomInfo12
*lockout_policy
)
1007 struct cache_entry
*centry
;
1009 centry
= centry_start(domain
, status
);
1013 centry_put_nttime(centry
, lockout_policy
->lockout_duration
);
1014 centry_put_nttime(centry
, lockout_policy
->lockout_window
);
1015 centry_put_uint16(centry
, lockout_policy
->lockout_threshold
);
1017 centry_end(centry
, "LOC_POL/%s", domain
->name
);
1019 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain
->name
));
1021 centry_free(centry
);
1026 static void wcache_save_password_policy(struct winbindd_domain
*domain
,
1028 struct samr_DomInfo1
*policy
)
1030 struct cache_entry
*centry
;
1032 centry
= centry_start(domain
, status
);
1036 centry_put_uint16(centry
, policy
->min_password_length
);
1037 centry_put_uint16(centry
, policy
->password_history_length
);
1038 centry_put_uint32(centry
, policy
->password_properties
);
1039 centry_put_nttime(centry
, policy
->max_password_age
);
1040 centry_put_nttime(centry
, policy
->min_password_age
);
1042 centry_end(centry
, "PWD_POL/%s", domain
->name
);
1044 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
1046 centry_free(centry
);
1049 /***************************************************************************
1050 ***************************************************************************/
1052 static void wcache_save_username_alias(struct winbindd_domain
*domain
,
1054 const char *name
, const char *alias
)
1056 struct cache_entry
*centry
;
1059 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1062 centry_put_string( centry
, alias
);
1064 fstrcpy(uname
, name
);
1065 (void)strupper_m(uname
);
1066 centry_end(centry
, "NSS/NA/%s", uname
);
1068 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name
, alias
));
1070 centry_free(centry
);
1073 static void wcache_save_alias_username(struct winbindd_domain
*domain
,
1075 const char *alias
, const char *name
)
1077 struct cache_entry
*centry
;
1080 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1083 centry_put_string( centry
, name
);
1085 fstrcpy(uname
, alias
);
1086 (void)strupper_m(uname
);
1087 centry_end(centry
, "NSS/AN/%s", uname
);
1089 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias
, name
));
1091 centry_free(centry
);
1094 /***************************************************************************
1095 ***************************************************************************/
1097 NTSTATUS
resolve_username_to_alias( TALLOC_CTX
*mem_ctx
,
1098 struct winbindd_domain
*domain
,
1099 const char *name
, char **alias
)
1101 struct winbind_cache
*cache
= get_cache(domain
);
1102 struct cache_entry
*centry
= NULL
;
1106 if ( domain
->internal
)
1107 return NT_STATUS_NOT_SUPPORTED
;
1112 upper_name
= talloc_strdup_upper(mem_ctx
, name
);
1113 if (upper_name
== NULL
) {
1114 return NT_STATUS_NO_MEMORY
;
1117 centry
= wcache_fetch(cache
, domain
, "NSS/NA/%s", upper_name
);
1119 talloc_free(upper_name
);
1124 status
= centry
->status
;
1126 if (!NT_STATUS_IS_OK(status
)) {
1127 centry_free(centry
);
1131 *alias
= centry_string( centry
, mem_ctx
);
1133 centry_free(centry
);
1135 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1136 name
, *alias
? *alias
: "(none)"));
1138 return (*alias
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1142 /* If its not in cache and we are offline, then fail */
1144 if (is_domain_offline(domain
)) {
1145 DEBUG(8,("resolve_username_to_alias: rejecting query "
1146 "in offline mode\n"));
1147 return NT_STATUS_NOT_FOUND
;
1150 status
= nss_map_to_alias( mem_ctx
, domain
->name
, name
, alias
);
1152 if ( NT_STATUS_IS_OK( status
) ) {
1153 wcache_save_username_alias(domain
, status
, name
, *alias
);
1156 if ( NT_STATUS_EQUAL( status
, NT_STATUS_NONE_MAPPED
) ) {
1157 wcache_save_username_alias(domain
, status
, name
, "(NULL)");
1160 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1161 nt_errstr(status
)));
1163 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1164 set_domain_offline( domain
);
1170 /***************************************************************************
1171 ***************************************************************************/
1173 NTSTATUS
resolve_alias_to_username( TALLOC_CTX
*mem_ctx
,
1174 struct winbindd_domain
*domain
,
1175 const char *alias
, char **name
)
1177 struct winbind_cache
*cache
= get_cache(domain
);
1178 struct cache_entry
*centry
= NULL
;
1182 if ( domain
->internal
)
1183 return NT_STATUS_NOT_SUPPORTED
;
1188 upper_name
= talloc_strdup(mem_ctx
, alias
);
1189 if (upper_name
== NULL
) {
1190 return NT_STATUS_NO_MEMORY
;
1192 if (!strupper_m(upper_name
)) {
1193 talloc_free(upper_name
);
1194 return NT_STATUS_INVALID_PARAMETER
;
1197 centry
= wcache_fetch(cache
, domain
, "NSS/AN/%s", upper_name
);
1199 talloc_free(upper_name
);
1204 status
= centry
->status
;
1206 if (!NT_STATUS_IS_OK(status
)) {
1207 centry_free(centry
);
1211 *name
= centry_string( centry
, mem_ctx
);
1213 centry_free(centry
);
1215 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1216 alias
, *name
? *name
: "(none)"));
1218 return (*name
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1222 /* If its not in cache and we are offline, then fail */
1224 if (is_domain_offline(domain
)) {
1225 DEBUG(8,("resolve_alias_to_username: rejecting query "
1226 "in offline mode\n"));
1227 return NT_STATUS_NOT_FOUND
;
1230 /* an alias cannot contain a domain prefix or '@' */
1232 if (strchr(alias
, '\\') || strchr(alias
, '@')) {
1233 DEBUG(10,("resolve_alias_to_username: skipping fully "
1234 "qualified name %s\n", alias
));
1235 return NT_STATUS_OBJECT_NAME_INVALID
;
1238 status
= nss_map_from_alias( mem_ctx
, domain
->name
, alias
, name
);
1240 if ( NT_STATUS_IS_OK( status
) ) {
1241 wcache_save_alias_username( domain
, status
, alias
, *name
);
1244 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1245 wcache_save_alias_username(domain
, status
, alias
, "(NULL)");
1248 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1249 nt_errstr(status
)));
1251 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1252 set_domain_offline( domain
);
1258 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
1260 struct winbind_cache
*cache
= get_cache(domain
);
1262 struct dom_sid_buf tmp
;
1267 return NT_STATUS_INTERNAL_DB_ERROR
;
1270 if (is_null_sid(sid
)) {
1271 return NT_STATUS_INVALID_SID
;
1274 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1275 return NT_STATUS_INVALID_SID
;
1278 fstr_sprintf(key_str
, "CRED/%s", dom_sid_str_buf(sid
, &tmp
));
1280 ret
= tdb_exists(cache
->tdb
, string_tdb_data(key_str
));
1282 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1285 return NT_STATUS_OK
;
1288 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1289 as new salted ones. */
1291 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
1292 TALLOC_CTX
*mem_ctx
,
1293 const struct dom_sid
*sid
,
1294 const uint8_t **cached_nt_pass
,
1295 const uint8_t **cached_salt
)
1297 struct winbind_cache
*cache
= get_cache(domain
);
1298 struct cache_entry
*centry
= NULL
;
1301 struct dom_sid_buf sidstr
;
1304 return NT_STATUS_INTERNAL_DB_ERROR
;
1307 if (is_null_sid(sid
)) {
1308 return NT_STATUS_INVALID_SID
;
1311 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1312 return NT_STATUS_INVALID_SID
;
1315 /* Try and get a salted cred first. If we can't
1316 fall back to an unsalted cred. */
1318 centry
= wcache_fetch(cache
, domain
, "CRED/%s",
1319 dom_sid_str_buf(sid
, &sidstr
));
1321 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1322 dom_sid_str_buf(sid
, &sidstr
)));
1323 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1327 * We don't use the time element at this moment,
1328 * but we have to consume it, so that we don't
1329 * neet to change the disk format of the cache.
1331 (void)centry_time(centry
);
1333 /* In the salted case this isn't actually the nt_hash itself,
1334 but the MD5 of the salt + nt_hash. Let the caller
1335 sort this out. It can tell as we only return the cached_salt
1336 if we are returning a salted cred. */
1338 *cached_nt_pass
= (const uint8_t *)centry_hash16(centry
, mem_ctx
);
1339 if (*cached_nt_pass
== NULL
) {
1341 dom_sid_str_buf(sid
, &sidstr
);
1343 /* Bad (old) cred cache. Delete and pretend we
1345 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1347 wcache_delete("CRED/%s", sidstr
.buf
);
1348 centry_free(centry
);
1349 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1352 /* We only have 17 bytes more data in the salted cred case. */
1353 if (centry
->len
- centry
->ofs
== 17) {
1354 *cached_salt
= (const uint8_t *)centry_hash16(centry
, mem_ctx
);
1356 *cached_salt
= NULL
;
1359 dump_data_pw("cached_nt_pass", *cached_nt_pass
, NT_HASH_LEN
);
1361 dump_data_pw("cached_salt", *cached_salt
, NT_HASH_LEN
);
1364 status
= centry
->status
;
1366 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1367 dom_sid_str_buf(sid
, &sidstr
),
1368 nt_errstr(status
) ));
1370 centry_free(centry
);
1374 /* Store creds for a SID - only writes out new salted ones. */
1376 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1377 const struct dom_sid
*sid
,
1378 const uint8_t nt_pass
[NT_HASH_LEN
])
1380 struct cache_entry
*centry
;
1381 struct dom_sid_buf sid_str
;
1383 uint8_t cred_salt
[NT_HASH_LEN
];
1384 uint8_t salted_hash
[NT_HASH_LEN
];
1385 gnutls_hash_hd_t hash_hnd
= NULL
;
1388 if (is_null_sid(sid
)) {
1389 return NT_STATUS_INVALID_SID
;
1392 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1393 return NT_STATUS_INVALID_SID
;
1396 centry
= centry_start(domain
, NT_STATUS_OK
);
1398 return NT_STATUS_INTERNAL_DB_ERROR
;
1401 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1403 centry_put_time(centry
, time(NULL
));
1405 /* Create a salt and then salt the hash. */
1406 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1408 rc
= gnutls_hash_init(&hash_hnd
, GNUTLS_DIG_MD5
);
1410 centry_free(centry
);
1411 return gnutls_error_to_ntstatus(rc
, NT_STATUS_HASH_NOT_SUPPORTED
);
1414 rc
= gnutls_hash(hash_hnd
, cred_salt
, 16);
1416 gnutls_hash_deinit(hash_hnd
, NULL
);
1417 centry_free(centry
);
1418 return gnutls_error_to_ntstatus(rc
, NT_STATUS_HASH_NOT_SUPPORTED
);
1420 rc
= gnutls_hash(hash_hnd
, nt_pass
, 16);
1422 gnutls_hash_deinit(hash_hnd
, NULL
);
1423 centry_free(centry
);
1424 return gnutls_error_to_ntstatus(rc
, NT_STATUS_HASH_NOT_SUPPORTED
);
1426 gnutls_hash_deinit(hash_hnd
, salted_hash
);
1428 centry_put_hash16(centry
, salted_hash
);
1429 centry_put_hash16(centry
, cred_salt
);
1430 centry_end(centry
, "CRED/%s", dom_sid_str_buf(sid
, &sid_str
));
1432 DEBUG(10,("wcache_save_creds: %s\n", sid_str
.buf
));
1434 centry_free(centry
);
1436 return NT_STATUS_OK
;
1440 /* Query display info. This is the basic user list fn */
1441 NTSTATUS
wb_cache_query_user_list(struct winbindd_domain
*domain
,
1442 TALLOC_CTX
*mem_ctx
,
1445 struct winbind_cache
*cache
= get_cache(domain
);
1446 struct cache_entry
*centry
= NULL
;
1447 uint32_t num_rids
= 0;
1448 uint32_t *rids
= NULL
;
1450 unsigned int i
, retry
;
1451 bool old_status
= domain
->online
;
1458 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1463 num_rids
= centry_uint32(centry
);
1465 if (num_rids
== 0) {
1469 rids
= talloc_array(mem_ctx
, uint32_t, num_rids
);
1471 centry_free(centry
);
1472 return NT_STATUS_NO_MEMORY
;
1475 for (i
=0; i
<num_rids
; i
++) {
1476 rids
[i
] = centry_uint32(centry
);
1480 status
= centry
->status
;
1482 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1483 domain
->name
, nt_errstr(status
) ));
1485 centry_free(centry
);
1490 /* Return status value returned by seq number check */
1492 if (!NT_STATUS_IS_OK(domain
->last_status
))
1493 return domain
->last_status
;
1495 /* Put the query_user_list() in a retry loop. There appears to be
1496 * some bug either with Windows 2000 or Samba's handling of large
1497 * rpc replies. This manifests itself as sudden disconnection
1498 * at a random point in the enumeration of a large (60k) user list.
1499 * The retry loop simply tries the operation again. )-: It's not
1500 * pretty but an acceptable workaround until we work out what the
1501 * real problem is. */
1506 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1510 status
= domain
->backend
->query_user_list(domain
, mem_ctx
,
1512 num_rids
= talloc_array_length(rids
);
1514 if (!NT_STATUS_IS_OK(status
)) {
1515 DEBUG(3, ("query_user_list: returned 0x%08x, "
1516 "retrying\n", NT_STATUS_V(status
)));
1518 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1519 DEBUG(3, ("query_user_list: flushing "
1520 "connection cache\n"));
1521 invalidate_cm_connection(domain
);
1523 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1524 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1525 if (!domain
->internal
&& old_status
) {
1526 set_domain_offline(domain
);
1528 /* store partial response. */
1531 * humm, what about the status used for cache?
1532 * Should it be NT_STATUS_OK?
1537 * domain is offline now, and there is no user entries,
1538 * try to fetch from cache again.
1540 if (cache
->tdb
&& !domain
->online
&& !domain
->internal
&& old_status
) {
1541 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1542 /* partial response... */
1546 goto do_fetch_cache
;
1553 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1557 refresh_sequence_number(domain
);
1558 if (!NT_STATUS_IS_OK(status
)) {
1561 centry
= centry_start(domain
, status
);
1564 centry_put_uint32(centry
, num_rids
);
1565 for (i
=0; i
<num_rids
; i
++) {
1566 centry_put_uint32(centry
, rids
[i
]);
1568 centry_end(centry
, "UL/%s", domain
->name
);
1569 centry_free(centry
);
1577 /* list all domain groups */
1578 NTSTATUS
wb_cache_enum_dom_groups(struct winbindd_domain
*domain
,
1579 TALLOC_CTX
*mem_ctx
,
1580 uint32_t *num_entries
,
1581 struct wb_acct_info
**info
)
1583 struct winbind_cache
*cache
= get_cache(domain
);
1584 struct cache_entry
*centry
= NULL
;
1589 old_status
= domain
->online
;
1593 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1598 *num_entries
= centry_uint32(centry
);
1600 if (*num_entries
== 0)
1603 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1605 smb_panic_fn("enum_dom_groups out of memory");
1607 for (i
=0; i
<(*num_entries
); i
++) {
1608 (*info
)[i
].acct_name
= centry_string(centry
, (*info
));
1609 (*info
)[i
].acct_desc
= centry_string(centry
, (*info
));
1610 (*info
)[i
].rid
= centry_uint32(centry
);
1614 status
= centry
->status
;
1616 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1617 domain
->name
, nt_errstr(status
) ));
1619 centry_free(centry
);
1626 /* Return status value returned by seq number check */
1628 if (!NT_STATUS_IS_OK(domain
->last_status
))
1629 return domain
->last_status
;
1631 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1634 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1636 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1637 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1638 if (!domain
->internal
&& old_status
) {
1639 set_domain_offline(domain
);
1643 !domain
->internal
&&
1645 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1647 goto do_fetch_cache
;
1652 refresh_sequence_number(domain
);
1653 if (!NT_STATUS_IS_OK(status
)) {
1656 centry
= centry_start(domain
, status
);
1659 centry_put_uint32(centry
, *num_entries
);
1660 for (i
=0; i
<(*num_entries
); i
++) {
1661 centry_put_string(centry
, (*info
)[i
].acct_name
);
1662 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1663 centry_put_uint32(centry
, (*info
)[i
].rid
);
1665 centry_end(centry
, "GL/%s/domain", domain
->name
);
1666 centry_free(centry
);
1672 /* list all domain groups */
1673 NTSTATUS
wb_cache_enum_local_groups(struct winbindd_domain
*domain
,
1674 TALLOC_CTX
*mem_ctx
,
1675 uint32_t *num_entries
,
1676 struct wb_acct_info
**info
)
1678 struct winbind_cache
*cache
= get_cache(domain
);
1679 struct cache_entry
*centry
= NULL
;
1684 old_status
= domain
->online
;
1688 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1693 *num_entries
= centry_uint32(centry
);
1695 if (*num_entries
== 0)
1698 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1700 smb_panic_fn("enum_dom_groups out of memory");
1702 for (i
=0; i
<(*num_entries
); i
++) {
1703 (*info
)[i
].acct_name
= centry_string(centry
, (*info
));
1704 (*info
)[i
].acct_desc
= centry_string(centry
, (*info
));
1705 (*info
)[i
].rid
= centry_uint32(centry
);
1710 /* If we are returning cached data and the domain controller
1711 is down then we don't know whether the data is up to date
1712 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1715 if (wcache_server_down(domain
)) {
1716 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1717 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1719 status
= centry
->status
;
1721 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1722 domain
->name
, nt_errstr(status
) ));
1724 centry_free(centry
);
1731 /* Return status value returned by seq number check */
1733 if (!NT_STATUS_IS_OK(domain
->last_status
))
1734 return domain
->last_status
;
1736 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1739 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1741 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1742 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1743 if (!domain
->internal
&& old_status
) {
1744 set_domain_offline(domain
);
1747 !domain
->internal
&&
1750 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1752 goto do_fetch_cache
;
1757 refresh_sequence_number(domain
);
1758 if (!NT_STATUS_IS_OK(status
)) {
1761 centry
= centry_start(domain
, status
);
1764 centry_put_uint32(centry
, *num_entries
);
1765 for (i
=0; i
<(*num_entries
); i
++) {
1766 centry_put_string(centry
, (*info
)[i
].acct_name
);
1767 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1768 centry_put_uint32(centry
, (*info
)[i
].rid
);
1770 centry_end(centry
, "GL/%s/local", domain
->name
);
1771 centry_free(centry
);
1777 struct wcache_name_to_sid_state
{
1778 struct dom_sid
*sid
;
1779 enum lsa_SidType
*type
;
1784 static void wcache_name_to_sid_fn(const struct dom_sid
*sid
,
1785 enum lsa_SidType type
,
1789 struct wcache_name_to_sid_state
*state
= private_data
;
1792 *state
->type
= type
;
1793 state
->found
= (!expired
|| state
->offline
);
1796 static NTSTATUS
wcache_name_to_sid(struct winbindd_domain
*domain
,
1797 const char *domain_name
,
1799 struct dom_sid
*sid
,
1800 enum lsa_SidType
*type
)
1802 struct wcache_name_to_sid_state state
= {
1803 .sid
= sid
, .type
= type
, .found
= false,
1804 .offline
= is_domain_offline(domain
),
1808 ok
= namemap_cache_find_name(domain_name
, name
, wcache_name_to_sid_fn
,
1811 DBG_DEBUG("namemap_cache_find_name failed\n");
1812 return NT_STATUS_NOT_FOUND
;
1815 DBG_DEBUG("cache entry not found\n");
1816 return NT_STATUS_NOT_FOUND
;
1818 if (*type
== SID_NAME_UNKNOWN
) {
1819 return NT_STATUS_NONE_MAPPED
;
1822 return NT_STATUS_OK
;
1825 /* convert a single name to a sid in a domain */
1826 NTSTATUS
wb_cache_name_to_sid(struct winbindd_domain
*domain
,
1827 TALLOC_CTX
*mem_ctx
,
1828 const char *domain_name
,
1831 struct dom_sid
*sid
,
1832 enum lsa_SidType
*type
)
1836 const char *dom_name
;
1838 old_status
= domain
->online
;
1840 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1841 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1847 /* If the seq number check indicated that there is a problem
1848 * with this DC, then return that status... except for
1849 * access_denied. This is special because the dc may be in
1850 * "restrict anonymous = 1" mode, in which case it will deny
1851 * most unauthenticated operations, but *will* allow the LSA
1852 * name-to-sid that we try as a fallback. */
1854 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1855 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1856 return domain
->last_status
;
1858 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1861 winbindd_domain_init_backend(domain
);
1862 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
,
1863 name
, flags
, &dom_name
, sid
, type
);
1865 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1866 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1867 if (!domain
->internal
&& old_status
) {
1868 set_domain_offline(domain
);
1870 if (!domain
->internal
&&
1873 NTSTATUS cache_status
;
1874 cache_status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1875 return cache_status
;
1880 if (domain
->online
&&
1881 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1882 enum lsa_SidType save_type
= *type
;
1884 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1885 save_type
= SID_NAME_UNKNOWN
;
1888 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
,
1891 /* Only save the reverse mapping if this was not a UPN */
1892 if (!strchr(name
, '@')) {
1893 if (!strupper_m(discard_const_p(char, domain_name
))) {
1894 return NT_STATUS_INVALID_PARAMETER
;
1896 (void)strlower_m(discard_const_p(char, name
));
1897 wcache_save_sid_to_name(domain
, status
, sid
,
1898 dom_name
, name
, save_type
);
1905 struct wcache_sid_to_name_state
{
1906 TALLOC_CTX
*mem_ctx
;
1909 enum lsa_SidType
*type
;
1914 static void wcache_sid_to_name_fn(const char *domain
,
1916 enum lsa_SidType type
,
1920 struct wcache_sid_to_name_state
*state
= private_data
;
1922 *state
->domain_name
= talloc_strdup(state
->mem_ctx
, domain
);
1923 if (*state
->domain_name
== NULL
) {
1926 *state
->name
= talloc_strdup(state
->mem_ctx
, name
);
1927 if (*state
->name
== NULL
) {
1930 *state
->type
= type
;
1931 state
->found
= (!expired
|| state
->offline
);
1934 static NTSTATUS
wcache_sid_to_name(struct winbindd_domain
*domain
,
1935 const struct dom_sid
*sid
,
1936 TALLOC_CTX
*mem_ctx
,
1939 enum lsa_SidType
*type
)
1941 struct wcache_sid_to_name_state state
= {
1942 .mem_ctx
= mem_ctx
, .found
= false,
1943 .domain_name
= domain_name
, .name
= name
, .type
= type
,
1944 .offline
= is_domain_offline(domain
)
1948 ok
= namemap_cache_find_sid(sid
, wcache_sid_to_name_fn
, &state
);
1950 DBG_DEBUG("namemap_cache_find_name failed\n");
1951 return NT_STATUS_NOT_FOUND
;
1954 DBG_DEBUG("cache entry not found\n");
1955 return NT_STATUS_NOT_FOUND
;
1957 if (*type
== SID_NAME_UNKNOWN
) {
1958 return NT_STATUS_NONE_MAPPED
;
1961 return NT_STATUS_OK
;
1964 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1966 NTSTATUS
wb_cache_sid_to_name(struct winbindd_domain
*domain
,
1967 TALLOC_CTX
*mem_ctx
,
1968 const struct dom_sid
*sid
,
1971 enum lsa_SidType
*type
)
1976 old_status
= domain
->online
;
1977 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
1979 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1984 *domain_name
= NULL
;
1986 /* If the seq number check indicated that there is a problem
1987 * with this DC, then return that status... except for
1988 * access_denied. This is special because the dc may be in
1989 * "restrict anonymous = 1" mode, in which case it will deny
1990 * most unauthenticated operations, but *will* allow the LSA
1991 * sid-to-name that we try as a fallback. */
1993 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1994 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1995 return domain
->last_status
;
1997 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
2000 winbindd_domain_init_backend(domain
);
2002 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
2004 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2005 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2006 if (!domain
->internal
&& old_status
) {
2007 set_domain_offline(domain
);
2009 if (!domain
->internal
&&
2012 NTSTATUS cache_status
;
2013 cache_status
= wcache_sid_to_name(domain
, sid
, mem_ctx
,
2014 domain_name
, name
, type
);
2015 return cache_status
;
2019 if (!NT_STATUS_IS_OK(status
)) {
2022 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
2024 /* We can't save the name to sid mapping here, as with sid history a
2025 * later name2sid would give the wrong sid. */
2030 NTSTATUS
wb_cache_rids_to_names(struct winbindd_domain
*domain
,
2031 TALLOC_CTX
*mem_ctx
,
2032 const struct dom_sid
*domain_sid
,
2037 enum lsa_SidType
**types
)
2039 struct winbind_cache
*cache
= get_cache(domain
);
2041 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
2046 old_status
= domain
->online
;
2047 *domain_name
= NULL
;
2055 if (num_rids
== 0) {
2056 return NT_STATUS_OK
;
2059 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2060 *types
= talloc_array(mem_ctx
, enum lsa_SidType
, num_rids
);
2062 if ((*names
== NULL
) || (*types
== NULL
)) {
2063 result
= NT_STATUS_NO_MEMORY
;
2067 have_mapped
= have_unmapped
= false;
2069 for (i
=0; i
<num_rids
; i
++) {
2072 enum lsa_SidType type
;
2075 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2076 result
= NT_STATUS_INTERNAL_ERROR
;
2080 status
= wcache_sid_to_name(domain
, &sid
, *names
, &dom
,
2083 (*types
)[i
] = SID_NAME_UNKNOWN
;
2084 (*names
)[i
] = talloc_strdup(*names
, "");
2086 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2091 if (NT_STATUS_IS_OK(status
)) {
2095 if (*domain_name
== NULL
) {
2103 } else if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
2104 have_unmapped
= true;
2106 /* something's definitely wrong */
2113 return NT_STATUS_NONE_MAPPED
;
2115 if (!have_unmapped
) {
2116 return NT_STATUS_OK
;
2118 return STATUS_SOME_UNMAPPED
;
2122 TALLOC_FREE(*names
);
2123 TALLOC_FREE(*types
);
2125 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
2126 rids
, num_rids
, domain_name
,
2129 if (NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
2130 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2131 if (!domain
->internal
&& old_status
) {
2132 set_domain_offline(domain
);
2135 !domain
->internal
&&
2138 have_mapped
= have_unmapped
= false;
2140 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2141 if (*names
== NULL
) {
2142 result
= NT_STATUS_NO_MEMORY
;
2146 *types
= talloc_array(mem_ctx
, enum lsa_SidType
,
2148 if (*types
== NULL
) {
2149 result
= NT_STATUS_NO_MEMORY
;
2153 for (i
=0; i
<num_rids
; i
++) {
2156 enum lsa_SidType type
;
2159 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2160 result
= NT_STATUS_INTERNAL_ERROR
;
2164 status
= wcache_sid_to_name(domain
, &sid
,
2168 (*types
)[i
] = SID_NAME_UNKNOWN
;
2169 (*names
)[i
] = talloc_strdup(*names
, "");
2171 if (NT_STATUS_IS_OK(status
)) {
2175 if (*domain_name
== NULL
) {
2183 } else if (NT_STATUS_EQUAL(
2185 NT_STATUS_NONE_MAPPED
)) {
2186 have_unmapped
= true;
2188 /* something's definitely wrong */
2195 return NT_STATUS_NONE_MAPPED
;
2197 if (!have_unmapped
) {
2198 return NT_STATUS_OK
;
2200 return STATUS_SOME_UNMAPPED
;
2204 None of the queried rids has been found so save all negative entries
2206 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
2207 for (i
= 0; i
< num_rids
; i
++) {
2209 const char *name
= "";
2210 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
2211 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
2213 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2214 return NT_STATUS_INTERNAL_ERROR
;
2217 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2225 Some or all of the queried rids have been found.
2227 if (!NT_STATUS_IS_OK(result
) &&
2228 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
2232 refresh_sequence_number(domain
);
2234 for (i
=0; i
<num_rids
; i
++) {
2238 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2239 result
= NT_STATUS_INTERNAL_ERROR
;
2243 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
2244 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
2246 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2247 (*names
)[i
], (*types
)[i
]);
2253 TALLOC_FREE(*names
);
2254 TALLOC_FREE(*types
);
2258 static NTSTATUS
wcache_query_user(struct winbindd_domain
*domain
,
2259 TALLOC_CTX
*mem_ctx
,
2260 const struct dom_sid
*user_sid
,
2261 struct wbint_userinfo
*info
)
2263 struct winbind_cache
*cache
= get_cache(domain
);
2264 struct cache_entry
*centry
= NULL
;
2266 struct dom_sid_buf sid_string
;
2268 if (cache
->tdb
== NULL
) {
2269 return NT_STATUS_NOT_FOUND
;
2272 centry
= wcache_fetch(
2273 cache
, domain
, "U/%s", dom_sid_str_buf(user_sid
, &sid_string
));
2274 if (centry
== NULL
) {
2275 return NT_STATUS_NOT_FOUND
;
2279 * If we have an access denied cache entry and a cached info3
2280 * in the samlogon cache then do a query. This will force the
2281 * rpc back end to return the info3 data.
2284 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
) &&
2285 netsamlogon_cache_have(user_sid
)) {
2286 DEBUG(10, ("query_user: cached access denied and have cached "
2288 domain
->last_status
= NT_STATUS_OK
;
2289 centry_free(centry
);
2290 return NT_STATUS_NOT_FOUND
;
2293 /* if status is not ok then this is a negative hit
2294 and the rest of the data doesn't matter */
2295 status
= centry
->status
;
2296 if (NT_STATUS_IS_OK(status
)) {
2297 info
->domain_name
= centry_string(centry
, mem_ctx
);
2298 info
->acct_name
= centry_string(centry
, mem_ctx
);
2299 info
->full_name
= centry_string(centry
, mem_ctx
);
2300 info
->homedir
= centry_string(centry
, mem_ctx
);
2301 info
->shell
= centry_string(centry
, mem_ctx
);
2302 info
->uid
= centry_uint32(centry
);
2303 info
->primary_gid
= centry_uint32(centry
);
2304 info
->primary_group_name
= centry_string(centry
, mem_ctx
);
2305 centry_sid(centry
, &info
->user_sid
);
2306 centry_sid(centry
, &info
->group_sid
);
2309 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2310 "%s\n", domain
->name
, nt_errstr(status
) ));
2312 centry_free(centry
);
2318 * @brief Query a fullname from the username cache (for further gecos processing)
2320 * @param domain A pointer to the winbindd_domain struct.
2321 * @param mem_ctx The talloc context.
2322 * @param user_sid The user sid.
2323 * @param full_name A pointer to the full_name string.
2325 * @return NTSTATUS code
2327 NTSTATUS
wcache_query_user_fullname(struct winbindd_domain
*domain
,
2328 TALLOC_CTX
*mem_ctx
,
2329 const struct dom_sid
*user_sid
,
2330 const char **full_name
)
2333 struct wbint_userinfo info
;
2335 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, &info
);
2336 if (!NT_STATUS_IS_OK(status
)) {
2340 if (info
.full_name
!= NULL
) {
2341 *full_name
= talloc_strdup(mem_ctx
, info
.full_name
);
2342 if (*full_name
== NULL
) {
2343 return NT_STATUS_NO_MEMORY
;
2347 return NT_STATUS_OK
;
2350 static NTSTATUS
wcache_lookup_usergroups(struct winbindd_domain
*domain
,
2351 TALLOC_CTX
*mem_ctx
,
2352 const struct dom_sid
*user_sid
,
2353 uint32_t *pnum_sids
,
2354 struct dom_sid
**psids
)
2356 struct winbind_cache
*cache
= get_cache(domain
);
2357 struct cache_entry
*centry
= NULL
;
2359 uint32_t i
, num_sids
;
2360 struct dom_sid
*sids
;
2361 struct dom_sid_buf sid_string
;
2363 if (cache
->tdb
== NULL
) {
2364 return NT_STATUS_NOT_FOUND
;
2367 centry
= wcache_fetch(
2371 dom_sid_str_buf(user_sid
, &sid_string
));
2372 if (centry
== NULL
) {
2373 return NT_STATUS_NOT_FOUND
;
2376 /* If we have an access denied cache entry and a cached info3 in the
2377 samlogon cache then do a query. This will force the rpc back end
2378 to return the info3 data. */
2380 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)
2381 && netsamlogon_cache_have(user_sid
)) {
2382 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2384 domain
->last_status
= NT_STATUS_OK
;
2385 centry_free(centry
);
2386 return NT_STATUS_NOT_FOUND
;
2389 num_sids
= centry_uint32(centry
);
2390 sids
= talloc_array(mem_ctx
, struct dom_sid
, num_sids
);
2392 centry_free(centry
);
2393 return NT_STATUS_NO_MEMORY
;
2396 for (i
=0; i
<num_sids
; i
++) {
2397 centry_sid(centry
, &sids
[i
]);
2400 status
= centry
->status
;
2402 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2403 "status: %s\n", domain
->name
, nt_errstr(status
)));
2405 centry_free(centry
);
2407 *pnum_sids
= num_sids
;
2412 /* Lookup groups a user is a member of. */
2413 NTSTATUS
wb_cache_lookup_usergroups(struct winbindd_domain
*domain
,
2414 TALLOC_CTX
*mem_ctx
,
2415 const struct dom_sid
*user_sid
,
2416 uint32_t *num_groups
,
2417 struct dom_sid
**user_gids
)
2419 struct cache_entry
*centry
= NULL
;
2422 struct dom_sid_buf sid_string
;
2425 old_status
= domain
->online
;
2426 status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2427 num_groups
, user_gids
);
2428 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2433 (*user_gids
) = NULL
;
2435 /* Return status value returned by seq number check */
2437 if (!NT_STATUS_IS_OK(domain
->last_status
))
2438 return domain
->last_status
;
2440 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2443 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
2445 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2446 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2447 if (!domain
->internal
&& old_status
) {
2448 set_domain_offline(domain
);
2450 if (!domain
->internal
&&
2453 NTSTATUS cache_status
;
2454 cache_status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2455 num_groups
, user_gids
);
2456 return cache_status
;
2459 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
2463 refresh_sequence_number(domain
);
2464 if (!NT_STATUS_IS_OK(status
)) {
2467 centry
= centry_start(domain
, status
);
2471 centry_put_uint32(centry
, *num_groups
);
2472 for (i
=0; i
<(*num_groups
); i
++) {
2473 centry_put_sid(centry
, &(*user_gids
)[i
]);
2476 centry_end(centry
, "UG/%s", dom_sid_str_buf(user_sid
, &sid_string
));
2477 centry_free(centry
);
2483 static char *wcache_make_sidlist(TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2484 const struct dom_sid
*sids
)
2489 sidlist
= talloc_strdup(mem_ctx
, "");
2490 if (sidlist
== NULL
) {
2493 for (i
=0; i
<num_sids
; i
++) {
2494 struct dom_sid_buf tmp
;
2495 sidlist
= talloc_asprintf_append_buffer(
2498 dom_sid_str_buf(&sids
[i
], &tmp
));
2499 if (sidlist
== NULL
) {
2506 static NTSTATUS
wcache_lookup_useraliases(struct winbindd_domain
*domain
,
2507 TALLOC_CTX
*mem_ctx
,
2509 const struct dom_sid
*sids
,
2510 uint32_t *pnum_aliases
,
2511 uint32_t **paliases
)
2513 struct winbind_cache
*cache
= get_cache(domain
);
2514 struct cache_entry
*centry
= NULL
;
2515 uint32_t i
, num_aliases
;
2520 if (cache
->tdb
== NULL
) {
2521 return NT_STATUS_NOT_FOUND
;
2524 if (num_sids
== 0) {
2527 return NT_STATUS_OK
;
2530 /* We need to cache indexed by the whole list of SIDs, the aliases
2531 * resulting might come from any of the SIDs. */
2533 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2534 if (sidlist
== NULL
) {
2535 return NT_STATUS_NO_MEMORY
;
2538 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2539 TALLOC_FREE(sidlist
);
2540 if (centry
== NULL
) {
2541 return NT_STATUS_NOT_FOUND
;
2544 num_aliases
= centry_uint32(centry
);
2545 aliases
= talloc_array(mem_ctx
, uint32_t, num_aliases
);
2546 if (aliases
== NULL
) {
2547 centry_free(centry
);
2548 return NT_STATUS_NO_MEMORY
;
2551 for (i
=0; i
<num_aliases
; i
++) {
2552 aliases
[i
] = centry_uint32(centry
);
2555 status
= centry
->status
;
2557 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2558 "status %s\n", domain
->name
, nt_errstr(status
)));
2560 centry_free(centry
);
2562 *pnum_aliases
= num_aliases
;
2563 *paliases
= aliases
;
2568 NTSTATUS
wb_cache_lookup_useraliases(struct winbindd_domain
*domain
,
2569 TALLOC_CTX
*mem_ctx
,
2571 const struct dom_sid
*sids
,
2572 uint32_t *num_aliases
,
2573 uint32_t **alias_rids
)
2575 struct cache_entry
*centry
= NULL
;
2581 old_status
= domain
->online
;
2582 status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
2583 num_aliases
, alias_rids
);
2584 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2589 (*alias_rids
) = NULL
;
2591 if (!NT_STATUS_IS_OK(domain
->last_status
))
2592 return domain
->last_status
;
2594 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2595 "for domain %s\n", domain
->name
));
2597 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2598 if (sidlist
== NULL
) {
2599 return NT_STATUS_NO_MEMORY
;
2602 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2604 num_aliases
, alias_rids
);
2606 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2607 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2608 if (!domain
->internal
&& old_status
) {
2609 set_domain_offline(domain
);
2611 if (!domain
->internal
&&
2614 NTSTATUS cache_status
;
2615 cache_status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
,
2616 sids
, num_aliases
, alias_rids
);
2617 return cache_status
;
2621 refresh_sequence_number(domain
);
2622 if (!NT_STATUS_IS_OK(status
)) {
2625 centry
= centry_start(domain
, status
);
2628 centry_put_uint32(centry
, *num_aliases
);
2629 for (i
=0; i
<(*num_aliases
); i
++)
2630 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2631 centry_end(centry
, "UA%s", sidlist
);
2632 centry_free(centry
);
2638 static NTSTATUS
wcache_lookup_groupmem(struct winbindd_domain
*domain
,
2639 TALLOC_CTX
*mem_ctx
,
2640 const struct dom_sid
*group_sid
,
2641 uint32_t *num_names
,
2642 struct dom_sid
**sid_mem
, char ***names
,
2643 uint32_t **name_types
)
2645 struct winbind_cache
*cache
= get_cache(domain
);
2646 struct cache_entry
*centry
= NULL
;
2649 struct dom_sid_buf sid_string
;
2651 if (cache
->tdb
== NULL
) {
2652 return NT_STATUS_NOT_FOUND
;
2655 centry
= wcache_fetch(
2659 dom_sid_str_buf(group_sid
, &sid_string
));
2660 if (centry
== NULL
) {
2661 return NT_STATUS_NOT_FOUND
;
2668 *num_names
= centry_uint32(centry
);
2669 if (*num_names
== 0) {
2670 centry_free(centry
);
2671 return NT_STATUS_OK
;
2674 *sid_mem
= talloc_array(mem_ctx
, struct dom_sid
, *num_names
);
2675 *names
= talloc_array(mem_ctx
, char *, *num_names
);
2676 *name_types
= talloc_array(mem_ctx
, uint32_t, *num_names
);
2678 if ((*sid_mem
== NULL
) || (*names
== NULL
) || (*name_types
== NULL
)) {
2679 TALLOC_FREE(*sid_mem
);
2680 TALLOC_FREE(*names
);
2681 TALLOC_FREE(*name_types
);
2682 centry_free(centry
);
2683 return NT_STATUS_NO_MEMORY
;
2686 for (i
=0; i
<(*num_names
); i
++) {
2687 centry_sid(centry
, &(*sid_mem
)[i
]);
2688 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2689 (*name_types
)[i
] = centry_uint32(centry
);
2692 status
= centry
->status
;
2694 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2695 "status: %s\n", domain
->name
, nt_errstr(status
)));
2697 centry_free(centry
);
2701 NTSTATUS
wb_cache_lookup_groupmem(struct winbindd_domain
*domain
,
2702 TALLOC_CTX
*mem_ctx
,
2703 const struct dom_sid
*group_sid
,
2704 enum lsa_SidType type
,
2705 uint32_t *num_names
,
2706 struct dom_sid
**sid_mem
,
2708 uint32_t **name_types
)
2710 struct cache_entry
*centry
= NULL
;
2713 struct dom_sid_buf sid_string
;
2716 old_status
= domain
->online
;
2717 status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2718 sid_mem
, names
, name_types
);
2719 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2726 (*name_types
) = NULL
;
2728 /* Return status value returned by seq number check */
2730 if (!NT_STATUS_IS_OK(domain
->last_status
))
2731 return domain
->last_status
;
2733 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2736 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
,
2738 sid_mem
, names
, name_types
);
2740 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2741 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2742 if (!domain
->internal
&& old_status
) {
2743 set_domain_offline(domain
);
2745 if (!domain
->internal
&&
2748 NTSTATUS cache_status
;
2749 cache_status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
,
2750 num_names
, sid_mem
, names
,
2752 return cache_status
;
2756 refresh_sequence_number(domain
);
2757 if (!NT_STATUS_IS_OK(status
)) {
2760 centry
= centry_start(domain
, status
);
2763 centry_put_uint32(centry
, *num_names
);
2764 for (i
=0; i
<(*num_names
); i
++) {
2765 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2766 centry_put_string(centry
, (*names
)[i
]);
2767 centry_put_uint32(centry
, (*name_types
)[i
]);
2771 dom_sid_str_buf(group_sid
, &sid_string
));
2772 centry_free(centry
);
2778 /* find the sequence number for a domain */
2779 NTSTATUS
wb_cache_sequence_number(struct winbindd_domain
*domain
,
2782 refresh_sequence_number(domain
);
2784 *seq
= domain
->sequence_number
;
2786 return NT_STATUS_OK
;
2789 /* enumerate trusted domains
2790 * (we need to have the list of trustdoms in the cache when we go offline) -
2792 NTSTATUS
wb_cache_trusted_domains(struct winbindd_domain
*domain
,
2793 TALLOC_CTX
*mem_ctx
,
2794 struct netr_DomainTrustList
*trusts
)
2797 struct winbind_cache
*cache
;
2798 struct winbindd_tdc_domain
*dom_list
= NULL
;
2799 size_t num_domains
= 0;
2800 bool retval
= false;
2804 old_status
= domain
->online
;
2806 trusts
->array
= NULL
;
2808 cache
= get_cache(domain
);
2809 if (!cache
|| !cache
->tdb
) {
2813 if (domain
->online
) {
2817 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2818 if (!retval
|| !num_domains
|| !dom_list
) {
2819 TALLOC_FREE(dom_list
);
2824 trusts
->array
= talloc_zero_array(mem_ctx
, struct netr_DomainTrust
, num_domains
);
2825 if (!trusts
->array
) {
2826 TALLOC_FREE(dom_list
);
2827 return NT_STATUS_NO_MEMORY
;
2830 for (i
= 0; i
< num_domains
; i
++) {
2831 struct netr_DomainTrust
*trust
;
2832 struct dom_sid
*sid
;
2833 struct winbindd_domain
*dom
;
2835 dom
= find_domain_from_name_noinit(dom_list
[i
].domain_name
);
2836 if (dom
&& dom
->internal
) {
2840 trust
= &trusts
->array
[trusts
->count
];
2841 trust
->netbios_name
= talloc_strdup(trusts
->array
, dom_list
[i
].domain_name
);
2842 trust
->dns_name
= talloc_strdup(trusts
->array
, dom_list
[i
].dns_name
);
2843 sid
= talloc(trusts
->array
, struct dom_sid
);
2844 if (!trust
->netbios_name
|| !trust
->dns_name
||
2846 TALLOC_FREE(dom_list
);
2847 TALLOC_FREE(trusts
->array
);
2848 return NT_STATUS_NO_MEMORY
;
2851 trust
->trust_flags
= dom_list
[i
].trust_flags
;
2852 trust
->trust_attributes
= dom_list
[i
].trust_attribs
;
2853 trust
->trust_type
= dom_list
[i
].trust_type
;
2854 sid_copy(sid
, &dom_list
[i
].sid
);
2859 TALLOC_FREE(dom_list
);
2860 return NT_STATUS_OK
;
2863 /* Return status value returned by seq number check */
2865 if (!NT_STATUS_IS_OK(domain
->last_status
))
2866 return domain
->last_status
;
2868 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2871 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, trusts
);
2873 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2874 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2875 if (!domain
->internal
&& old_status
) {
2876 set_domain_offline(domain
);
2878 if (!domain
->internal
&&
2881 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2882 if (retval
&& num_domains
&& dom_list
) {
2883 TALLOC_FREE(trusts
->array
);
2885 goto do_fetch_cache
;
2889 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2890 * so that the generic centry handling still applies correctly -
2893 if (!NT_STATUS_IS_ERR(status
)) {
2894 status
= NT_STATUS_OK
;
2899 /* get lockout policy */
2900 NTSTATUS
wb_cache_lockout_policy(struct winbindd_domain
*domain
,
2901 TALLOC_CTX
*mem_ctx
,
2902 struct samr_DomInfo12
*policy
)
2904 struct winbind_cache
*cache
= get_cache(domain
);
2905 struct cache_entry
*centry
= NULL
;
2909 old_status
= domain
->online
;
2913 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2919 policy
->lockout_duration
= centry_nttime(centry
);
2920 policy
->lockout_window
= centry_nttime(centry
);
2921 policy
->lockout_threshold
= centry_uint16(centry
);
2923 status
= centry
->status
;
2925 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2926 domain
->name
, nt_errstr(status
) ));
2928 centry_free(centry
);
2932 ZERO_STRUCTP(policy
);
2934 /* Return status value returned by seq number check */
2936 if (!NT_STATUS_IS_OK(domain
->last_status
))
2937 return domain
->last_status
;
2939 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2942 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2944 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2945 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2946 if (!domain
->internal
&& old_status
) {
2947 set_domain_offline(domain
);
2950 !domain
->internal
&&
2953 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2955 goto do_fetch_cache
;
2960 refresh_sequence_number(domain
);
2961 if (!NT_STATUS_IS_OK(status
)) {
2964 wcache_save_lockout_policy(domain
, status
, policy
);
2969 /* get password policy */
2970 NTSTATUS
wb_cache_password_policy(struct winbindd_domain
*domain
,
2971 TALLOC_CTX
*mem_ctx
,
2972 struct samr_DomInfo1
*policy
)
2974 struct winbind_cache
*cache
= get_cache(domain
);
2975 struct cache_entry
*centry
= NULL
;
2979 old_status
= domain
->online
;
2983 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2989 policy
->min_password_length
= centry_uint16(centry
);
2990 policy
->password_history_length
= centry_uint16(centry
);
2991 policy
->password_properties
= centry_uint32(centry
);
2992 policy
->max_password_age
= centry_nttime(centry
);
2993 policy
->min_password_age
= centry_nttime(centry
);
2995 status
= centry
->status
;
2997 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2998 domain
->name
, nt_errstr(status
) ));
3000 centry_free(centry
);
3004 ZERO_STRUCTP(policy
);
3006 /* Return status value returned by seq number check */
3008 if (!NT_STATUS_IS_OK(domain
->last_status
))
3009 return domain
->last_status
;
3011 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
3014 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
3016 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
3017 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
3018 if (!domain
->internal
&& old_status
) {
3019 set_domain_offline(domain
);
3022 !domain
->internal
&&
3025 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
3027 goto do_fetch_cache
;
3032 refresh_sequence_number(domain
);
3033 if (!NT_STATUS_IS_OK(status
)) {
3036 wcache_save_password_policy(domain
, status
, policy
);
3042 /* Invalidate cached user and group lists coherently */
3044 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3047 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
3048 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
3049 tdb_delete(the_tdb
, kbuf
);
3054 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3056 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
3057 const struct dom_sid
*sid
)
3060 struct dom_sid_buf sid_string
;
3061 struct winbind_cache
*cache
;
3063 /* don't clear cached U/SID and UG/SID entries when we want to logon
3066 if (lp_winbind_offline_logon()) {
3073 cache
= get_cache(domain
);
3079 /* Clear U/SID cache entry */
3080 fstr_sprintf(key_str
, "U/%s", dom_sid_str_buf(sid
, &sid_string
));
3081 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3082 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3084 /* Clear UG/SID cache entry */
3085 fstr_sprintf(key_str
, "UG/%s", dom_sid_str_buf(sid
, &sid_string
));
3086 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3087 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3089 /* Samba/winbindd never needs this. */
3090 netsamlogon_clear_cached_user(sid
);
3093 bool wcache_invalidate_cache(void)
3095 struct winbindd_domain
*domain
;
3097 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3098 struct winbind_cache
*cache
= get_cache(domain
);
3100 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3101 "entries for %s\n", domain
->name
));
3104 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3113 bool wcache_invalidate_cache_noinit(void)
3115 struct winbindd_domain
*domain
;
3117 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3118 struct winbind_cache
*cache
;
3120 /* Skip uninitialized domains. */
3121 if (!domain
->initialized
&& !domain
->internal
) {
3125 cache
= get_cache(domain
);
3127 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3128 "entries for %s\n", domain
->name
));
3131 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3133 * Flushing cache has nothing to with domains.
3134 * return here if we successfully flushed once.
3135 * To avoid unnecessary traversing the cache.
3146 static bool init_wcache(void)
3150 if (wcache
== NULL
) {
3151 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
3152 ZERO_STRUCTP(wcache
);
3155 if (wcache
->tdb
!= NULL
)
3158 db_path
= wcache_path();
3159 if (db_path
== NULL
) {
3163 /* when working offline we must not clear the cache on restart */
3164 wcache
->tdb
= tdb_open_log(db_path
,
3165 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3166 TDB_INCOMPATIBLE_HASH
|
3167 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3168 O_RDWR
|O_CREAT
, 0600);
3169 TALLOC_FREE(db_path
);
3170 if (wcache
->tdb
== NULL
) {
3171 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3178 /************************************************************************
3179 This is called by the parent to initialize the cache file.
3180 We don't need sophisticated locking here as we know we're the
3182 ************************************************************************/
3184 bool initialize_winbindd_cache(void)
3186 bool cache_bad
= true;
3189 if (!init_wcache()) {
3190 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3194 /* Check version number. */
3195 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
3196 vers
== WINBINDD_CACHE_VERSION
) {
3203 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3204 "and re-creating with version number %d\n",
3205 WINBINDD_CACHE_VERSION
));
3207 tdb_close(wcache
->tdb
);
3210 db_path
= wcache_path();
3211 if (db_path
== NULL
) {
3215 if (unlink(db_path
) == -1) {
3216 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3219 TALLOC_FREE(db_path
);
3222 TALLOC_FREE(db_path
);
3223 if (!init_wcache()) {
3224 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3225 "init_wcache failed.\n"));
3229 /* Write the version. */
3230 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
3231 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3232 tdb_errorstr(wcache
->tdb
) ));
3237 tdb_close(wcache
->tdb
);
3242 void close_winbindd_cache(void)
3248 tdb_close(wcache
->tdb
);
3253 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*sid
,
3254 char **domain_name
, char **name
,
3255 enum lsa_SidType
*type
)
3257 struct winbindd_domain
*domain
;
3260 domain
= find_lookup_domain_from_sid(sid
);
3261 if (domain
== NULL
) {
3264 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
3266 return NT_STATUS_IS_OK(status
);
3269 bool lookup_cached_name(const char *namespace,
3270 const char *domain_name
,
3272 struct dom_sid
*sid
,
3273 enum lsa_SidType
*type
)
3275 struct winbindd_domain
*domain
;
3277 bool original_online_state
;
3279 domain
= find_lookup_domain_from_name(namespace);
3280 if (domain
== NULL
) {
3284 /* If we are doing a cached logon, temporarily set the domain
3285 offline so the cache won't expire the entry */
3287 original_online_state
= domain
->online
;
3288 domain
->online
= false;
3289 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
3290 domain
->online
= original_online_state
;
3292 return NT_STATUS_IS_OK(status
);
3296 * Cache a name to sid without checking the sequence number.
3297 * Used when caching from a trusted PAC.
3300 void cache_name2sid_trusted(struct winbindd_domain
*domain
,
3301 const char *domain_name
,
3303 enum lsa_SidType type
,
3304 const struct dom_sid
*sid
)
3307 * Ensure we store the mapping with the
3308 * existing sequence number from the cache.
3311 (void)fetch_cache_seqnum(domain
, time(NULL
));
3312 wcache_save_name_to_sid(domain
,
3320 void cache_name2sid(struct winbindd_domain
*domain
,
3321 const char *domain_name
, const char *name
,
3322 enum lsa_SidType type
, const struct dom_sid
*sid
)
3324 refresh_sequence_number(domain
);
3325 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
3330 * The original idea that this cache only contains centries has
3331 * been blurred - now other stuff gets put in here. Ensure we
3332 * ignore these things on cleanup.
3335 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
3336 TDB_DATA dbuf
, void *state
)
3338 struct cache_entry
*centry
;
3340 if (is_non_centry_key(kbuf
)) {
3344 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
3349 if (!NT_STATUS_IS_OK(centry
->status
)) {
3350 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
3351 tdb_delete(the_tdb
, kbuf
);
3354 centry_free(centry
);
3358 /* flush the cache */
3359 static void wcache_flush_cache(void)
3366 tdb_close(wcache
->tdb
);
3369 if (!winbindd_use_cache()) {
3373 db_path
= wcache_path();
3374 if (db_path
== NULL
) {
3378 /* when working offline we must not clear the cache on restart */
3379 wcache
->tdb
= tdb_open_log(db_path
,
3380 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3381 TDB_INCOMPATIBLE_HASH
|
3382 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3383 O_RDWR
|O_CREAT
, 0600);
3384 TALLOC_FREE(db_path
);
3386 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3390 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
3392 DEBUG(10,("wcache_flush_cache success\n"));
3395 /* Count cached creds */
3397 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3400 int *cred_count
= (int*)state
;
3402 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3408 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
3410 struct winbind_cache
*cache
= get_cache(domain
);
3415 return NT_STATUS_INTERNAL_DB_ERROR
;
3418 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
3420 return NT_STATUS_OK
;
3424 struct cred_list
*prev
, *next
;
3429 static struct cred_list
*wcache_cred_list
;
3431 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3434 struct cred_list
*cred
;
3436 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3438 cred
= SMB_MALLOC_P(struct cred_list
);
3440 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3446 /* save a copy of the key */
3448 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
3449 DLIST_ADD(wcache_cred_list
, cred
);
3455 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
3457 struct winbind_cache
*cache
= get_cache(domain
);
3460 struct cred_list
*cred
, *next
, *oldest
= NULL
;
3463 return NT_STATUS_INTERNAL_DB_ERROR
;
3466 /* we possibly already have an entry */
3467 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
3470 struct dom_sid_buf tmp
;
3472 DEBUG(11,("we already have an entry, deleting that\n"));
3474 fstr_sprintf(key_str
, "CRED/%s", dom_sid_str_buf(sid
, &tmp
));
3476 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3478 return NT_STATUS_OK
;
3481 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
3483 return NT_STATUS_OK
;
3484 } else if ((ret
< 0) || (wcache_cred_list
== NULL
)) {
3485 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3488 ZERO_STRUCTP(oldest
);
3490 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
3495 data
= tdb_fetch(cache
->tdb
, string_tdb_data(cred
->name
));
3497 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3499 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3503 t
= IVAL(data
.dptr
, 0);
3504 SAFE_FREE(data
.dptr
);
3507 oldest
= SMB_MALLOC_P(struct cred_list
);
3508 if (oldest
== NULL
) {
3509 status
= NT_STATUS_NO_MEMORY
;
3513 fstrcpy(oldest
->name
, cred
->name
);
3514 oldest
->created
= t
;
3518 if (t
< oldest
->created
) {
3519 fstrcpy(oldest
->name
, cred
->name
);
3520 oldest
->created
= t
;
3524 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3525 status
= NT_STATUS_OK
;
3527 status
= NT_STATUS_UNSUCCESSFUL
;
3530 for (cred
= wcache_cred_list
; cred
; cred
= next
) {
3532 DLIST_REMOVE(wcache_cred_list
, cred
);
3540 /* Change the global online/offline state. */
3541 bool set_global_winbindd_state_offline(void)
3545 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3547 /* Only go offline if someone has created
3548 the key "WINBINDD_OFFLINE" in the cache tdb. */
3550 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3551 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3555 if (!lp_winbind_offline_logon()) {
3556 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3560 if (global_winbindd_offline_state
) {
3561 /* Already offline. */
3565 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
3567 if (!data
.dptr
|| data
.dsize
!= 4) {
3568 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3569 SAFE_FREE(data
.dptr
);
3572 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3573 global_winbindd_offline_state
= true;
3574 SAFE_FREE(data
.dptr
);
3579 void set_global_winbindd_state_online(void)
3581 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3583 if (!lp_winbind_offline_logon()) {
3584 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3588 if (!global_winbindd_offline_state
) {
3589 /* Already online. */
3592 global_winbindd_offline_state
= false;
3598 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3599 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3602 bool get_global_winbindd_state_offline(void)
3604 return global_winbindd_offline_state
;
3607 /***********************************************************************
3608 Validate functions for all possible cache tdb keys.
3609 ***********************************************************************/
3611 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3612 struct tdb_validation_status
*state
)
3614 struct cache_entry
*centry
;
3616 centry
= SMB_XMALLOC_P(struct cache_entry
);
3617 centry
->data
= (unsigned char *)smb_memdup(data
.dptr
, data
.dsize
);
3618 if (!centry
->data
) {
3622 centry
->len
= data
.dsize
;
3625 if (centry
->len
< 16) {
3626 /* huh? corrupt cache? */
3627 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3628 "(len < 16) ?\n", kstr
));
3629 centry_free(centry
);
3630 state
->bad_entry
= true;
3631 state
->success
= false;
3635 centry
->status
= NT_STATUS(centry_uint32(centry
));
3636 centry
->sequence_number
= centry_uint32(centry
);
3637 centry
->timeout
= centry_uint64_t(centry
);
3641 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3642 struct tdb_validation_status
*state
)
3644 if (dbuf
.dsize
!= 8) {
3645 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3646 keystr
, (unsigned int)dbuf
.dsize
));
3647 state
->bad_entry
= true;
3653 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3654 struct tdb_validation_status
*state
)
3656 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3663 (void)centry_string(centry
, mem_ctx
);
3664 (void)centry_string(centry
, mem_ctx
);
3665 (void)centry_string(centry
, mem_ctx
);
3666 (void)centry_string(centry
, mem_ctx
);
3667 (void)centry_string(centry
, mem_ctx
);
3668 (void)centry_uint32(centry
);
3669 (void)centry_uint32(centry
);
3670 (void)centry_string(centry
, mem_ctx
);
3671 (void)centry_sid(centry
, &sid
);
3672 (void)centry_sid(centry
, &sid
);
3674 centry_free(centry
);
3676 if (!(state
->success
)) {
3679 DEBUG(10,("validate_u: %s ok\n", keystr
));
3683 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3684 struct tdb_validation_status
*state
)
3686 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3692 (void)centry_nttime(centry
);
3693 (void)centry_nttime(centry
);
3694 (void)centry_uint16(centry
);
3696 centry_free(centry
);
3698 if (!(state
->success
)) {
3701 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3705 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3706 struct tdb_validation_status
*state
)
3708 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3714 (void)centry_uint16(centry
);
3715 (void)centry_uint16(centry
);
3716 (void)centry_uint32(centry
);
3717 (void)centry_nttime(centry
);
3718 (void)centry_nttime(centry
);
3720 centry_free(centry
);
3722 if (!(state
->success
)) {
3725 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3729 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3730 struct tdb_validation_status
*state
)
3732 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3738 (void)centry_time(centry
);
3739 (void)centry_hash16(centry
, mem_ctx
);
3741 /* We only have 17 bytes more data in the salted cred case. */
3742 if (centry
->len
- centry
->ofs
== 17) {
3743 (void)centry_hash16(centry
, mem_ctx
);
3746 centry_free(centry
);
3748 if (!(state
->success
)) {
3751 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3755 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3756 struct tdb_validation_status
*state
)
3758 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3759 int32_t num_entries
, i
;
3765 num_entries
= (int32_t)centry_uint32(centry
);
3767 for (i
=0; i
< num_entries
; i
++) {
3768 (void)centry_uint32(centry
);
3771 centry_free(centry
);
3773 if (!(state
->success
)) {
3776 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3780 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3781 struct tdb_validation_status
*state
)
3783 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3784 int32_t num_entries
, i
;
3790 num_entries
= centry_uint32(centry
);
3792 for (i
=0; i
< num_entries
; i
++) {
3793 (void)centry_string(centry
, mem_ctx
);
3794 (void)centry_string(centry
, mem_ctx
);
3795 (void)centry_uint32(centry
);
3798 centry_free(centry
);
3800 if (!(state
->success
)) {
3803 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3807 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3808 struct tdb_validation_status
*state
)
3810 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3811 int32_t num_groups
, i
;
3817 num_groups
= centry_uint32(centry
);
3819 for (i
=0; i
< num_groups
; i
++) {
3821 centry_sid(centry
, &sid
);
3824 centry_free(centry
);
3826 if (!(state
->success
)) {
3829 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3833 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3834 struct tdb_validation_status
*state
)
3836 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3837 int32_t num_aliases
, i
;
3843 num_aliases
= centry_uint32(centry
);
3845 for (i
=0; i
< num_aliases
; i
++) {
3846 (void)centry_uint32(centry
);
3849 centry_free(centry
);
3851 if (!(state
->success
)) {
3854 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3858 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3859 struct tdb_validation_status
*state
)
3861 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3862 int32_t num_names
, i
;
3868 num_names
= centry_uint32(centry
);
3870 for (i
=0; i
< num_names
; i
++) {
3872 centry_sid(centry
, &sid
);
3873 (void)centry_string(centry
, mem_ctx
);
3874 (void)centry_uint32(centry
);
3877 centry_free(centry
);
3879 if (!(state
->success
)) {
3882 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3886 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3887 struct tdb_validation_status
*state
)
3889 /* Can't say anything about this other than must be nonzero. */
3890 if (dbuf
.dsize
== 0) {
3891 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3893 state
->bad_entry
= true;
3894 state
->success
= false;
3898 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3902 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3903 struct tdb_validation_status
*state
)
3905 /* Can't say anything about this other than must be nonzero. */
3906 if (dbuf
.dsize
== 0) {
3907 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3909 state
->bad_entry
= true;
3910 state
->success
= false;
3914 DEBUG(10,("validate_de: %s ok\n", keystr
));
3918 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3920 struct tdb_validation_status
*state
)
3922 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3928 (void)centry_string( centry
, mem_ctx
);
3930 centry_free(centry
);
3932 if (!(state
->success
)) {
3935 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3939 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3941 struct tdb_validation_status
*state
)
3943 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3949 (void)centry_string( centry
, mem_ctx
);
3951 centry_free(centry
);
3953 if (!(state
->success
)) {
3956 DBG_DEBUG("%s ok\n", keystr
);
3960 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3962 struct tdb_validation_status
*state
)
3964 if (dbuf
.dsize
== 0) {
3965 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3966 "key %s (len ==0) ?\n", keystr
));
3967 state
->bad_entry
= true;
3968 state
->success
= false;
3972 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3973 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3977 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3978 struct tdb_validation_status
*state
)
3980 if (dbuf
.dsize
!= 4) {
3981 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3982 keystr
, (unsigned int)dbuf
.dsize
));
3983 state
->bad_entry
= true;
3984 state
->success
= false;
3987 DEBUG(10,("validate_offline: %s ok\n", keystr
));
3991 static int validate_ndr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3992 struct tdb_validation_status
*state
)
3995 * Ignore validation for now. The proper way to do this is with a
3996 * checksum. Just pure parsing does not really catch much.
4001 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
4002 struct tdb_validation_status
*state
)
4004 if (dbuf
.dsize
!= 4) {
4005 DEBUG(0, ("validate_cache_version: Corrupt cache for "
4006 "key %s (len %u != 4) ?\n",
4007 keystr
, (unsigned int)dbuf
.dsize
));
4008 state
->bad_entry
= true;
4009 state
->success
= false;
4013 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
4017 /***********************************************************************
4018 A list of all possible cache tdb keys with associated validation
4020 ***********************************************************************/
4022 struct key_val_struct
{
4023 const char *keyname
;
4024 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
4026 {"SEQNUM/", validate_seqnum
},
4028 {"LOC_POL/", validate_loc_pol
},
4029 {"PWD_POL/", validate_pwd_pol
},
4030 {"CRED/", validate_cred
},
4031 {"UL/", validate_ul
},
4032 {"GL/", validate_gl
},
4033 {"UG/", validate_ug
},
4034 {"UA", validate_ua
},
4035 {"GM/", validate_gm
},
4036 {"DR/", validate_dr
},
4037 {"DE/", validate_de
},
4038 {"TRUSTDOMCACHE/", validate_trustdomcache
},
4039 {"NSS/NA/", validate_nss_na
},
4040 {"NSS/AN/", validate_nss_an
},
4041 {"WINBINDD_OFFLINE", validate_offline
},
4042 {"NDR/", validate_ndr
},
4043 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
4047 /***********************************************************************
4048 Function to look at every entry in the tdb and validate it as far as
4050 ***********************************************************************/
4052 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
4055 unsigned int max_key_len
= 1024;
4056 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
4058 /* Paranoia check. */
4059 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0 ||
4060 strncmp("NDR/", (const char *)kbuf
.dptr
, 4) == 0) {
4061 max_key_len
= 1024 * 1024;
4063 if (kbuf
.dsize
> max_key_len
) {
4064 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4066 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
4070 for (i
= 0; key_val
[i
].keyname
; i
++) {
4071 size_t namelen
= strlen(key_val
[i
].keyname
);
4072 if (kbuf
.dsize
>= namelen
&& (
4073 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
4074 TALLOC_CTX
*mem_ctx
;
4078 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
4082 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
4083 keystr
[kbuf
.dsize
] = '\0';
4085 mem_ctx
= talloc_init("validate_ctx");
4091 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
4095 talloc_destroy(mem_ctx
);
4100 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4101 dump_data(0, (uint8_t *)kbuf
.dptr
, kbuf
.dsize
);
4102 DEBUG(0,("data :\n"));
4103 dump_data(0, (uint8_t *)dbuf
.dptr
, dbuf
.dsize
);
4104 v_state
->unknown_key
= true;
4105 v_state
->success
= false;
4106 return 1; /* terminate. */
4109 static void validate_panic(const char *const why
)
4111 DEBUG(0,("validating cache: would panic %s\n", why
));
4112 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4116 static int wbcache_update_centry_fn(TDB_CONTEXT
*tdb
,
4124 if (is_non_centry_key(key
)) {
4128 if (data
.dptr
== NULL
|| data
.dsize
== 0) {
4129 if (tdb_delete(tdb
, key
) < 0) {
4130 DEBUG(0, ("tdb_delete for [%s] failed!\n",
4136 /* add timeout to blob (uint64_t) */
4137 blob
.dsize
= data
.dsize
+ 8;
4139 blob
.dptr
= SMB_XMALLOC_ARRAY(uint8_t, blob
.dsize
);
4140 if (blob
.dptr
== NULL
) {
4143 memset(blob
.dptr
, 0, blob
.dsize
);
4145 /* copy status and seqnum */
4146 memcpy(blob
.dptr
, data
.dptr
, 8);
4149 ctimeout
= lp_winbind_cache_time() + time(NULL
);
4150 SBVAL(blob
.dptr
, 8, ctimeout
);
4153 memcpy(blob
.dptr
+ 16, data
.dptr
+ 8, data
.dsize
- 8);
4155 if (tdb_store(tdb
, key
, blob
, TDB_REPLACE
) < 0) {
4156 DEBUG(0, ("tdb_store to update [%s] failed!\n",
4158 SAFE_FREE(blob
.dptr
);
4162 SAFE_FREE(blob
.dptr
);
4166 static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT
*tdb
)
4170 DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
4172 rc
= tdb_traverse(tdb
, wbcache_update_centry_fn
, NULL
);
4180 /***********************************************************************
4181 Try and validate every entry in the winbindd cache. If we fail here,
4182 delete the cache tdb and return non-zero.
4183 ***********************************************************************/
4185 int winbindd_validate_cache(void)
4188 char *tdb_path
= NULL
;
4189 TDB_CONTEXT
*tdb
= NULL
;
4193 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4194 smb_panic_fn
= validate_panic
;
4196 tdb_path
= wcache_path();
4197 if (tdb_path
== NULL
) {
4201 tdb
= tdb_open_log(tdb_path
,
4202 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
4203 TDB_INCOMPATIBLE_HASH
|
4204 ( lp_winbind_offline_logon()
4206 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
4210 DEBUG(0, ("winbindd_validate_cache: "
4211 "error opening/initializing tdb\n"));
4215 /* Version check and upgrade code. */
4216 if (!tdb_fetch_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers_id
)) {
4217 DEBUG(10, ("Fresh database\n"));
4218 tdb_store_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
);
4219 vers_id
= WINBINDD_CACHE_VERSION
;
4222 if (vers_id
!= WINBINDD_CACHE_VERSION
) {
4223 if (vers_id
== WINBINDD_CACHE_VER1
) {
4224 ok
= wbcache_upgrade_v1_to_v2(tdb
);
4226 DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
4231 tdb_store_uint32(tdb
,
4232 WINBINDD_CACHE_VERSION_KEYSTR
,
4233 WINBINDD_CACHE_VERSION
);
4234 vers_id
= WINBINDD_CACHE_VER2
;
4240 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
4243 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4244 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
4249 TALLOC_FREE(tdb_path
);
4250 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4251 smb_panic_fn
= smb_panic
;
4255 /***********************************************************************
4256 Try and validate every entry in the winbindd cache.
4257 ***********************************************************************/
4259 int winbindd_validate_cache_nobackup(void)
4264 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4265 smb_panic_fn
= validate_panic
;
4267 tdb_path
= wcache_path();
4268 if (tdb_path
== NULL
) {
4269 goto err_panic_restore
;
4272 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
4273 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
4275 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
4279 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4283 TALLOC_FREE(tdb_path
);
4285 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4287 smb_panic_fn
= smb_panic
;
4291 bool winbindd_cache_validate_and_initialize(void)
4293 close_winbindd_cache();
4295 if (lp_winbind_offline_logon()) {
4296 if (winbindd_validate_cache() < 0) {
4297 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4298 "could be restored.\n"));
4302 return initialize_winbindd_cache();
4305 /*********************************************************************
4306 ********************************************************************/
4308 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
4309 struct winbindd_tdc_domain
**domains
,
4310 size_t *num_domains
)
4312 struct winbindd_tdc_domain
*list
= NULL
;
4314 bool set_only
= false;
4316 /* don't allow duplicates */
4321 for ( i
=0; i
< (*num_domains
); i
++ ) {
4322 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
4323 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4334 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, 1 );
4337 list
= talloc_realloc( *domains
, *domains
,
4338 struct winbindd_tdc_domain
,
4343 ZERO_STRUCT( list
[idx
] );
4349 list
[idx
].domain_name
= talloc_strdup(list
, new_dom
->name
);
4350 if (list
[idx
].domain_name
== NULL
) {
4353 if (new_dom
->alt_name
!= NULL
) {
4354 list
[idx
].dns_name
= talloc_strdup(list
, new_dom
->alt_name
);
4355 if (list
[idx
].dns_name
== NULL
) {
4360 if ( !is_null_sid( &new_dom
->sid
) ) {
4361 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
4363 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
4366 if ( new_dom
->domain_flags
!= 0x0 )
4367 list
[idx
].trust_flags
= new_dom
->domain_flags
;
4369 if ( new_dom
->domain_type
!= 0x0 )
4370 list
[idx
].trust_type
= new_dom
->domain_type
;
4372 if ( new_dom
->domain_trust_attribs
!= 0x0 )
4373 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
4377 *num_domains
= idx
+ 1;
4383 /*********************************************************************
4384 ********************************************************************/
4386 static TDB_DATA
make_tdc_key( const char *domain_name
)
4388 char *keystr
= NULL
;
4389 TDB_DATA key
= { NULL
, 0 };
4391 if ( !domain_name
) {
4392 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4396 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
4399 key
= string_term_tdb_data(keystr
);
4404 /*********************************************************************
4405 ********************************************************************/
4407 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
4409 unsigned char **buf
)
4411 unsigned char *buffer
= NULL
;
4416 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4424 /* Store the number of array items first */
4425 len
+= tdb_pack( buffer
? buffer
+len
: NULL
,
4426 buffer
? buflen
-len
: 0, "d",
4429 /* now pack each domain trust record */
4430 for ( i
=0; i
<num_domains
; i
++ ) {
4432 struct dom_sid_buf tmp
;
4435 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4436 domains
[i
].domain_name
,
4437 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
4440 len
+= tdb_pack( buffer
? buffer
+len
: NULL
,
4441 buffer
? buflen
-len
: 0, "fffddd",
4442 domains
[i
].domain_name
,
4443 domains
[i
].dns_name
? domains
[i
].dns_name
: "",
4444 dom_sid_str_buf(&domains
[i
].sid
, &tmp
),
4445 domains
[i
].trust_flags
,
4446 domains
[i
].trust_attribs
,
4447 domains
[i
].trust_type
);
4450 if ( buflen
< len
) {
4452 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
4453 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4467 /*********************************************************************
4468 ********************************************************************/
4470 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
4471 struct winbindd_tdc_domain
**domains
)
4473 fstring domain_name
, dns_name
, sid_string
;
4474 uint32_t type
, attribs
, flags
;
4478 struct winbindd_tdc_domain
*list
= NULL
;
4480 /* get the number of domains */
4481 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
4483 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4487 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, num_domains
);
4489 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4493 for ( i
=0; i
<num_domains
; i
++ ) {
4496 this_len
= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
4504 if ( this_len
== -1 ) {
4505 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4506 TALLOC_FREE( list
);
4511 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4512 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4513 domain_name
, dns_name
, sid_string
,
4514 flags
, attribs
, type
));
4516 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
4517 list
[i
].dns_name
= NULL
;
4518 if (dns_name
[0] != '\0') {
4519 list
[i
].dns_name
= talloc_strdup(list
, dns_name
);
4521 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
4522 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4525 list
[i
].trust_flags
= flags
;
4526 list
[i
].trust_attribs
= attribs
;
4527 list
[i
].trust_type
= type
;
4535 /*********************************************************************
4536 ********************************************************************/
4538 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
4540 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4541 TDB_DATA data
= { NULL
, 0 };
4547 /* See if we were asked to delete the cache entry */
4550 ret
= tdb_delete( wcache
->tdb
, key
);
4554 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4561 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4564 SAFE_FREE( data
.dptr
);
4565 SAFE_FREE( key
.dptr
);
4567 return ( ret
== 0 );
4570 /*********************************************************************
4571 ********************************************************************/
4573 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4575 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4576 TDB_DATA data
= { NULL
, 0 };
4584 data
= tdb_fetch( wcache
->tdb
, key
);
4586 SAFE_FREE( key
.dptr
);
4591 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4593 SAFE_FREE( data
.dptr
);
4601 /*********************************************************************
4602 ********************************************************************/
4604 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4606 struct winbindd_tdc_domain
*dom_list
= NULL
;
4607 size_t num_domains
= 0;
4609 struct dom_sid_buf buf
;
4611 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4612 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4613 domain
->name
, domain
->alt_name
,
4614 dom_sid_str_buf(&domain
->sid
, &buf
),
4615 domain
->domain_flags
,
4616 domain
->domain_trust_attribs
,
4617 domain
->domain_type
));
4619 if ( !init_wcache() ) {
4623 /* fetch the list */
4625 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4627 /* add the new domain */
4629 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4633 /* pack the domain */
4635 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4643 TALLOC_FREE( dom_list
);
4648 static struct winbindd_tdc_domain
*wcache_tdc_dup_domain(
4649 TALLOC_CTX
*mem_ctx
, const struct winbindd_tdc_domain
*src
)
4651 struct winbindd_tdc_domain
*dst
;
4653 dst
= talloc(mem_ctx
, struct winbindd_tdc_domain
);
4657 dst
->domain_name
= talloc_strdup(dst
, src
->domain_name
);
4658 if (dst
->domain_name
== NULL
) {
4662 dst
->dns_name
= NULL
;
4663 if (src
->dns_name
!= NULL
) {
4664 dst
->dns_name
= talloc_strdup(dst
, src
->dns_name
);
4665 if (dst
->dns_name
== NULL
) {
4670 sid_copy(&dst
->sid
, &src
->sid
);
4671 dst
->trust_flags
= src
->trust_flags
;
4672 dst
->trust_type
= src
->trust_type
;
4673 dst
->trust_attribs
= src
->trust_attribs
;
4680 /*********************************************************************
4681 ********************************************************************/
4683 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4685 struct winbindd_tdc_domain
*dom_list
= NULL
;
4686 size_t num_domains
= 0;
4688 struct winbindd_tdc_domain
*d
= NULL
;
4690 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4692 if ( !init_wcache() ) {
4696 /* fetch the list */
4698 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4700 for ( i
=0; i
<num_domains
; i
++ ) {
4701 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4702 strequal(name
, dom_list
[i
].dns_name
) )
4704 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4707 d
= wcache_tdc_dup_domain(ctx
, &dom_list
[i
]);
4712 TALLOC_FREE( dom_list
);
4717 /*********************************************************************
4718 ********************************************************************/
4720 void wcache_tdc_clear( void )
4722 if ( !init_wcache() )
4725 wcache_tdc_store_list( NULL
, 0 );
4730 static bool wcache_ndr_key(TALLOC_CTX
*mem_ctx
, const char *domain_name
,
4731 uint32_t opnum
, const DATA_BLOB
*req
,
4737 key
= talloc_asprintf(mem_ctx
, "NDR/%s/%d/", domain_name
, (int)opnum
);
4741 keylen
= talloc_get_size(key
) - 1;
4743 key
= talloc_realloc(mem_ctx
, key
, char, keylen
+ req
->length
);
4747 memcpy(key
+ keylen
, req
->data
, req
->length
);
4749 pkey
->dptr
= (uint8_t *)key
;
4750 pkey
->dsize
= talloc_get_size(key
);
4754 static bool wcache_opnum_cacheable(uint32_t opnum
)
4757 case NDR_WBINT_PING
:
4758 case NDR_WBINT_QUERYSEQUENCENUMBER
:
4759 case NDR_WBINT_ALLOCATEUID
:
4760 case NDR_WBINT_ALLOCATEGID
:
4761 case NDR_WBINT_CHECKMACHINEACCOUNT
:
4762 case NDR_WBINT_CHANGEMACHINEACCOUNT
:
4763 case NDR_WBINT_PINGDC
:
4769 bool wcache_fetch_ndr(TALLOC_CTX
*mem_ctx
, struct winbindd_domain
*domain
,
4770 uint32_t opnum
, const DATA_BLOB
*req
, DATA_BLOB
*resp
)
4775 if (!wcache_opnum_cacheable(opnum
) ||
4776 is_my_own_sam_domain(domain
) ||
4777 is_builtin_domain(domain
)) {
4781 if (wcache
->tdb
== NULL
) {
4785 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4788 data
= tdb_fetch(wcache
->tdb
, key
);
4789 TALLOC_FREE(key
.dptr
);
4791 if (data
.dptr
== NULL
) {
4794 if (data
.dsize
< 12) {
4798 if (is_domain_online(domain
)) {
4799 uint32_t entry_seqnum
, dom_seqnum
, last_check
;
4800 uint64_t entry_timeout
;
4802 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
,
4806 entry_seqnum
= IVAL(data
.dptr
, 0);
4807 if (entry_seqnum
!= dom_seqnum
) {
4808 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4809 (int)entry_seqnum
));
4812 entry_timeout
= BVAL(data
.dptr
, 4);
4813 if (time(NULL
) > (time_t)entry_timeout
) {
4814 DEBUG(10, ("Entry has timed out\n"));
4819 resp
->data
= (uint8_t *)talloc_memdup(mem_ctx
, data
.dptr
+ 12,
4821 if (resp
->data
== NULL
) {
4822 DEBUG(10, ("talloc failed\n"));
4825 resp
->length
= data
.dsize
- 12;
4829 SAFE_FREE(data
.dptr
);
4833 void wcache_store_ndr(struct winbindd_domain
*domain
, uint32_t opnum
,
4834 const DATA_BLOB
*req
, const DATA_BLOB
*resp
)
4837 uint32_t dom_seqnum
, last_check
;
4840 if (!wcache_opnum_cacheable(opnum
) ||
4841 is_my_own_sam_domain(domain
) ||
4842 is_builtin_domain(domain
)) {
4846 if (wcache
->tdb
== NULL
) {
4850 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
, &last_check
)) {
4851 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4856 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4860 timeout
= time(NULL
) + lp_winbind_cache_time();
4862 data
.dsize
= resp
->length
+ 12;
4863 data
.dptr
= talloc_array(key
.dptr
, uint8_t, data
.dsize
);
4864 if (data
.dptr
== NULL
) {
4868 SIVAL(data
.dptr
, 0, dom_seqnum
);
4869 SBVAL(data
.dptr
, 4, timeout
);
4870 memcpy(data
.dptr
+ 12, resp
->data
, resp
->length
);
4872 tdb_store(wcache
->tdb
, key
, data
, 0);
4875 TALLOC_FREE(key
.dptr
);