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"
41 #define DBGC_CLASS DBGC_WINBIND
43 #define WINBINDD_CACHE_VER1 1 /* initial db version */
44 #define WINBINDD_CACHE_VER2 2 /* second version with timeouts for NDR entries */
46 #define WINBINDD_CACHE_VERSION WINBINDD_CACHE_VER2
47 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
49 extern struct winbindd_methods reconnect_methods
;
51 extern struct winbindd_methods reconnect_ads_methods
;
53 extern struct winbindd_methods builtin_passdb_methods
;
54 extern struct winbindd_methods sam_passdb_methods
;
56 static void wcache_flush_cache(void);
59 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
60 * Here are the list of entry types that are *not* stored
61 * as form struct cache_entry in the cache.
64 static const char *non_centry_keys
[] = {
67 WINBINDD_CACHE_VERSION_KEYSTR
,
71 /************************************************************************
72 Is this key a non-centry type ?
73 ************************************************************************/
75 static bool is_non_centry_key(TDB_DATA kbuf
)
79 if (kbuf
.dptr
== NULL
|| kbuf
.dsize
== 0) {
82 for (i
= 0; non_centry_keys
[i
] != NULL
; i
++) {
83 size_t namelen
= strlen(non_centry_keys
[i
]);
84 if (kbuf
.dsize
< namelen
) {
87 if (strncmp(non_centry_keys
[i
], (const char *)kbuf
.dptr
, namelen
) == 0) {
94 /* Global online/offline state - False when online. winbindd starts up online
95 and sets this to true if the first query fails and there's an entry in
96 the cache tdb telling us to stay offline. */
98 static bool global_winbindd_offline_state
;
100 struct winbind_cache
{
106 uint32_t sequence_number
;
112 void (*smb_panic_fn
)(const char *const why
) = smb_panic
;
114 static struct winbind_cache
*wcache
;
116 static char *wcache_path(void)
119 * Data needs to be kept persistent in state directory for
120 * running with "winbindd offline logon".
122 return state_path("winbindd_cache.tdb");
125 static void winbindd_domain_init_backend(struct winbindd_domain
*domain
)
127 if (domain
->backend
!= NULL
) {
131 if (domain
->internal
) {
132 domain
->backend
= &builtin_passdb_methods
;
135 if (dom_sid_equal(&domain
->sid
, &global_sid_Builtin
)) {
136 domain
->initialized
= true;
139 if (strequal(domain
->name
, get_global_sam_name()) &&
140 sid_check_is_our_sam(&domain
->sid
))
142 domain
->backend
= &sam_passdb_methods
;
145 if (!domain
->initialized
) {
146 /* We do not need a connection to an RW DC for cache operation */
147 init_dc_connection(domain
, false);
151 if (domain
->backend
== NULL
) {
152 struct winbindd_domain
*our_domain
= domain
;
154 /* find our domain first so we can figure out if we
155 are joined to a kerberized domain */
157 if (!domain
->primary
) {
158 our_domain
= find_our_domain();
161 if ((our_domain
->active_directory
|| IS_DC
)
162 && domain
->active_directory
163 && !lp_winbind_rpc_only())
165 DBG_INFO("Setting ADS methods for domain %s\n",
167 domain
->backend
= &reconnect_ads_methods
;
170 #endif /* HAVE_ADS */
172 if (domain
->backend
== NULL
) {
173 DBG_INFO("Setting MS-RPC methods for domain %s\n", domain
->name
);
174 domain
->backend
= &reconnect_methods
;
178 /* get the winbind_cache structure */
179 static struct winbind_cache
*get_cache(struct winbindd_domain
*domain
)
181 struct winbind_cache
*ret
= wcache
;
183 winbindd_domain_init_backend(domain
);
189 ret
= SMB_XMALLOC_P(struct winbind_cache
);
193 wcache_flush_cache();
199 free a centry structure
201 static void centry_free(struct cache_entry
*centry
)
205 SAFE_FREE(centry
->data
);
209 static bool centry_check_bytes(struct cache_entry
*centry
, size_t nbytes
)
211 if (centry
->len
- centry
->ofs
< nbytes
) {
212 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
213 (unsigned int)nbytes
,
214 centry
->len
- centry
->ofs
));
221 pull a uint64_t from a cache entry
223 static uint64_t centry_uint64_t(struct cache_entry
*centry
)
227 if (!centry_check_bytes(centry
, 8)) {
228 smb_panic_fn("centry_uint64_t");
230 ret
= BVAL(centry
->data
, centry
->ofs
);
236 pull a uint32_t from a cache entry
238 static uint32_t centry_uint32(struct cache_entry
*centry
)
242 if (!centry_check_bytes(centry
, 4)) {
243 smb_panic_fn("centry_uint32");
245 ret
= IVAL(centry
->data
, centry
->ofs
);
251 pull a uint16_t from a cache entry
253 static uint16_t centry_uint16(struct cache_entry
*centry
)
256 if (!centry_check_bytes(centry
, 2)) {
257 smb_panic_fn("centry_uint16");
259 ret
= SVAL(centry
->data
, centry
->ofs
);
265 pull a uint8_t from a cache entry
267 static uint8_t centry_uint8(struct cache_entry
*centry
)
270 if (!centry_check_bytes(centry
, 1)) {
271 smb_panic_fn("centry_uint8");
273 ret
= CVAL(centry
->data
, centry
->ofs
);
279 pull a NTTIME from a cache entry
281 static NTTIME
centry_nttime(struct cache_entry
*centry
)
284 if (!centry_check_bytes(centry
, 8)) {
285 smb_panic_fn("centry_nttime");
287 ret
= IVAL(centry
->data
, centry
->ofs
);
289 ret
+= (uint64_t)IVAL(centry
->data
, centry
->ofs
) << 32;
295 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
297 static time_t centry_time(struct cache_entry
*centry
)
299 return (time_t)centry_nttime(centry
);
302 /* pull a string from a cache entry, using the supplied
305 static char *centry_string(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
310 len
= centry_uint8(centry
);
313 /* a deliberate NULL string */
317 if (!centry_check_bytes(centry
, (size_t)len
)) {
318 smb_panic_fn("centry_string");
321 ret
= talloc_array(mem_ctx
, char, len
+1);
323 smb_panic_fn("centry_string out of memory\n");
325 memcpy(ret
,centry
->data
+ centry
->ofs
, len
);
331 /* pull a hash16 from a cache entry, using the supplied
334 static char *centry_hash16(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
339 len
= centry_uint8(centry
);
342 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
347 if (!centry_check_bytes(centry
, 16)) {
351 ret
= talloc_array(mem_ctx
, char, 16);
353 smb_panic_fn("centry_hash out of memory\n");
355 memcpy(ret
,centry
->data
+ centry
->ofs
, 16);
360 /* pull a sid from a cache entry, using the supplied
363 static bool centry_sid(struct cache_entry
*centry
, struct dom_sid
*sid
)
368 sid_string
= centry_string(centry
, talloc_tos());
369 if (sid_string
== NULL
) {
372 ret
= string_to_sid(sid
, sid_string
);
373 TALLOC_FREE(sid_string
);
379 pull a NTSTATUS from a cache entry
381 static NTSTATUS
centry_ntstatus(struct cache_entry
*centry
)
385 status
= NT_STATUS(centry_uint32(centry
));
390 /* the server is considered down if it can't give us a sequence number */
391 static bool wcache_server_down(struct winbindd_domain
*domain
)
398 ret
= (domain
->sequence_number
== DOM_SEQUENCE_NONE
);
401 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
406 struct wcache_seqnum_state
{
408 uint32_t *last_seq_check
;
411 static int wcache_seqnum_parser(TDB_DATA key
, TDB_DATA data
,
414 struct wcache_seqnum_state
*state
= private_data
;
416 if (data
.dsize
!= 8) {
417 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
422 *state
->seqnum
= IVAL(data
.dptr
, 0);
423 *state
->last_seq_check
= IVAL(data
.dptr
, 4);
427 static bool wcache_fetch_seqnum(const char *domain_name
, uint32_t *seqnum
,
428 uint32_t *last_seq_check
)
430 struct wcache_seqnum_state state
= {
431 .seqnum
= seqnum
, .last_seq_check
= last_seq_check
433 size_t len
= strlen(domain_name
);
435 TDB_DATA key
= { .dptr
= (uint8_t *)keystr
, .dsize
= sizeof(keystr
) };
438 if (wcache
->tdb
== NULL
) {
439 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
443 snprintf(keystr
, sizeof(keystr
), "SEQNUM/%s", domain_name
);
445 ret
= tdb_parse_record(wcache
->tdb
, key
, wcache_seqnum_parser
,
450 static NTSTATUS
fetch_cache_seqnum( struct winbindd_domain
*domain
, time_t now
)
452 uint32_t last_check
, time_diff
;
454 if (!wcache_fetch_seqnum(domain
->name
, &domain
->sequence_number
,
456 return NT_STATUS_UNSUCCESSFUL
;
458 domain
->last_seq_check
= last_check
;
460 /* have we expired? */
462 time_diff
= now
- domain
->last_seq_check
;
463 if ((int)time_diff
> lp_winbind_cache_time()) {
464 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
465 domain
->name
, domain
->sequence_number
,
466 (uint32_t)domain
->last_seq_check
));
467 return NT_STATUS_UNSUCCESSFUL
;
470 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
471 domain
->name
, domain
->sequence_number
,
472 (uint32_t)domain
->last_seq_check
));
477 bool wcache_store_seqnum(const char *domain_name
, uint32_t seqnum
,
478 time_t last_seq_check
)
480 size_t len
= strlen(domain_name
);
482 TDB_DATA key
= { .dptr
= (uint8_t *)keystr
, .dsize
= sizeof(keystr
) };
486 if (wcache
->tdb
== NULL
) {
487 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
491 snprintf(keystr
, sizeof(keystr
), "SEQNUM/%s", domain_name
);
493 SIVAL(buf
, 0, seqnum
);
494 SIVAL(buf
, 4, last_seq_check
);
496 ret
= tdb_store(wcache
->tdb
, key
, make_tdb_data(buf
, sizeof(buf
)),
499 DEBUG(10, ("tdb_store_bystring failed: %s\n",
500 tdb_errorstr(wcache
->tdb
)));
504 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
505 domain_name
, seqnum
, (unsigned)last_seq_check
));
510 static bool store_cache_seqnum( struct winbindd_domain
*domain
)
512 return wcache_store_seqnum(domain
->name
, domain
->sequence_number
,
513 domain
->last_seq_check
);
517 refresh the domain sequence number on timeout.
520 static void refresh_sequence_number(struct winbindd_domain
*domain
)
524 time_t t
= time(NULL
);
525 unsigned cache_time
= lp_winbind_cache_time();
527 if (is_domain_offline(domain
)) {
533 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
534 /* trying to reconnect is expensive, don't do it too often */
535 if (domain
->sequence_number
== DOM_SEQUENCE_NONE
) {
540 time_diff
= t
- domain
->last_seq_check
;
542 /* see if we have to refetch the domain sequence number */
543 if ((time_diff
< cache_time
) &&
544 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
545 NT_STATUS_IS_OK(domain
->last_status
)) {
546 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain
->name
));
550 /* try to get the sequence number from the tdb cache first */
551 /* this will update the timestamp as well */
553 status
= fetch_cache_seqnum( domain
, t
);
554 if (NT_STATUS_IS_OK(status
) &&
555 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
556 NT_STATUS_IS_OK(domain
->last_status
)) {
560 /* important! make sure that we know if this is a native
561 mode domain or not. And that we can contact it. */
563 if ( winbindd_can_contact_domain( domain
) ) {
564 status
= domain
->backend
->sequence_number(domain
,
565 &domain
->sequence_number
);
567 /* just use the current time */
568 status
= NT_STATUS_OK
;
569 domain
->sequence_number
= time(NULL
);
573 /* the above call could have set our domain->backend to NULL when
574 * coming from offline to online mode, make sure to reinitialize the
575 * backend - Guenther */
578 if (!NT_STATUS_IS_OK(status
)) {
579 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status
)));
580 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
583 domain
->last_status
= status
;
584 domain
->last_seq_check
= time(NULL
);
586 /* save the new sequence number in the cache */
587 store_cache_seqnum( domain
);
590 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
591 domain
->name
, domain
->sequence_number
));
597 decide if a cache entry has expired
599 static bool centry_expired(struct winbindd_domain
*domain
, const char *keystr
, struct cache_entry
*centry
)
601 /* If we've been told to be offline - stay in that state... */
602 if (lp_winbind_offline_logon() && global_winbindd_offline_state
) {
603 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
604 keystr
, domain
->name
));
608 /* when the domain is offline return the cached entry.
609 * This deals with transient offline states... */
611 if (!domain
->online
) {
612 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
613 keystr
, domain
->name
));
617 /* if the server is OK and our cache entry came from when it was down then
618 the entry is invalid */
619 if ((domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
620 (centry
->sequence_number
== DOM_SEQUENCE_NONE
)) {
621 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
622 keystr
, domain
->name
));
626 /* if the server is down or the cache entry is not older than the
627 current sequence number or it did not timeout then it is OK */
628 if (wcache_server_down(domain
)
629 || ((centry
->sequence_number
== domain
->sequence_number
)
630 && ((time_t)centry
->timeout
> time(NULL
)))) {
631 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
632 keystr
, domain
->name
));
636 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
637 keystr
, domain
->name
));
643 static struct cache_entry
*wcache_fetch_raw(char *kstr
)
646 struct cache_entry
*centry
;
649 key
= string_tdb_data(kstr
);
650 data
= tdb_fetch(wcache
->tdb
, key
);
656 centry
= SMB_XMALLOC_P(struct cache_entry
);
657 centry
->data
= (unsigned char *)data
.dptr
;
658 centry
->len
= data
.dsize
;
661 if (centry
->len
< 16) {
662 /* huh? corrupt cache? */
663 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s "
664 "(len < 16)?\n", kstr
));
669 centry
->status
= centry_ntstatus(centry
);
670 centry
->sequence_number
= centry_uint32(centry
);
671 centry
->timeout
= centry_uint64_t(centry
);
676 static bool is_my_own_sam_domain(struct winbindd_domain
*domain
)
678 if (strequal(domain
->name
, get_global_sam_name()) &&
679 sid_check_is_our_sam(&domain
->sid
)) {
686 static bool is_builtin_domain(struct winbindd_domain
*domain
)
688 if (strequal(domain
->name
, "BUILTIN") &&
689 sid_check_is_builtin(&domain
->sid
)) {
697 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
698 number and return status
700 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
701 struct winbindd_domain
*domain
,
702 const char *format
, ...) PRINTF_ATTRIBUTE(3,4);
703 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
704 struct winbindd_domain
*domain
,
705 const char *format
, ...)
709 struct cache_entry
*centry
;
711 if (!winbindd_use_cache() ||
712 is_my_own_sam_domain(domain
) ||
713 is_builtin_domain(domain
)) {
717 refresh_sequence_number(domain
);
719 va_start(ap
, format
);
720 smb_xvasprintf(&kstr
, format
, ap
);
723 centry
= wcache_fetch_raw(kstr
);
724 if (centry
== NULL
) {
729 if (centry_expired(domain
, kstr
, centry
)) {
731 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
732 kstr
, domain
->name
));
739 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
740 kstr
, domain
->name
));
746 static void wcache_delete(const char *format
, ...) PRINTF_ATTRIBUTE(1,2);
747 static void wcache_delete(const char *format
, ...)
753 va_start(ap
, format
);
754 smb_xvasprintf(&kstr
, format
, ap
);
757 key
= string_tdb_data(kstr
);
759 tdb_delete(wcache
->tdb
, key
);
764 make sure we have at least len bytes available in a centry
766 static void centry_expand(struct cache_entry
*centry
, uint32_t len
)
768 if (centry
->len
- centry
->ofs
>= len
)
771 centry
->data
= SMB_REALLOC_ARRAY(centry
->data
, unsigned char,
774 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry
->len
));
775 smb_panic_fn("out of memory in centry_expand");
780 push a uint64_t into a centry
782 static void centry_put_uint64_t(struct cache_entry
*centry
, uint64_t v
)
784 centry_expand(centry
, 8);
785 SBVAL(centry
->data
, centry
->ofs
, v
);
790 push a uint32_t into a centry
792 static void centry_put_uint32(struct cache_entry
*centry
, uint32_t v
)
794 centry_expand(centry
, 4);
795 SIVAL(centry
->data
, centry
->ofs
, v
);
800 push a uint16_t into a centry
802 static void centry_put_uint16(struct cache_entry
*centry
, uint16_t v
)
804 centry_expand(centry
, 2);
805 SSVAL(centry
->data
, centry
->ofs
, v
);
810 push a uint8_t into a centry
812 static void centry_put_uint8(struct cache_entry
*centry
, uint8_t v
)
814 centry_expand(centry
, 1);
815 SCVAL(centry
->data
, centry
->ofs
, v
);
820 push a string into a centry
822 static void centry_put_string(struct cache_entry
*centry
, const char *s
)
827 /* null strings are marked as len 0xFFFF */
828 centry_put_uint8(centry
, 0xFF);
833 /* can't handle more than 254 char strings. Truncating is probably best */
835 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len
));
838 centry_put_uint8(centry
, len
);
839 centry_expand(centry
, len
);
840 memcpy(centry
->data
+ centry
->ofs
, s
, len
);
845 push a 16 byte hash into a centry - treat as 16 byte string.
847 static void centry_put_hash16(struct cache_entry
*centry
, const uint8_t val
[16])
849 centry_put_uint8(centry
, 16);
850 centry_expand(centry
, 16);
851 memcpy(centry
->data
+ centry
->ofs
, val
, 16);
855 static void centry_put_sid(struct cache_entry
*centry
, const struct dom_sid
*sid
)
858 centry_put_string(centry
, sid_to_fstring(sid_string
, sid
));
863 put NTSTATUS into a centry
865 static void centry_put_ntstatus(struct cache_entry
*centry
, NTSTATUS status
)
867 uint32_t status_value
= NT_STATUS_V(status
);
868 centry_put_uint32(centry
, status_value
);
873 push a NTTIME into a centry
875 static void centry_put_nttime(struct cache_entry
*centry
, NTTIME nt
)
877 centry_expand(centry
, 8);
878 SIVAL(centry
->data
, centry
->ofs
, nt
& 0xFFFFFFFF);
880 SIVAL(centry
->data
, centry
->ofs
, nt
>> 32);
885 push a time_t into a centry - use a 64 bit size.
886 NTTIME here is being used as a convenient 64-bit size.
888 static void centry_put_time(struct cache_entry
*centry
, time_t t
)
890 NTTIME nt
= (NTTIME
)t
;
891 centry_put_nttime(centry
, nt
);
895 start a centry for output. When finished, call centry_end()
897 static struct cache_entry
*centry_start(struct winbindd_domain
*domain
,
900 struct cache_entry
*centry
;
905 centry
= SMB_XMALLOC_P(struct cache_entry
);
907 centry
->len
= 8192; /* reasonable default */
908 centry
->data
= SMB_XMALLOC_ARRAY(uint8_t, centry
->len
);
910 centry
->sequence_number
= domain
->sequence_number
;
911 centry
->timeout
= lp_winbind_cache_time() + time(NULL
);
912 centry_put_ntstatus(centry
, status
);
913 centry_put_uint32(centry
, centry
->sequence_number
);
914 centry_put_uint64_t(centry
, centry
->timeout
);
919 finish a centry and write it to the tdb
921 static void centry_end(struct cache_entry
*centry
, const char *format
, ...) PRINTF_ATTRIBUTE(2,3);
922 static void centry_end(struct cache_entry
*centry
, const char *format
, ...)
928 if (!winbindd_use_cache()) {
932 va_start(ap
, format
);
933 smb_xvasprintf(&kstr
, format
, ap
);
936 key
= string_tdb_data(kstr
);
937 data
.dptr
= centry
->data
;
938 data
.dsize
= centry
->ofs
;
940 tdb_store(wcache
->tdb
, key
, data
, TDB_REPLACE
);
944 static void wcache_save_name_to_sid(struct winbindd_domain
*domain
,
945 NTSTATUS status
, const char *domain_name
,
946 const char *name
, const struct dom_sid
*sid
,
947 enum lsa_SidType type
)
951 ok
= namemap_cache_set_name2sid(domain_name
, name
, sid
, type
,
952 time(NULL
) + lp_winbind_cache_time());
954 DBG_DEBUG("namemap_cache_set_name2sid failed\n");
958 * Don't store the reverse mapping. The name came from user
959 * input, and we might not have the correct capitalization,
960 * which is important for nsswitch.
964 static void wcache_save_sid_to_name(struct winbindd_domain
*domain
, NTSTATUS status
,
965 const struct dom_sid
*sid
, const char *domain_name
, const char *name
, enum lsa_SidType type
)
969 ok
= namemap_cache_set_sid2name(sid
, domain_name
, name
, type
,
970 time(NULL
) + lp_winbind_cache_time());
972 DBG_DEBUG("namemap_cache_set_sid2name failed\n");
975 if (type
!= SID_NAME_UNKNOWN
) {
976 ok
= namemap_cache_set_name2sid(
977 domain_name
, name
, sid
, type
,
978 time(NULL
) + lp_winbind_cache_time());
980 DBG_DEBUG("namemap_cache_set_name2sid failed\n");
985 static void wcache_save_lockout_policy(struct winbindd_domain
*domain
,
987 struct samr_DomInfo12
*lockout_policy
)
989 struct cache_entry
*centry
;
991 centry
= centry_start(domain
, status
);
995 centry_put_nttime(centry
, lockout_policy
->lockout_duration
);
996 centry_put_nttime(centry
, lockout_policy
->lockout_window
);
997 centry_put_uint16(centry
, lockout_policy
->lockout_threshold
);
999 centry_end(centry
, "LOC_POL/%s", domain
->name
);
1001 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain
->name
));
1003 centry_free(centry
);
1008 static void wcache_save_password_policy(struct winbindd_domain
*domain
,
1010 struct samr_DomInfo1
*policy
)
1012 struct cache_entry
*centry
;
1014 centry
= centry_start(domain
, status
);
1018 centry_put_uint16(centry
, policy
->min_password_length
);
1019 centry_put_uint16(centry
, policy
->password_history_length
);
1020 centry_put_uint32(centry
, policy
->password_properties
);
1021 centry_put_nttime(centry
, policy
->max_password_age
);
1022 centry_put_nttime(centry
, policy
->min_password_age
);
1024 centry_end(centry
, "PWD_POL/%s", domain
->name
);
1026 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
1028 centry_free(centry
);
1031 /***************************************************************************
1032 ***************************************************************************/
1034 static void wcache_save_username_alias(struct winbindd_domain
*domain
,
1036 const char *name
, const char *alias
)
1038 struct cache_entry
*centry
;
1041 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1044 centry_put_string( centry
, alias
);
1046 fstrcpy(uname
, name
);
1047 (void)strupper_m(uname
);
1048 centry_end(centry
, "NSS/NA/%s", uname
);
1050 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name
, alias
));
1052 centry_free(centry
);
1055 static void wcache_save_alias_username(struct winbindd_domain
*domain
,
1057 const char *alias
, const char *name
)
1059 struct cache_entry
*centry
;
1062 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1065 centry_put_string( centry
, name
);
1067 fstrcpy(uname
, alias
);
1068 (void)strupper_m(uname
);
1069 centry_end(centry
, "NSS/AN/%s", uname
);
1071 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias
, name
));
1073 centry_free(centry
);
1076 /***************************************************************************
1077 ***************************************************************************/
1079 NTSTATUS
resolve_username_to_alias( TALLOC_CTX
*mem_ctx
,
1080 struct winbindd_domain
*domain
,
1081 const char *name
, char **alias
)
1083 struct winbind_cache
*cache
= get_cache(domain
);
1084 struct cache_entry
*centry
= NULL
;
1088 if ( domain
->internal
)
1089 return NT_STATUS_NOT_SUPPORTED
;
1094 upper_name
= talloc_strdup_upper(mem_ctx
, name
);
1095 if (upper_name
== NULL
) {
1096 return NT_STATUS_NO_MEMORY
;
1099 centry
= wcache_fetch(cache
, domain
, "NSS/NA/%s", upper_name
);
1101 talloc_free(upper_name
);
1106 status
= centry
->status
;
1108 if (!NT_STATUS_IS_OK(status
)) {
1109 centry_free(centry
);
1113 *alias
= centry_string( centry
, mem_ctx
);
1115 centry_free(centry
);
1117 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1118 name
, *alias
? *alias
: "(none)"));
1120 return (*alias
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1124 /* If its not in cache and we are offline, then fail */
1126 if (is_domain_offline(domain
)) {
1127 DEBUG(8,("resolve_username_to_alias: rejecting query "
1128 "in offline mode\n"));
1129 return NT_STATUS_NOT_FOUND
;
1132 status
= nss_map_to_alias( mem_ctx
, domain
->name
, name
, alias
);
1134 if ( NT_STATUS_IS_OK( status
) ) {
1135 wcache_save_username_alias(domain
, status
, name
, *alias
);
1138 if ( NT_STATUS_EQUAL( status
, NT_STATUS_NONE_MAPPED
) ) {
1139 wcache_save_username_alias(domain
, status
, name
, "(NULL)");
1142 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1143 nt_errstr(status
)));
1145 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1146 set_domain_offline( domain
);
1152 /***************************************************************************
1153 ***************************************************************************/
1155 NTSTATUS
resolve_alias_to_username( TALLOC_CTX
*mem_ctx
,
1156 struct winbindd_domain
*domain
,
1157 const char *alias
, char **name
)
1159 struct winbind_cache
*cache
= get_cache(domain
);
1160 struct cache_entry
*centry
= NULL
;
1164 if ( domain
->internal
)
1165 return NT_STATUS_NOT_SUPPORTED
;
1170 upper_name
= talloc_strdup(mem_ctx
, alias
);
1171 if (upper_name
== NULL
) {
1172 return NT_STATUS_NO_MEMORY
;
1174 if (!strupper_m(upper_name
)) {
1175 talloc_free(upper_name
);
1176 return NT_STATUS_INVALID_PARAMETER
;
1179 centry
= wcache_fetch(cache
, domain
, "NSS/AN/%s", upper_name
);
1181 talloc_free(upper_name
);
1186 status
= centry
->status
;
1188 if (!NT_STATUS_IS_OK(status
)) {
1189 centry_free(centry
);
1193 *name
= centry_string( centry
, mem_ctx
);
1195 centry_free(centry
);
1197 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1198 alias
, *name
? *name
: "(none)"));
1200 return (*name
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1204 /* If its not in cache and we are offline, then fail */
1206 if (is_domain_offline(domain
)) {
1207 DEBUG(8,("resolve_alias_to_username: rejecting query "
1208 "in offline mode\n"));
1209 return NT_STATUS_NOT_FOUND
;
1212 /* an alias cannot contain a domain prefix or '@' */
1214 if (strchr(alias
, '\\') || strchr(alias
, '@')) {
1215 DEBUG(10,("resolve_alias_to_username: skipping fully "
1216 "qualified name %s\n", alias
));
1217 return NT_STATUS_OBJECT_NAME_INVALID
;
1220 status
= nss_map_from_alias( mem_ctx
, domain
->name
, alias
, name
);
1222 if ( NT_STATUS_IS_OK( status
) ) {
1223 wcache_save_alias_username( domain
, status
, alias
, *name
);
1226 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1227 wcache_save_alias_username(domain
, status
, alias
, "(NULL)");
1230 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1231 nt_errstr(status
)));
1233 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1234 set_domain_offline( domain
);
1240 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
1242 struct winbind_cache
*cache
= get_cache(domain
);
1244 fstring key_str
, tmp
;
1248 return NT_STATUS_INTERNAL_DB_ERROR
;
1251 if (is_null_sid(sid
)) {
1252 return NT_STATUS_INVALID_SID
;
1255 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1256 return NT_STATUS_INVALID_SID
;
1259 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
1261 ret
= tdb_exists(cache
->tdb
, string_tdb_data(key_str
));
1263 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1266 return NT_STATUS_OK
;
1269 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1270 as new salted ones. */
1272 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
1273 TALLOC_CTX
*mem_ctx
,
1274 const struct dom_sid
*sid
,
1275 const uint8_t **cached_nt_pass
,
1276 const uint8_t **cached_salt
)
1278 struct winbind_cache
*cache
= get_cache(domain
);
1279 struct cache_entry
*centry
= NULL
;
1285 return NT_STATUS_INTERNAL_DB_ERROR
;
1288 if (is_null_sid(sid
)) {
1289 return NT_STATUS_INVALID_SID
;
1292 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1293 return NT_STATUS_INVALID_SID
;
1296 /* Try and get a salted cred first. If we can't
1297 fall back to an unsalted cred. */
1299 centry
= wcache_fetch(cache
, domain
, "CRED/%s",
1300 sid_to_fstring(tmp
, sid
));
1302 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1303 sid_string_dbg(sid
)));
1304 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1308 * We don't use the time element at this moment,
1309 * but we have to consume it, so that we don't
1310 * neet to change the disk format of the cache.
1312 (void)centry_time(centry
);
1314 /* In the salted case this isn't actually the nt_hash itself,
1315 but the MD5 of the salt + nt_hash. Let the caller
1316 sort this out. It can tell as we only return the cached_salt
1317 if we are returning a salted cred. */
1319 *cached_nt_pass
= (const uint8_t *)centry_hash16(centry
, mem_ctx
);
1320 if (*cached_nt_pass
== NULL
) {
1323 sid_to_fstring(sidstr
, sid
);
1325 /* Bad (old) cred cache. Delete and pretend we
1327 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1329 wcache_delete("CRED/%s", sidstr
);
1330 centry_free(centry
);
1331 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1334 /* We only have 17 bytes more data in the salted cred case. */
1335 if (centry
->len
- centry
->ofs
== 17) {
1336 *cached_salt
= (const uint8_t *)centry_hash16(centry
, mem_ctx
);
1338 *cached_salt
= NULL
;
1341 dump_data_pw("cached_nt_pass", *cached_nt_pass
, NT_HASH_LEN
);
1343 dump_data_pw("cached_salt", *cached_salt
, NT_HASH_LEN
);
1346 status
= centry
->status
;
1348 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1349 sid_string_dbg(sid
), nt_errstr(status
) ));
1351 centry_free(centry
);
1355 /* Store creds for a SID - only writes out new salted ones. */
1357 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1358 const struct dom_sid
*sid
,
1359 const uint8_t nt_pass
[NT_HASH_LEN
])
1361 struct cache_entry
*centry
;
1364 uint8_t cred_salt
[NT_HASH_LEN
];
1365 uint8_t salted_hash
[NT_HASH_LEN
];
1367 if (is_null_sid(sid
)) {
1368 return NT_STATUS_INVALID_SID
;
1371 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1372 return NT_STATUS_INVALID_SID
;
1375 centry
= centry_start(domain
, NT_STATUS_OK
);
1377 return NT_STATUS_INTERNAL_DB_ERROR
;
1380 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1382 centry_put_time(centry
, time(NULL
));
1384 /* Create a salt and then salt the hash. */
1385 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1386 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1388 centry_put_hash16(centry
, salted_hash
);
1389 centry_put_hash16(centry
, cred_salt
);
1390 centry_end(centry
, "CRED/%s", sid_to_fstring(sid_string
, sid
));
1392 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1394 centry_free(centry
);
1396 return NT_STATUS_OK
;
1400 /* Query display info. This is the basic user list fn */
1401 NTSTATUS
wb_cache_query_user_list(struct winbindd_domain
*domain
,
1402 TALLOC_CTX
*mem_ctx
,
1405 struct winbind_cache
*cache
= get_cache(domain
);
1406 struct cache_entry
*centry
= NULL
;
1407 uint32_t num_rids
= 0;
1408 uint32_t *rids
= NULL
;
1410 unsigned int i
, retry
;
1411 bool old_status
= domain
->online
;
1418 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1423 num_rids
= centry_uint32(centry
);
1425 if (num_rids
== 0) {
1429 rids
= talloc_array(mem_ctx
, uint32_t, num_rids
);
1431 centry_free(centry
);
1432 return NT_STATUS_NO_MEMORY
;
1435 for (i
=0; i
<num_rids
; i
++) {
1436 rids
[i
] = centry_uint32(centry
);
1440 status
= centry
->status
;
1442 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1443 domain
->name
, nt_errstr(status
) ));
1445 centry_free(centry
);
1450 /* Return status value returned by seq number check */
1452 if (!NT_STATUS_IS_OK(domain
->last_status
))
1453 return domain
->last_status
;
1455 /* Put the query_user_list() in a retry loop. There appears to be
1456 * some bug either with Windows 2000 or Samba's handling of large
1457 * rpc replies. This manifests itself as sudden disconnection
1458 * at a random point in the enumeration of a large (60k) user list.
1459 * The retry loop simply tries the operation again. )-: It's not
1460 * pretty but an acceptable workaround until we work out what the
1461 * real problem is. */
1466 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1470 status
= domain
->backend
->query_user_list(domain
, mem_ctx
,
1472 num_rids
= talloc_array_length(rids
);
1474 if (!NT_STATUS_IS_OK(status
)) {
1475 DEBUG(3, ("query_user_list: returned 0x%08x, "
1476 "retrying\n", NT_STATUS_V(status
)));
1478 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1479 DEBUG(3, ("query_user_list: flushing "
1480 "connection cache\n"));
1481 invalidate_cm_connection(domain
);
1483 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1484 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1485 if (!domain
->internal
&& old_status
) {
1486 set_domain_offline(domain
);
1488 /* store partial response. */
1491 * humm, what about the status used for cache?
1492 * Should it be NT_STATUS_OK?
1497 * domain is offline now, and there is no user entries,
1498 * try to fetch from cache again.
1500 if (cache
->tdb
&& !domain
->online
&& !domain
->internal
&& old_status
) {
1501 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1502 /* partial response... */
1506 goto do_fetch_cache
;
1513 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1517 refresh_sequence_number(domain
);
1518 if (!NT_STATUS_IS_OK(status
)) {
1521 centry
= centry_start(domain
, status
);
1524 centry_put_uint32(centry
, num_rids
);
1525 for (i
=0; i
<num_rids
; i
++) {
1526 centry_put_uint32(centry
, rids
[i
]);
1528 centry_end(centry
, "UL/%s", domain
->name
);
1529 centry_free(centry
);
1537 /* list all domain groups */
1538 NTSTATUS
wb_cache_enum_dom_groups(struct winbindd_domain
*domain
,
1539 TALLOC_CTX
*mem_ctx
,
1540 uint32_t *num_entries
,
1541 struct wb_acct_info
**info
)
1543 struct winbind_cache
*cache
= get_cache(domain
);
1544 struct cache_entry
*centry
= NULL
;
1549 old_status
= domain
->online
;
1553 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1558 *num_entries
= centry_uint32(centry
);
1560 if (*num_entries
== 0)
1563 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1565 smb_panic_fn("enum_dom_groups out of memory");
1567 for (i
=0; i
<(*num_entries
); i
++) {
1568 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1569 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1570 (*info
)[i
].rid
= centry_uint32(centry
);
1574 status
= centry
->status
;
1576 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1577 domain
->name
, nt_errstr(status
) ));
1579 centry_free(centry
);
1586 /* Return status value returned by seq number check */
1588 if (!NT_STATUS_IS_OK(domain
->last_status
))
1589 return domain
->last_status
;
1591 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1594 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1596 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1597 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1598 if (!domain
->internal
&& old_status
) {
1599 set_domain_offline(domain
);
1603 !domain
->internal
&&
1605 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1607 goto do_fetch_cache
;
1612 refresh_sequence_number(domain
);
1613 if (!NT_STATUS_IS_OK(status
)) {
1616 centry
= centry_start(domain
, status
);
1619 centry_put_uint32(centry
, *num_entries
);
1620 for (i
=0; i
<(*num_entries
); i
++) {
1621 centry_put_string(centry
, (*info
)[i
].acct_name
);
1622 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1623 centry_put_uint32(centry
, (*info
)[i
].rid
);
1625 centry_end(centry
, "GL/%s/domain", domain
->name
);
1626 centry_free(centry
);
1632 /* list all domain groups */
1633 NTSTATUS
wb_cache_enum_local_groups(struct winbindd_domain
*domain
,
1634 TALLOC_CTX
*mem_ctx
,
1635 uint32_t *num_entries
,
1636 struct wb_acct_info
**info
)
1638 struct winbind_cache
*cache
= get_cache(domain
);
1639 struct cache_entry
*centry
= NULL
;
1644 old_status
= domain
->online
;
1648 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1653 *num_entries
= centry_uint32(centry
);
1655 if (*num_entries
== 0)
1658 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1660 smb_panic_fn("enum_dom_groups out of memory");
1662 for (i
=0; i
<(*num_entries
); i
++) {
1663 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1664 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1665 (*info
)[i
].rid
= centry_uint32(centry
);
1670 /* If we are returning cached data and the domain controller
1671 is down then we don't know whether the data is up to date
1672 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1675 if (wcache_server_down(domain
)) {
1676 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1677 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1679 status
= centry
->status
;
1681 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1682 domain
->name
, nt_errstr(status
) ));
1684 centry_free(centry
);
1691 /* Return status value returned by seq number check */
1693 if (!NT_STATUS_IS_OK(domain
->last_status
))
1694 return domain
->last_status
;
1696 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1699 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1701 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1702 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1703 if (!domain
->internal
&& old_status
) {
1704 set_domain_offline(domain
);
1707 !domain
->internal
&&
1710 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1712 goto do_fetch_cache
;
1717 refresh_sequence_number(domain
);
1718 if (!NT_STATUS_IS_OK(status
)) {
1721 centry
= centry_start(domain
, status
);
1724 centry_put_uint32(centry
, *num_entries
);
1725 for (i
=0; i
<(*num_entries
); i
++) {
1726 centry_put_string(centry
, (*info
)[i
].acct_name
);
1727 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1728 centry_put_uint32(centry
, (*info
)[i
].rid
);
1730 centry_end(centry
, "GL/%s/local", domain
->name
);
1731 centry_free(centry
);
1737 struct wcache_name_to_sid_state
{
1738 struct dom_sid
*sid
;
1739 enum lsa_SidType
*type
;
1744 static void wcache_name_to_sid_fn(const struct dom_sid
*sid
,
1745 enum lsa_SidType type
, time_t timeout
,
1748 struct wcache_name_to_sid_state
*state
= private_data
;
1751 *state
->type
= type
;
1752 state
->found
= (state
->offline
|| (timeout
> time(NULL
)));
1755 static NTSTATUS
wcache_name_to_sid(struct winbindd_domain
*domain
,
1756 const char *domain_name
,
1758 struct dom_sid
*sid
,
1759 enum lsa_SidType
*type
)
1761 struct wcache_name_to_sid_state state
= {
1762 .sid
= sid
, .type
= type
, .found
= false,
1763 .offline
= is_domain_offline(domain
),
1767 ok
= namemap_cache_find_name(domain_name
, name
, wcache_name_to_sid_fn
,
1770 DBG_DEBUG("namemap_cache_find_name failed\n");
1771 return NT_STATUS_NOT_FOUND
;
1774 DBG_DEBUG("cache entry not found\n");
1775 return NT_STATUS_NOT_FOUND
;
1777 if (*type
== SID_NAME_UNKNOWN
) {
1778 return NT_STATUS_NONE_MAPPED
;
1781 return NT_STATUS_OK
;
1784 /* convert a single name to a sid in a domain */
1785 NTSTATUS
wb_cache_name_to_sid(struct winbindd_domain
*domain
,
1786 TALLOC_CTX
*mem_ctx
,
1787 const char *domain_name
,
1790 struct dom_sid
*sid
,
1791 enum lsa_SidType
*type
)
1795 const char *dom_name
;
1797 old_status
= domain
->online
;
1799 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1800 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1806 /* If the seq number check indicated that there is a problem
1807 * with this DC, then return that status... except for
1808 * access_denied. This is special because the dc may be in
1809 * "restrict anonymous = 1" mode, in which case it will deny
1810 * most unauthenticated operations, but *will* allow the LSA
1811 * name-to-sid that we try as a fallback. */
1813 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1814 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1815 return domain
->last_status
;
1817 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1820 winbindd_domain_init_backend(domain
);
1821 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
,
1822 name
, flags
, &dom_name
, sid
, type
);
1824 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1825 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1826 if (!domain
->internal
&& old_status
) {
1827 set_domain_offline(domain
);
1829 if (!domain
->internal
&&
1832 NTSTATUS cache_status
;
1833 cache_status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1834 return cache_status
;
1839 if (domain
->online
&&
1840 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1841 enum lsa_SidType save_type
= *type
;
1843 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1844 save_type
= SID_NAME_UNKNOWN
;
1847 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
,
1850 /* Only save the reverse mapping if this was not a UPN */
1851 if (!strchr(name
, '@')) {
1852 if (!strupper_m(discard_const_p(char, domain_name
))) {
1853 return NT_STATUS_INVALID_PARAMETER
;
1855 (void)strlower_m(discard_const_p(char, name
));
1856 wcache_save_sid_to_name(domain
, status
, sid
,
1857 dom_name
, name
, save_type
);
1864 struct wcache_sid_to_name_state
{
1865 TALLOC_CTX
*mem_ctx
;
1868 enum lsa_SidType
*type
;
1873 static void wcache_sid_to_name_fn(const char *domain
, const char *name
,
1874 enum lsa_SidType type
, time_t timeout
,
1877 struct wcache_sid_to_name_state
*state
= private_data
;
1879 *state
->domain_name
= talloc_strdup(state
->mem_ctx
, domain
);
1880 if (*state
->domain_name
== NULL
) {
1883 *state
->name
= talloc_strdup(state
->mem_ctx
, name
);
1884 if (*state
->name
== NULL
) {
1887 *state
->type
= type
;
1888 state
->found
= (state
->offline
|| (timeout
> time(NULL
)));
1891 static NTSTATUS
wcache_sid_to_name(struct winbindd_domain
*domain
,
1892 const struct dom_sid
*sid
,
1893 TALLOC_CTX
*mem_ctx
,
1896 enum lsa_SidType
*type
)
1898 struct wcache_sid_to_name_state state
= {
1899 .mem_ctx
= mem_ctx
, .found
= false,
1900 .domain_name
= domain_name
, .name
= name
, .type
= type
,
1901 .offline
= is_domain_offline(domain
)
1905 ok
= namemap_cache_find_sid(sid
, wcache_sid_to_name_fn
, &state
);
1907 DBG_DEBUG("namemap_cache_find_name failed\n");
1908 return NT_STATUS_NOT_FOUND
;
1911 DBG_DEBUG("cache entry not found\n");
1912 return NT_STATUS_NOT_FOUND
;
1914 if (*type
== SID_NAME_UNKNOWN
) {
1915 return NT_STATUS_NONE_MAPPED
;
1918 return NT_STATUS_OK
;
1921 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1923 NTSTATUS
wb_cache_sid_to_name(struct winbindd_domain
*domain
,
1924 TALLOC_CTX
*mem_ctx
,
1925 const struct dom_sid
*sid
,
1928 enum lsa_SidType
*type
)
1933 old_status
= domain
->online
;
1934 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
1936 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1941 *domain_name
= NULL
;
1943 /* If the seq number check indicated that there is a problem
1944 * with this DC, then return that status... except for
1945 * access_denied. This is special because the dc may be in
1946 * "restrict anonymous = 1" mode, in which case it will deny
1947 * most unauthenticated operations, but *will* allow the LSA
1948 * sid-to-name that we try as a fallback. */
1950 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1951 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1952 return domain
->last_status
;
1954 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1957 winbindd_domain_init_backend(domain
);
1959 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1961 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1962 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1963 if (!domain
->internal
&& old_status
) {
1964 set_domain_offline(domain
);
1966 if (!domain
->internal
&&
1969 NTSTATUS cache_status
;
1970 cache_status
= wcache_sid_to_name(domain
, sid
, mem_ctx
,
1971 domain_name
, name
, type
);
1972 return cache_status
;
1976 if (!NT_STATUS_IS_OK(status
)) {
1979 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
1981 /* We can't save the name to sid mapping here, as with sid history a
1982 * later name2sid would give the wrong sid. */
1987 NTSTATUS
wb_cache_rids_to_names(struct winbindd_domain
*domain
,
1988 TALLOC_CTX
*mem_ctx
,
1989 const struct dom_sid
*domain_sid
,
1994 enum lsa_SidType
**types
)
1996 struct winbind_cache
*cache
= get_cache(domain
);
1998 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
2003 old_status
= domain
->online
;
2004 *domain_name
= NULL
;
2012 if (num_rids
== 0) {
2013 return NT_STATUS_OK
;
2016 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2017 *types
= talloc_array(mem_ctx
, enum lsa_SidType
, num_rids
);
2019 if ((*names
== NULL
) || (*types
== NULL
)) {
2020 result
= NT_STATUS_NO_MEMORY
;
2024 have_mapped
= have_unmapped
= false;
2026 for (i
=0; i
<num_rids
; i
++) {
2029 enum lsa_SidType type
;
2032 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2033 result
= NT_STATUS_INTERNAL_ERROR
;
2037 status
= wcache_sid_to_name(domain
, &sid
, *names
, &dom
,
2040 (*types
)[i
] = SID_NAME_UNKNOWN
;
2041 (*names
)[i
] = talloc_strdup(*names
, "");
2043 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2048 if (NT_STATUS_IS_OK(status
)) {
2052 if (*domain_name
== NULL
) {
2060 } else if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
2061 have_unmapped
= true;
2063 /* something's definitely wrong */
2070 return NT_STATUS_NONE_MAPPED
;
2072 if (!have_unmapped
) {
2073 return NT_STATUS_OK
;
2075 return STATUS_SOME_UNMAPPED
;
2079 TALLOC_FREE(*names
);
2080 TALLOC_FREE(*types
);
2082 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
2083 rids
, num_rids
, domain_name
,
2086 if (NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
2087 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2088 if (!domain
->internal
&& old_status
) {
2089 set_domain_offline(domain
);
2092 !domain
->internal
&&
2095 have_mapped
= have_unmapped
= false;
2097 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2098 if (*names
== NULL
) {
2099 result
= NT_STATUS_NO_MEMORY
;
2103 *types
= talloc_array(mem_ctx
, enum lsa_SidType
,
2105 if (*types
== NULL
) {
2106 result
= NT_STATUS_NO_MEMORY
;
2110 for (i
=0; i
<num_rids
; i
++) {
2113 enum lsa_SidType type
;
2116 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2117 result
= NT_STATUS_INTERNAL_ERROR
;
2121 status
= wcache_sid_to_name(domain
, &sid
,
2125 (*types
)[i
] = SID_NAME_UNKNOWN
;
2126 (*names
)[i
] = talloc_strdup(*names
, "");
2128 if (NT_STATUS_IS_OK(status
)) {
2132 if (*domain_name
== NULL
) {
2140 } else if (NT_STATUS_EQUAL(
2142 NT_STATUS_NONE_MAPPED
)) {
2143 have_unmapped
= true;
2145 /* something's definitely wrong */
2152 return NT_STATUS_NONE_MAPPED
;
2154 if (!have_unmapped
) {
2155 return NT_STATUS_OK
;
2157 return STATUS_SOME_UNMAPPED
;
2161 None of the queried rids has been found so save all negative entries
2163 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
2164 for (i
= 0; i
< num_rids
; i
++) {
2166 const char *name
= "";
2167 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
2168 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
2170 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2171 return NT_STATUS_INTERNAL_ERROR
;
2174 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2182 Some or all of the queried rids have been found.
2184 if (!NT_STATUS_IS_OK(result
) &&
2185 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
2189 refresh_sequence_number(domain
);
2191 for (i
=0; i
<num_rids
; i
++) {
2195 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2196 result
= NT_STATUS_INTERNAL_ERROR
;
2200 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
2201 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
2203 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2204 (*names
)[i
], (*types
)[i
]);
2210 TALLOC_FREE(*names
);
2211 TALLOC_FREE(*types
);
2215 static NTSTATUS
wcache_query_user(struct winbindd_domain
*domain
,
2216 TALLOC_CTX
*mem_ctx
,
2217 const struct dom_sid
*user_sid
,
2218 struct wbint_userinfo
*info
)
2220 struct winbind_cache
*cache
= get_cache(domain
);
2221 struct cache_entry
*centry
= NULL
;
2225 if (cache
->tdb
== NULL
) {
2226 return NT_STATUS_NOT_FOUND
;
2229 sid_string
= sid_string_tos(user_sid
);
2230 if (sid_string
== NULL
) {
2231 return NT_STATUS_NO_MEMORY
;
2234 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string
);
2235 TALLOC_FREE(sid_string
);
2236 if (centry
== NULL
) {
2237 return NT_STATUS_NOT_FOUND
;
2241 * If we have an access denied cache entry and a cached info3
2242 * in the samlogon cache then do a query. This will force the
2243 * rpc back end to return the info3 data.
2246 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
) &&
2247 netsamlogon_cache_have(user_sid
)) {
2248 DEBUG(10, ("query_user: cached access denied and have cached "
2250 domain
->last_status
= NT_STATUS_OK
;
2251 centry_free(centry
);
2252 return NT_STATUS_NOT_FOUND
;
2255 /* if status is not ok then this is a negative hit
2256 and the rest of the data doesn't matter */
2257 status
= centry
->status
;
2258 if (NT_STATUS_IS_OK(status
)) {
2259 info
->domain_name
= centry_string(centry
, mem_ctx
);
2260 info
->acct_name
= centry_string(centry
, mem_ctx
);
2261 info
->full_name
= centry_string(centry
, mem_ctx
);
2262 info
->homedir
= centry_string(centry
, mem_ctx
);
2263 info
->shell
= centry_string(centry
, mem_ctx
);
2264 info
->uid
= centry_uint32(centry
);
2265 info
->primary_gid
= centry_uint32(centry
);
2266 info
->primary_group_name
= centry_string(centry
, mem_ctx
);
2267 centry_sid(centry
, &info
->user_sid
);
2268 centry_sid(centry
, &info
->group_sid
);
2271 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2272 "%s\n", domain
->name
, nt_errstr(status
) ));
2274 centry_free(centry
);
2280 * @brief Query a fullname from the username cache (for further gecos processing)
2282 * @param domain A pointer to the winbindd_domain struct.
2283 * @param mem_ctx The talloc context.
2284 * @param user_sid The user sid.
2285 * @param full_name A pointer to the full_name string.
2287 * @return NTSTATUS code
2289 NTSTATUS
wcache_query_user_fullname(struct winbindd_domain
*domain
,
2290 TALLOC_CTX
*mem_ctx
,
2291 const struct dom_sid
*user_sid
,
2292 const char **full_name
)
2295 struct wbint_userinfo info
;
2297 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, &info
);
2298 if (!NT_STATUS_IS_OK(status
)) {
2302 if (info
.full_name
!= NULL
) {
2303 *full_name
= talloc_strdup(mem_ctx
, info
.full_name
);
2304 if (*full_name
== NULL
) {
2305 return NT_STATUS_NO_MEMORY
;
2309 return NT_STATUS_OK
;
2312 static NTSTATUS
wcache_lookup_usergroups(struct winbindd_domain
*domain
,
2313 TALLOC_CTX
*mem_ctx
,
2314 const struct dom_sid
*user_sid
,
2315 uint32_t *pnum_sids
,
2316 struct dom_sid
**psids
)
2318 struct winbind_cache
*cache
= get_cache(domain
);
2319 struct cache_entry
*centry
= NULL
;
2321 uint32_t i
, num_sids
;
2322 struct dom_sid
*sids
;
2325 if (cache
->tdb
== NULL
) {
2326 return NT_STATUS_NOT_FOUND
;
2329 centry
= wcache_fetch(cache
, domain
, "UG/%s",
2330 sid_to_fstring(sid_string
, user_sid
));
2331 if (centry
== NULL
) {
2332 return NT_STATUS_NOT_FOUND
;
2335 /* If we have an access denied cache entry and a cached info3 in the
2336 samlogon cache then do a query. This will force the rpc back end
2337 to return the info3 data. */
2339 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)
2340 && netsamlogon_cache_have(user_sid
)) {
2341 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2343 domain
->last_status
= NT_STATUS_OK
;
2344 centry_free(centry
);
2345 return NT_STATUS_NOT_FOUND
;
2348 num_sids
= centry_uint32(centry
);
2349 sids
= talloc_array(mem_ctx
, struct dom_sid
, num_sids
);
2351 centry_free(centry
);
2352 return NT_STATUS_NO_MEMORY
;
2355 for (i
=0; i
<num_sids
; i
++) {
2356 centry_sid(centry
, &sids
[i
]);
2359 status
= centry
->status
;
2361 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2362 "status: %s\n", domain
->name
, nt_errstr(status
)));
2364 centry_free(centry
);
2366 *pnum_sids
= num_sids
;
2371 /* Lookup groups a user is a member of. */
2372 NTSTATUS
wb_cache_lookup_usergroups(struct winbindd_domain
*domain
,
2373 TALLOC_CTX
*mem_ctx
,
2374 const struct dom_sid
*user_sid
,
2375 uint32_t *num_groups
,
2376 struct dom_sid
**user_gids
)
2378 struct cache_entry
*centry
= NULL
;
2384 old_status
= domain
->online
;
2385 status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2386 num_groups
, user_gids
);
2387 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2392 (*user_gids
) = NULL
;
2394 /* Return status value returned by seq number check */
2396 if (!NT_STATUS_IS_OK(domain
->last_status
))
2397 return domain
->last_status
;
2399 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2402 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
2404 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2405 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2406 if (!domain
->internal
&& old_status
) {
2407 set_domain_offline(domain
);
2409 if (!domain
->internal
&&
2412 NTSTATUS cache_status
;
2413 cache_status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2414 num_groups
, user_gids
);
2415 return cache_status
;
2418 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
2422 refresh_sequence_number(domain
);
2423 if (!NT_STATUS_IS_OK(status
)) {
2426 centry
= centry_start(domain
, status
);
2430 centry_put_uint32(centry
, *num_groups
);
2431 for (i
=0; i
<(*num_groups
); i
++) {
2432 centry_put_sid(centry
, &(*user_gids
)[i
]);
2435 centry_end(centry
, "UG/%s", sid_to_fstring(sid_string
, user_sid
));
2436 centry_free(centry
);
2442 static char *wcache_make_sidlist(TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2443 const struct dom_sid
*sids
)
2448 sidlist
= talloc_strdup(mem_ctx
, "");
2449 if (sidlist
== NULL
) {
2452 for (i
=0; i
<num_sids
; i
++) {
2454 sidlist
= talloc_asprintf_append_buffer(
2455 sidlist
, "/%s", sid_to_fstring(tmp
, &sids
[i
]));
2456 if (sidlist
== NULL
) {
2463 static NTSTATUS
wcache_lookup_useraliases(struct winbindd_domain
*domain
,
2464 TALLOC_CTX
*mem_ctx
,
2466 const struct dom_sid
*sids
,
2467 uint32_t *pnum_aliases
,
2468 uint32_t **paliases
)
2470 struct winbind_cache
*cache
= get_cache(domain
);
2471 struct cache_entry
*centry
= NULL
;
2472 uint32_t i
, num_aliases
;
2477 if (cache
->tdb
== NULL
) {
2478 return NT_STATUS_NOT_FOUND
;
2481 if (num_sids
== 0) {
2484 return NT_STATUS_OK
;
2487 /* We need to cache indexed by the whole list of SIDs, the aliases
2488 * resulting might come from any of the SIDs. */
2490 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2491 if (sidlist
== NULL
) {
2492 return NT_STATUS_NO_MEMORY
;
2495 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2496 TALLOC_FREE(sidlist
);
2497 if (centry
== NULL
) {
2498 return NT_STATUS_NOT_FOUND
;
2501 num_aliases
= centry_uint32(centry
);
2502 aliases
= talloc_array(mem_ctx
, uint32_t, num_aliases
);
2503 if (aliases
== NULL
) {
2504 centry_free(centry
);
2505 return NT_STATUS_NO_MEMORY
;
2508 for (i
=0; i
<num_aliases
; i
++) {
2509 aliases
[i
] = centry_uint32(centry
);
2512 status
= centry
->status
;
2514 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2515 "status %s\n", domain
->name
, nt_errstr(status
)));
2517 centry_free(centry
);
2519 *pnum_aliases
= num_aliases
;
2520 *paliases
= aliases
;
2525 NTSTATUS
wb_cache_lookup_useraliases(struct winbindd_domain
*domain
,
2526 TALLOC_CTX
*mem_ctx
,
2528 const struct dom_sid
*sids
,
2529 uint32_t *num_aliases
,
2530 uint32_t **alias_rids
)
2532 struct cache_entry
*centry
= NULL
;
2538 old_status
= domain
->online
;
2539 status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
2540 num_aliases
, alias_rids
);
2541 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2546 (*alias_rids
) = NULL
;
2548 if (!NT_STATUS_IS_OK(domain
->last_status
))
2549 return domain
->last_status
;
2551 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2552 "for domain %s\n", domain
->name
));
2554 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2555 if (sidlist
== NULL
) {
2556 return NT_STATUS_NO_MEMORY
;
2559 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2561 num_aliases
, alias_rids
);
2563 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2564 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2565 if (!domain
->internal
&& old_status
) {
2566 set_domain_offline(domain
);
2568 if (!domain
->internal
&&
2571 NTSTATUS cache_status
;
2572 cache_status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
,
2573 sids
, num_aliases
, alias_rids
);
2574 return cache_status
;
2578 refresh_sequence_number(domain
);
2579 if (!NT_STATUS_IS_OK(status
)) {
2582 centry
= centry_start(domain
, status
);
2585 centry_put_uint32(centry
, *num_aliases
);
2586 for (i
=0; i
<(*num_aliases
); i
++)
2587 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2588 centry_end(centry
, "UA%s", sidlist
);
2589 centry_free(centry
);
2595 static NTSTATUS
wcache_lookup_groupmem(struct winbindd_domain
*domain
,
2596 TALLOC_CTX
*mem_ctx
,
2597 const struct dom_sid
*group_sid
,
2598 uint32_t *num_names
,
2599 struct dom_sid
**sid_mem
, char ***names
,
2600 uint32_t **name_types
)
2602 struct winbind_cache
*cache
= get_cache(domain
);
2603 struct cache_entry
*centry
= NULL
;
2608 if (cache
->tdb
== NULL
) {
2609 return NT_STATUS_NOT_FOUND
;
2612 sid_string
= sid_string_tos(group_sid
);
2613 if (sid_string
== NULL
) {
2614 return NT_STATUS_NO_MEMORY
;
2617 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_string
);
2618 TALLOC_FREE(sid_string
);
2619 if (centry
== NULL
) {
2620 return NT_STATUS_NOT_FOUND
;
2627 *num_names
= centry_uint32(centry
);
2628 if (*num_names
== 0) {
2629 centry_free(centry
);
2630 return NT_STATUS_OK
;
2633 *sid_mem
= talloc_array(mem_ctx
, struct dom_sid
, *num_names
);
2634 *names
= talloc_array(mem_ctx
, char *, *num_names
);
2635 *name_types
= talloc_array(mem_ctx
, uint32_t, *num_names
);
2637 if ((*sid_mem
== NULL
) || (*names
== NULL
) || (*name_types
== NULL
)) {
2638 TALLOC_FREE(*sid_mem
);
2639 TALLOC_FREE(*names
);
2640 TALLOC_FREE(*name_types
);
2641 centry_free(centry
);
2642 return NT_STATUS_NO_MEMORY
;
2645 for (i
=0; i
<(*num_names
); i
++) {
2646 centry_sid(centry
, &(*sid_mem
)[i
]);
2647 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2648 (*name_types
)[i
] = centry_uint32(centry
);
2651 status
= centry
->status
;
2653 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2654 "status: %s\n", domain
->name
, nt_errstr(status
)));
2656 centry_free(centry
);
2660 NTSTATUS
wb_cache_lookup_groupmem(struct winbindd_domain
*domain
,
2661 TALLOC_CTX
*mem_ctx
,
2662 const struct dom_sid
*group_sid
,
2663 enum lsa_SidType type
,
2664 uint32_t *num_names
,
2665 struct dom_sid
**sid_mem
,
2667 uint32_t **name_types
)
2669 struct cache_entry
*centry
= NULL
;
2675 old_status
= domain
->online
;
2676 status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2677 sid_mem
, names
, name_types
);
2678 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2685 (*name_types
) = NULL
;
2687 /* Return status value returned by seq number check */
2689 if (!NT_STATUS_IS_OK(domain
->last_status
))
2690 return domain
->last_status
;
2692 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2695 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
,
2697 sid_mem
, names
, name_types
);
2699 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2700 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2701 if (!domain
->internal
&& old_status
) {
2702 set_domain_offline(domain
);
2704 if (!domain
->internal
&&
2707 NTSTATUS cache_status
;
2708 cache_status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
,
2709 num_names
, sid_mem
, names
,
2711 return cache_status
;
2715 refresh_sequence_number(domain
);
2716 if (!NT_STATUS_IS_OK(status
)) {
2719 centry
= centry_start(domain
, status
);
2722 centry_put_uint32(centry
, *num_names
);
2723 for (i
=0; i
<(*num_names
); i
++) {
2724 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2725 centry_put_string(centry
, (*names
)[i
]);
2726 centry_put_uint32(centry
, (*name_types
)[i
]);
2728 centry_end(centry
, "GM/%s", sid_to_fstring(sid_string
, group_sid
));
2729 centry_free(centry
);
2735 /* find the sequence number for a domain */
2736 NTSTATUS
wb_cache_sequence_number(struct winbindd_domain
*domain
,
2739 refresh_sequence_number(domain
);
2741 *seq
= domain
->sequence_number
;
2743 return NT_STATUS_OK
;
2746 /* enumerate trusted domains
2747 * (we need to have the list of trustdoms in the cache when we go offline) -
2749 NTSTATUS
wb_cache_trusted_domains(struct winbindd_domain
*domain
,
2750 TALLOC_CTX
*mem_ctx
,
2751 struct netr_DomainTrustList
*trusts
)
2754 struct winbind_cache
*cache
;
2755 struct winbindd_tdc_domain
*dom_list
= NULL
;
2756 size_t num_domains
= 0;
2757 bool retval
= false;
2761 old_status
= domain
->online
;
2763 trusts
->array
= NULL
;
2765 cache
= get_cache(domain
);
2766 if (!cache
|| !cache
->tdb
) {
2770 if (domain
->online
) {
2774 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2775 if (!retval
|| !num_domains
|| !dom_list
) {
2776 TALLOC_FREE(dom_list
);
2781 trusts
->array
= talloc_zero_array(mem_ctx
, struct netr_DomainTrust
, num_domains
);
2782 if (!trusts
->array
) {
2783 TALLOC_FREE(dom_list
);
2784 return NT_STATUS_NO_MEMORY
;
2787 for (i
= 0; i
< num_domains
; i
++) {
2788 struct netr_DomainTrust
*trust
;
2789 struct dom_sid
*sid
;
2790 struct winbindd_domain
*dom
;
2792 dom
= find_domain_from_name_noinit(dom_list
[i
].domain_name
);
2793 if (dom
&& dom
->internal
) {
2797 trust
= &trusts
->array
[trusts
->count
];
2798 trust
->netbios_name
= talloc_strdup(trusts
->array
, dom_list
[i
].domain_name
);
2799 trust
->dns_name
= talloc_strdup(trusts
->array
, dom_list
[i
].dns_name
);
2800 sid
= talloc(trusts
->array
, struct dom_sid
);
2801 if (!trust
->netbios_name
|| !trust
->dns_name
||
2803 TALLOC_FREE(dom_list
);
2804 TALLOC_FREE(trusts
->array
);
2805 return NT_STATUS_NO_MEMORY
;
2808 trust
->trust_flags
= dom_list
[i
].trust_flags
;
2809 trust
->trust_attributes
= dom_list
[i
].trust_attribs
;
2810 trust
->trust_type
= dom_list
[i
].trust_type
;
2811 sid_copy(sid
, &dom_list
[i
].sid
);
2816 TALLOC_FREE(dom_list
);
2817 return NT_STATUS_OK
;
2820 /* Return status value returned by seq number check */
2822 if (!NT_STATUS_IS_OK(domain
->last_status
))
2823 return domain
->last_status
;
2825 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2828 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, trusts
);
2830 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2831 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2832 if (!domain
->internal
&& old_status
) {
2833 set_domain_offline(domain
);
2835 if (!domain
->internal
&&
2838 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2839 if (retval
&& num_domains
&& dom_list
) {
2840 TALLOC_FREE(trusts
->array
);
2842 goto do_fetch_cache
;
2846 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2847 * so that the generic centry handling still applies correctly -
2850 if (!NT_STATUS_IS_ERR(status
)) {
2851 status
= NT_STATUS_OK
;
2856 /* get lockout policy */
2857 NTSTATUS
wb_cache_lockout_policy(struct winbindd_domain
*domain
,
2858 TALLOC_CTX
*mem_ctx
,
2859 struct samr_DomInfo12
*policy
)
2861 struct winbind_cache
*cache
= get_cache(domain
);
2862 struct cache_entry
*centry
= NULL
;
2866 old_status
= domain
->online
;
2870 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2876 policy
->lockout_duration
= centry_nttime(centry
);
2877 policy
->lockout_window
= centry_nttime(centry
);
2878 policy
->lockout_threshold
= centry_uint16(centry
);
2880 status
= centry
->status
;
2882 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2883 domain
->name
, nt_errstr(status
) ));
2885 centry_free(centry
);
2889 ZERO_STRUCTP(policy
);
2891 /* Return status value returned by seq number check */
2893 if (!NT_STATUS_IS_OK(domain
->last_status
))
2894 return domain
->last_status
;
2896 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2899 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2901 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2902 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2903 if (!domain
->internal
&& old_status
) {
2904 set_domain_offline(domain
);
2907 !domain
->internal
&&
2910 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2912 goto do_fetch_cache
;
2917 refresh_sequence_number(domain
);
2918 if (!NT_STATUS_IS_OK(status
)) {
2921 wcache_save_lockout_policy(domain
, status
, policy
);
2926 /* get password policy */
2927 NTSTATUS
wb_cache_password_policy(struct winbindd_domain
*domain
,
2928 TALLOC_CTX
*mem_ctx
,
2929 struct samr_DomInfo1
*policy
)
2931 struct winbind_cache
*cache
= get_cache(domain
);
2932 struct cache_entry
*centry
= NULL
;
2936 old_status
= domain
->online
;
2940 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2946 policy
->min_password_length
= centry_uint16(centry
);
2947 policy
->password_history_length
= centry_uint16(centry
);
2948 policy
->password_properties
= centry_uint32(centry
);
2949 policy
->max_password_age
= centry_nttime(centry
);
2950 policy
->min_password_age
= centry_nttime(centry
);
2952 status
= centry
->status
;
2954 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2955 domain
->name
, nt_errstr(status
) ));
2957 centry_free(centry
);
2961 ZERO_STRUCTP(policy
);
2963 /* Return status value returned by seq number check */
2965 if (!NT_STATUS_IS_OK(domain
->last_status
))
2966 return domain
->last_status
;
2968 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2971 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
2973 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2974 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2975 if (!domain
->internal
&& old_status
) {
2976 set_domain_offline(domain
);
2979 !domain
->internal
&&
2982 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2984 goto do_fetch_cache
;
2989 refresh_sequence_number(domain
);
2990 if (!NT_STATUS_IS_OK(status
)) {
2993 wcache_save_password_policy(domain
, status
, policy
);
2999 /* Invalidate cached user and group lists coherently */
3001 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3004 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
3005 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
3006 tdb_delete(the_tdb
, kbuf
);
3011 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3013 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
3014 const struct dom_sid
*sid
)
3016 fstring key_str
, sid_string
;
3017 struct winbind_cache
*cache
;
3019 /* don't clear cached U/SID and UG/SID entries when we want to logon
3022 if (lp_winbind_offline_logon()) {
3029 cache
= get_cache(domain
);
3035 /* Clear U/SID cache entry */
3036 fstr_sprintf(key_str
, "U/%s", sid_to_fstring(sid_string
, sid
));
3037 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3038 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3040 /* Clear UG/SID cache entry */
3041 fstr_sprintf(key_str
, "UG/%s", sid_to_fstring(sid_string
, sid
));
3042 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3043 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3045 /* Samba/winbindd never needs this. */
3046 netsamlogon_clear_cached_user(sid
);
3049 bool wcache_invalidate_cache(void)
3051 struct winbindd_domain
*domain
;
3053 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3054 struct winbind_cache
*cache
= get_cache(domain
);
3056 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3057 "entries for %s\n", domain
->name
));
3060 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3069 bool wcache_invalidate_cache_noinit(void)
3071 struct winbindd_domain
*domain
;
3073 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3074 struct winbind_cache
*cache
;
3076 /* Skip uninitialized domains. */
3077 if (!domain
->initialized
&& !domain
->internal
) {
3081 cache
= get_cache(domain
);
3083 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3084 "entries for %s\n", domain
->name
));
3087 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3089 * Flushing cache has nothing to with domains.
3090 * return here if we successfully flushed once.
3091 * To avoid unnecessary traversing the cache.
3102 static bool init_wcache(void)
3106 if (wcache
== NULL
) {
3107 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
3108 ZERO_STRUCTP(wcache
);
3111 if (wcache
->tdb
!= NULL
)
3114 db_path
= wcache_path();
3115 if (db_path
== NULL
) {
3119 /* when working offline we must not clear the cache on restart */
3120 wcache
->tdb
= tdb_open_log(db_path
,
3121 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3122 TDB_INCOMPATIBLE_HASH
|
3123 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3124 O_RDWR
|O_CREAT
, 0600);
3125 TALLOC_FREE(db_path
);
3126 if (wcache
->tdb
== NULL
) {
3127 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3134 /************************************************************************
3135 This is called by the parent to initialize the cache file.
3136 We don't need sophisticated locking here as we know we're the
3138 ************************************************************************/
3140 bool initialize_winbindd_cache(void)
3142 bool cache_bad
= true;
3145 if (!init_wcache()) {
3146 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3150 /* Check version number. */
3151 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
3152 vers
== WINBINDD_CACHE_VERSION
) {
3159 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3160 "and re-creating with version number %d\n",
3161 WINBINDD_CACHE_VERSION
));
3163 tdb_close(wcache
->tdb
);
3166 db_path
= wcache_path();
3167 if (db_path
== NULL
) {
3171 if (unlink(db_path
) == -1) {
3172 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3175 TALLOC_FREE(db_path
);
3178 TALLOC_FREE(db_path
);
3179 if (!init_wcache()) {
3180 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3181 "init_wcache failed.\n"));
3185 /* Write the version. */
3186 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
3187 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3188 tdb_errorstr(wcache
->tdb
) ));
3193 tdb_close(wcache
->tdb
);
3198 void close_winbindd_cache(void)
3204 tdb_close(wcache
->tdb
);
3209 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*sid
,
3210 char **domain_name
, char **name
,
3211 enum lsa_SidType
*type
)
3213 struct winbindd_domain
*domain
;
3216 domain
= find_lookup_domain_from_sid(sid
);
3217 if (domain
== NULL
) {
3220 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
3222 return NT_STATUS_IS_OK(status
);
3225 bool lookup_cached_name(const char *namespace,
3226 const char *domain_name
,
3228 struct dom_sid
*sid
,
3229 enum lsa_SidType
*type
)
3231 struct winbindd_domain
*domain
;
3233 bool original_online_state
;
3235 domain
= find_lookup_domain_from_name(namespace);
3236 if (domain
== NULL
) {
3240 /* If we are doing a cached logon, temporarily set the domain
3241 offline so the cache won't expire the entry */
3243 original_online_state
= domain
->online
;
3244 domain
->online
= false;
3245 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
3246 domain
->online
= original_online_state
;
3248 return NT_STATUS_IS_OK(status
);
3252 * Cache a name to sid without checking the sequence number.
3253 * Used when caching from a trusted PAC.
3256 void cache_name2sid_trusted(struct winbindd_domain
*domain
,
3257 const char *domain_name
,
3259 enum lsa_SidType type
,
3260 const struct dom_sid
*sid
)
3263 * Ensure we store the mapping with the
3264 * existing sequence number from the cache.
3267 (void)fetch_cache_seqnum(domain
, time(NULL
));
3268 wcache_save_name_to_sid(domain
,
3276 void cache_name2sid(struct winbindd_domain
*domain
,
3277 const char *domain_name
, const char *name
,
3278 enum lsa_SidType type
, const struct dom_sid
*sid
)
3280 refresh_sequence_number(domain
);
3281 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
3286 * The original idea that this cache only contains centries has
3287 * been blurred - now other stuff gets put in here. Ensure we
3288 * ignore these things on cleanup.
3291 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
3292 TDB_DATA dbuf
, void *state
)
3294 struct cache_entry
*centry
;
3296 if (is_non_centry_key(kbuf
)) {
3300 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
3305 if (!NT_STATUS_IS_OK(centry
->status
)) {
3306 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
3307 tdb_delete(the_tdb
, kbuf
);
3310 centry_free(centry
);
3314 /* flush the cache */
3315 static void wcache_flush_cache(void)
3322 tdb_close(wcache
->tdb
);
3325 if (!winbindd_use_cache()) {
3329 db_path
= wcache_path();
3330 if (db_path
== NULL
) {
3334 /* when working offline we must not clear the cache on restart */
3335 wcache
->tdb
= tdb_open_log(db_path
,
3336 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3337 TDB_INCOMPATIBLE_HASH
|
3338 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3339 O_RDWR
|O_CREAT
, 0600);
3340 TALLOC_FREE(db_path
);
3342 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3346 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
3348 DEBUG(10,("wcache_flush_cache success\n"));
3351 /* Count cached creds */
3353 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3356 int *cred_count
= (int*)state
;
3358 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3364 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
3366 struct winbind_cache
*cache
= get_cache(domain
);
3371 return NT_STATUS_INTERNAL_DB_ERROR
;
3374 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
3376 return NT_STATUS_OK
;
3380 struct cred_list
*prev
, *next
;
3385 static struct cred_list
*wcache_cred_list
;
3387 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3390 struct cred_list
*cred
;
3392 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3394 cred
= SMB_MALLOC_P(struct cred_list
);
3396 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3402 /* save a copy of the key */
3404 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
3405 DLIST_ADD(wcache_cred_list
, cred
);
3411 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
3413 struct winbind_cache
*cache
= get_cache(domain
);
3416 struct cred_list
*cred
, *next
, *oldest
= NULL
;
3419 return NT_STATUS_INTERNAL_DB_ERROR
;
3422 /* we possibly already have an entry */
3423 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
3425 fstring key_str
, tmp
;
3427 DEBUG(11,("we already have an entry, deleting that\n"));
3429 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
3431 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3433 return NT_STATUS_OK
;
3436 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
3438 return NT_STATUS_OK
;
3439 } else if ((ret
< 0) || (wcache_cred_list
== NULL
)) {
3440 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3443 ZERO_STRUCTP(oldest
);
3445 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
3450 data
= tdb_fetch(cache
->tdb
, string_tdb_data(cred
->name
));
3452 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3454 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3458 t
= IVAL(data
.dptr
, 0);
3459 SAFE_FREE(data
.dptr
);
3462 oldest
= SMB_MALLOC_P(struct cred_list
);
3463 if (oldest
== NULL
) {
3464 status
= NT_STATUS_NO_MEMORY
;
3468 fstrcpy(oldest
->name
, cred
->name
);
3469 oldest
->created
= t
;
3473 if (t
< oldest
->created
) {
3474 fstrcpy(oldest
->name
, cred
->name
);
3475 oldest
->created
= t
;
3479 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3480 status
= NT_STATUS_OK
;
3482 status
= NT_STATUS_UNSUCCESSFUL
;
3485 for (cred
= wcache_cred_list
; cred
; cred
= next
) {
3487 DLIST_REMOVE(wcache_cred_list
, cred
);
3495 /* Change the global online/offline state. */
3496 bool set_global_winbindd_state_offline(void)
3500 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3502 /* Only go offline if someone has created
3503 the key "WINBINDD_OFFLINE" in the cache tdb. */
3505 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3506 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3510 if (!lp_winbind_offline_logon()) {
3511 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3515 if (global_winbindd_offline_state
) {
3516 /* Already offline. */
3520 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
3522 if (!data
.dptr
|| data
.dsize
!= 4) {
3523 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3524 SAFE_FREE(data
.dptr
);
3527 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3528 global_winbindd_offline_state
= true;
3529 SAFE_FREE(data
.dptr
);
3534 void set_global_winbindd_state_online(void)
3536 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3538 if (!lp_winbind_offline_logon()) {
3539 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3543 if (!global_winbindd_offline_state
) {
3544 /* Already online. */
3547 global_winbindd_offline_state
= false;
3553 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3554 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3557 bool get_global_winbindd_state_offline(void)
3559 return global_winbindd_offline_state
;
3562 /***********************************************************************
3563 Validate functions for all possible cache tdb keys.
3564 ***********************************************************************/
3566 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3567 struct tdb_validation_status
*state
)
3569 struct cache_entry
*centry
;
3571 centry
= SMB_XMALLOC_P(struct cache_entry
);
3572 centry
->data
= (unsigned char *)smb_memdup(data
.dptr
, data
.dsize
);
3573 if (!centry
->data
) {
3577 centry
->len
= data
.dsize
;
3580 if (centry
->len
< 16) {
3581 /* huh? corrupt cache? */
3582 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3583 "(len < 16) ?\n", kstr
));
3584 centry_free(centry
);
3585 state
->bad_entry
= true;
3586 state
->success
= false;
3590 centry
->status
= NT_STATUS(centry_uint32(centry
));
3591 centry
->sequence_number
= centry_uint32(centry
);
3592 centry
->timeout
= centry_uint64_t(centry
);
3596 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3597 struct tdb_validation_status
*state
)
3599 if (dbuf
.dsize
!= 8) {
3600 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3601 keystr
, (unsigned int)dbuf
.dsize
));
3602 state
->bad_entry
= true;
3608 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3609 struct tdb_validation_status
*state
)
3611 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3618 (void)centry_string(centry
, mem_ctx
);
3619 (void)centry_string(centry
, mem_ctx
);
3620 (void)centry_string(centry
, mem_ctx
);
3621 (void)centry_string(centry
, mem_ctx
);
3622 (void)centry_string(centry
, mem_ctx
);
3623 (void)centry_uint32(centry
);
3624 (void)centry_uint32(centry
);
3625 (void)centry_string(centry
, mem_ctx
);
3626 (void)centry_sid(centry
, &sid
);
3627 (void)centry_sid(centry
, &sid
);
3629 centry_free(centry
);
3631 if (!(state
->success
)) {
3634 DEBUG(10,("validate_u: %s ok\n", keystr
));
3638 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3639 struct tdb_validation_status
*state
)
3641 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3647 (void)centry_nttime(centry
);
3648 (void)centry_nttime(centry
);
3649 (void)centry_uint16(centry
);
3651 centry_free(centry
);
3653 if (!(state
->success
)) {
3656 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3660 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3661 struct tdb_validation_status
*state
)
3663 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3669 (void)centry_uint16(centry
);
3670 (void)centry_uint16(centry
);
3671 (void)centry_uint32(centry
);
3672 (void)centry_nttime(centry
);
3673 (void)centry_nttime(centry
);
3675 centry_free(centry
);
3677 if (!(state
->success
)) {
3680 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3684 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3685 struct tdb_validation_status
*state
)
3687 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3693 (void)centry_time(centry
);
3694 (void)centry_hash16(centry
, mem_ctx
);
3696 /* We only have 17 bytes more data in the salted cred case. */
3697 if (centry
->len
- centry
->ofs
== 17) {
3698 (void)centry_hash16(centry
, mem_ctx
);
3701 centry_free(centry
);
3703 if (!(state
->success
)) {
3706 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3710 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3711 struct tdb_validation_status
*state
)
3713 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3714 int32_t num_entries
, i
;
3720 num_entries
= (int32_t)centry_uint32(centry
);
3722 for (i
=0; i
< num_entries
; i
++) {
3723 (void)centry_uint32(centry
);
3726 centry_free(centry
);
3728 if (!(state
->success
)) {
3731 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3735 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3736 struct tdb_validation_status
*state
)
3738 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3739 int32_t num_entries
, i
;
3745 num_entries
= centry_uint32(centry
);
3747 for (i
=0; i
< num_entries
; i
++) {
3748 (void)centry_string(centry
, mem_ctx
);
3749 (void)centry_string(centry
, mem_ctx
);
3750 (void)centry_uint32(centry
);
3753 centry_free(centry
);
3755 if (!(state
->success
)) {
3758 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3762 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3763 struct tdb_validation_status
*state
)
3765 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3766 int32_t num_groups
, i
;
3772 num_groups
= centry_uint32(centry
);
3774 for (i
=0; i
< num_groups
; i
++) {
3776 centry_sid(centry
, &sid
);
3779 centry_free(centry
);
3781 if (!(state
->success
)) {
3784 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3788 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3789 struct tdb_validation_status
*state
)
3791 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3792 int32_t num_aliases
, i
;
3798 num_aliases
= centry_uint32(centry
);
3800 for (i
=0; i
< num_aliases
; i
++) {
3801 (void)centry_uint32(centry
);
3804 centry_free(centry
);
3806 if (!(state
->success
)) {
3809 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3813 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3814 struct tdb_validation_status
*state
)
3816 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3817 int32_t num_names
, i
;
3823 num_names
= centry_uint32(centry
);
3825 for (i
=0; i
< num_names
; i
++) {
3827 centry_sid(centry
, &sid
);
3828 (void)centry_string(centry
, mem_ctx
);
3829 (void)centry_uint32(centry
);
3832 centry_free(centry
);
3834 if (!(state
->success
)) {
3837 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3841 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3842 struct tdb_validation_status
*state
)
3844 /* Can't say anything about this other than must be nonzero. */
3845 if (dbuf
.dsize
== 0) {
3846 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3848 state
->bad_entry
= true;
3849 state
->success
= false;
3853 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3857 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3858 struct tdb_validation_status
*state
)
3860 /* Can't say anything about this other than must be nonzero. */
3861 if (dbuf
.dsize
== 0) {
3862 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3864 state
->bad_entry
= true;
3865 state
->success
= false;
3869 DEBUG(10,("validate_de: %s ok\n", keystr
));
3873 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3875 struct tdb_validation_status
*state
)
3877 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3883 (void)centry_string( centry
, mem_ctx
);
3885 centry_free(centry
);
3887 if (!(state
->success
)) {
3890 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3894 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3896 struct tdb_validation_status
*state
)
3898 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3904 (void)centry_string( centry
, mem_ctx
);
3906 centry_free(centry
);
3908 if (!(state
->success
)) {
3911 DBG_DEBUG("%s ok\n", keystr
);
3915 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3917 struct tdb_validation_status
*state
)
3919 if (dbuf
.dsize
== 0) {
3920 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3921 "key %s (len ==0) ?\n", keystr
));
3922 state
->bad_entry
= true;
3923 state
->success
= false;
3927 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3928 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3932 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3933 struct tdb_validation_status
*state
)
3935 if (dbuf
.dsize
!= 4) {
3936 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3937 keystr
, (unsigned int)dbuf
.dsize
));
3938 state
->bad_entry
= true;
3939 state
->success
= false;
3942 DEBUG(10,("validate_offline: %s ok\n", keystr
));
3946 static int validate_ndr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3947 struct tdb_validation_status
*state
)
3950 * Ignore validation for now. The proper way to do this is with a
3951 * checksum. Just pure parsing does not really catch much.
3956 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3957 struct tdb_validation_status
*state
)
3959 if (dbuf
.dsize
!= 4) {
3960 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3961 "key %s (len %u != 4) ?\n",
3962 keystr
, (unsigned int)dbuf
.dsize
));
3963 state
->bad_entry
= true;
3964 state
->success
= false;
3968 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
3972 /***********************************************************************
3973 A list of all possible cache tdb keys with associated validation
3975 ***********************************************************************/
3977 struct key_val_struct
{
3978 const char *keyname
;
3979 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
3981 {"SEQNUM/", validate_seqnum
},
3983 {"LOC_POL/", validate_loc_pol
},
3984 {"PWD_POL/", validate_pwd_pol
},
3985 {"CRED/", validate_cred
},
3986 {"UL/", validate_ul
},
3987 {"GL/", validate_gl
},
3988 {"UG/", validate_ug
},
3989 {"UA", validate_ua
},
3990 {"GM/", validate_gm
},
3991 {"DR/", validate_dr
},
3992 {"DE/", validate_de
},
3993 {"TRUSTDOMCACHE/", validate_trustdomcache
},
3994 {"NSS/NA/", validate_nss_na
},
3995 {"NSS/AN/", validate_nss_an
},
3996 {"WINBINDD_OFFLINE", validate_offline
},
3997 {"NDR/", validate_ndr
},
3998 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
4002 /***********************************************************************
4003 Function to look at every entry in the tdb and validate it as far as
4005 ***********************************************************************/
4007 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
4010 unsigned int max_key_len
= 1024;
4011 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
4013 /* Paranoia check. */
4014 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0 ||
4015 strncmp("NDR/", (const char *)kbuf
.dptr
, 4) == 0) {
4016 max_key_len
= 1024 * 1024;
4018 if (kbuf
.dsize
> max_key_len
) {
4019 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4021 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
4025 for (i
= 0; key_val
[i
].keyname
; i
++) {
4026 size_t namelen
= strlen(key_val
[i
].keyname
);
4027 if (kbuf
.dsize
>= namelen
&& (
4028 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
4029 TALLOC_CTX
*mem_ctx
;
4033 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
4037 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
4038 keystr
[kbuf
.dsize
] = '\0';
4040 mem_ctx
= talloc_init("validate_ctx");
4046 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
4050 talloc_destroy(mem_ctx
);
4055 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4056 dump_data(0, (uint8_t *)kbuf
.dptr
, kbuf
.dsize
);
4057 DEBUG(0,("data :\n"));
4058 dump_data(0, (uint8_t *)dbuf
.dptr
, dbuf
.dsize
);
4059 v_state
->unknown_key
= true;
4060 v_state
->success
= false;
4061 return 1; /* terminate. */
4064 static void validate_panic(const char *const why
)
4066 DEBUG(0,("validating cache: would panic %s\n", why
));
4067 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4071 static int wbcache_update_centry_fn(TDB_CONTEXT
*tdb
,
4079 if (is_non_centry_key(key
)) {
4083 if (data
.dptr
== NULL
|| data
.dsize
== 0) {
4084 if (tdb_delete(tdb
, key
) < 0) {
4085 DEBUG(0, ("tdb_delete for [%s] failed!\n",
4091 /* add timeout to blob (uint64_t) */
4092 blob
.dsize
= data
.dsize
+ 8;
4094 blob
.dptr
= SMB_XMALLOC_ARRAY(uint8_t, blob
.dsize
);
4095 if (blob
.dptr
== NULL
) {
4098 memset(blob
.dptr
, 0, blob
.dsize
);
4100 /* copy status and seqnum */
4101 memcpy(blob
.dptr
, data
.dptr
, 8);
4104 ctimeout
= lp_winbind_cache_time() + time(NULL
);
4105 SBVAL(blob
.dptr
, 8, ctimeout
);
4108 memcpy(blob
.dptr
+ 16, data
.dptr
+ 8, data
.dsize
- 8);
4110 if (tdb_store(tdb
, key
, blob
, TDB_REPLACE
) < 0) {
4111 DEBUG(0, ("tdb_store to update [%s] failed!\n",
4113 SAFE_FREE(blob
.dptr
);
4117 SAFE_FREE(blob
.dptr
);
4121 static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT
*tdb
)
4125 DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
4127 rc
= tdb_traverse(tdb
, wbcache_update_centry_fn
, NULL
);
4135 /***********************************************************************
4136 Try and validate every entry in the winbindd cache. If we fail here,
4137 delete the cache tdb and return non-zero.
4138 ***********************************************************************/
4140 int winbindd_validate_cache(void)
4143 char *tdb_path
= NULL
;
4144 TDB_CONTEXT
*tdb
= NULL
;
4148 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4149 smb_panic_fn
= validate_panic
;
4151 tdb_path
= wcache_path();
4152 if (tdb_path
== NULL
) {
4156 tdb
= tdb_open_log(tdb_path
,
4157 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
4158 TDB_INCOMPATIBLE_HASH
|
4159 ( lp_winbind_offline_logon()
4161 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
4165 DEBUG(0, ("winbindd_validate_cache: "
4166 "error opening/initializing tdb\n"));
4170 /* Version check and upgrade code. */
4171 if (!tdb_fetch_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers_id
)) {
4172 DEBUG(10, ("Fresh database\n"));
4173 tdb_store_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
);
4174 vers_id
= WINBINDD_CACHE_VERSION
;
4177 if (vers_id
!= WINBINDD_CACHE_VERSION
) {
4178 if (vers_id
== WINBINDD_CACHE_VER1
) {
4179 ok
= wbcache_upgrade_v1_to_v2(tdb
);
4181 DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
4186 tdb_store_uint32(tdb
,
4187 WINBINDD_CACHE_VERSION_KEYSTR
,
4188 WINBINDD_CACHE_VERSION
);
4189 vers_id
= WINBINDD_CACHE_VER2
;
4195 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
4198 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4199 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
4204 TALLOC_FREE(tdb_path
);
4205 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4206 smb_panic_fn
= smb_panic
;
4210 /***********************************************************************
4211 Try and validate every entry in the winbindd cache.
4212 ***********************************************************************/
4214 int winbindd_validate_cache_nobackup(void)
4219 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4220 smb_panic_fn
= validate_panic
;
4222 tdb_path
= wcache_path();
4223 if (tdb_path
== NULL
) {
4224 goto err_panic_restore
;
4227 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
4228 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
4230 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
4234 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4238 TALLOC_FREE(tdb_path
);
4240 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4242 smb_panic_fn
= smb_panic
;
4246 bool winbindd_cache_validate_and_initialize(void)
4248 close_winbindd_cache();
4250 if (lp_winbind_offline_logon()) {
4251 if (winbindd_validate_cache() < 0) {
4252 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4253 "could be restored.\n"));
4257 return initialize_winbindd_cache();
4260 /*********************************************************************
4261 ********************************************************************/
4263 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
4264 struct winbindd_tdc_domain
**domains
,
4265 size_t *num_domains
)
4267 struct winbindd_tdc_domain
*list
= NULL
;
4269 bool set_only
= false;
4271 /* don't allow duplicates */
4276 for ( i
=0; i
< (*num_domains
); i
++ ) {
4277 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
4278 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4289 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, 1 );
4292 list
= talloc_realloc( *domains
, *domains
,
4293 struct winbindd_tdc_domain
,
4298 ZERO_STRUCT( list
[idx
] );
4304 list
[idx
].domain_name
= talloc_strdup(list
, new_dom
->name
);
4305 if (list
[idx
].domain_name
== NULL
) {
4308 if (new_dom
->alt_name
!= NULL
) {
4309 list
[idx
].dns_name
= talloc_strdup(list
, new_dom
->alt_name
);
4310 if (list
[idx
].dns_name
== NULL
) {
4315 if ( !is_null_sid( &new_dom
->sid
) ) {
4316 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
4318 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
4321 if ( new_dom
->domain_flags
!= 0x0 )
4322 list
[idx
].trust_flags
= new_dom
->domain_flags
;
4324 if ( new_dom
->domain_type
!= 0x0 )
4325 list
[idx
].trust_type
= new_dom
->domain_type
;
4327 if ( new_dom
->domain_trust_attribs
!= 0x0 )
4328 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
4332 *num_domains
= idx
+ 1;
4338 /*********************************************************************
4339 ********************************************************************/
4341 static TDB_DATA
make_tdc_key( const char *domain_name
)
4343 char *keystr
= NULL
;
4344 TDB_DATA key
= { NULL
, 0 };
4346 if ( !domain_name
) {
4347 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4351 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
4354 key
= string_term_tdb_data(keystr
);
4359 /*********************************************************************
4360 ********************************************************************/
4362 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
4364 unsigned char **buf
)
4366 unsigned char *buffer
= NULL
;
4371 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4379 /* Store the number of array items first */
4380 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
4383 /* now pack each domain trust record */
4384 for ( i
=0; i
<num_domains
; i
++ ) {
4389 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4390 domains
[i
].domain_name
,
4391 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
4394 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
4395 domains
[i
].domain_name
,
4396 domains
[i
].dns_name
? domains
[i
].dns_name
: "",
4397 sid_to_fstring(tmp
, &domains
[i
].sid
),
4398 domains
[i
].trust_flags
,
4399 domains
[i
].trust_attribs
,
4400 domains
[i
].trust_type
);
4403 if ( buflen
< len
) {
4405 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
4406 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4420 /*********************************************************************
4421 ********************************************************************/
4423 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
4424 struct winbindd_tdc_domain
**domains
)
4426 fstring domain_name
, dns_name
, sid_string
;
4427 uint32_t type
, attribs
, flags
;
4431 struct winbindd_tdc_domain
*list
= NULL
;
4433 /* get the number of domains */
4434 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
4436 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4440 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, num_domains
);
4442 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4446 for ( i
=0; i
<num_domains
; i
++ ) {
4449 this_len
= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
4457 if ( this_len
== -1 ) {
4458 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4459 TALLOC_FREE( list
);
4464 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4465 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4466 domain_name
, dns_name
, sid_string
,
4467 flags
, attribs
, type
));
4469 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
4470 list
[i
].dns_name
= NULL
;
4471 if (dns_name
[0] != '\0') {
4472 list
[i
].dns_name
= talloc_strdup(list
, dns_name
);
4474 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
4475 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4478 list
[i
].trust_flags
= flags
;
4479 list
[i
].trust_attribs
= attribs
;
4480 list
[i
].trust_type
= type
;
4488 /*********************************************************************
4489 ********************************************************************/
4491 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
4493 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4494 TDB_DATA data
= { NULL
, 0 };
4500 /* See if we were asked to delete the cache entry */
4503 ret
= tdb_delete( wcache
->tdb
, key
);
4507 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4514 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4517 SAFE_FREE( data
.dptr
);
4518 SAFE_FREE( key
.dptr
);
4520 return ( ret
== 0 );
4523 /*********************************************************************
4524 ********************************************************************/
4526 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4528 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4529 TDB_DATA data
= { NULL
, 0 };
4537 data
= tdb_fetch( wcache
->tdb
, key
);
4539 SAFE_FREE( key
.dptr
);
4544 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4546 SAFE_FREE( data
.dptr
);
4554 /*********************************************************************
4555 ********************************************************************/
4557 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4559 struct winbindd_tdc_domain
*dom_list
= NULL
;
4560 size_t num_domains
= 0;
4563 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4564 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4565 domain
->name
, domain
->alt_name
,
4566 sid_string_dbg(&domain
->sid
),
4567 domain
->domain_flags
,
4568 domain
->domain_trust_attribs
,
4569 domain
->domain_type
));
4571 if ( !init_wcache() ) {
4575 /* fetch the list */
4577 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4579 /* add the new domain */
4581 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4585 /* pack the domain */
4587 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4595 TALLOC_FREE( dom_list
);
4600 static struct winbindd_tdc_domain
*wcache_tdc_dup_domain(
4601 TALLOC_CTX
*mem_ctx
, const struct winbindd_tdc_domain
*src
)
4603 struct winbindd_tdc_domain
*dst
;
4605 dst
= talloc(mem_ctx
, struct winbindd_tdc_domain
);
4609 dst
->domain_name
= talloc_strdup(dst
, src
->domain_name
);
4610 if (dst
->domain_name
== NULL
) {
4614 dst
->dns_name
= NULL
;
4615 if (src
->dns_name
!= NULL
) {
4616 dst
->dns_name
= talloc_strdup(dst
, src
->dns_name
);
4617 if (dst
->dns_name
== NULL
) {
4622 sid_copy(&dst
->sid
, &src
->sid
);
4623 dst
->trust_flags
= src
->trust_flags
;
4624 dst
->trust_type
= src
->trust_type
;
4625 dst
->trust_attribs
= src
->trust_attribs
;
4632 /*********************************************************************
4633 ********************************************************************/
4635 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4637 struct winbindd_tdc_domain
*dom_list
= NULL
;
4638 size_t num_domains
= 0;
4640 struct winbindd_tdc_domain
*d
= NULL
;
4642 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4644 if ( !init_wcache() ) {
4648 /* fetch the list */
4650 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4652 for ( i
=0; i
<num_domains
; i
++ ) {
4653 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4654 strequal(name
, dom_list
[i
].dns_name
) )
4656 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4659 d
= wcache_tdc_dup_domain(ctx
, &dom_list
[i
]);
4664 TALLOC_FREE( dom_list
);
4669 /*********************************************************************
4670 ********************************************************************/
4672 void wcache_tdc_clear( void )
4674 if ( !init_wcache() )
4677 wcache_tdc_store_list( NULL
, 0 );
4682 static bool wcache_ndr_key(TALLOC_CTX
*mem_ctx
, const char *domain_name
,
4683 uint32_t opnum
, const DATA_BLOB
*req
,
4689 key
= talloc_asprintf(mem_ctx
, "NDR/%s/%d/", domain_name
, (int)opnum
);
4693 keylen
= talloc_get_size(key
) - 1;
4695 key
= talloc_realloc(mem_ctx
, key
, char, keylen
+ req
->length
);
4699 memcpy(key
+ keylen
, req
->data
, req
->length
);
4701 pkey
->dptr
= (uint8_t *)key
;
4702 pkey
->dsize
= talloc_get_size(key
);
4706 static bool wcache_opnum_cacheable(uint32_t opnum
)
4709 case NDR_WBINT_PING
:
4710 case NDR_WBINT_QUERYSEQUENCENUMBER
:
4711 case NDR_WBINT_ALLOCATEUID
:
4712 case NDR_WBINT_ALLOCATEGID
:
4713 case NDR_WBINT_CHECKMACHINEACCOUNT
:
4714 case NDR_WBINT_CHANGEMACHINEACCOUNT
:
4715 case NDR_WBINT_PINGDC
:
4721 bool wcache_fetch_ndr(TALLOC_CTX
*mem_ctx
, struct winbindd_domain
*domain
,
4722 uint32_t opnum
, const DATA_BLOB
*req
, DATA_BLOB
*resp
)
4727 if (!wcache_opnum_cacheable(opnum
) ||
4728 is_my_own_sam_domain(domain
) ||
4729 is_builtin_domain(domain
)) {
4733 if (wcache
->tdb
== NULL
) {
4737 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4740 data
= tdb_fetch(wcache
->tdb
, key
);
4741 TALLOC_FREE(key
.dptr
);
4743 if (data
.dptr
== NULL
) {
4746 if (data
.dsize
< 12) {
4750 if (is_domain_online(domain
)) {
4751 uint32_t entry_seqnum
, dom_seqnum
, last_check
;
4752 uint64_t entry_timeout
;
4754 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
,
4758 entry_seqnum
= IVAL(data
.dptr
, 0);
4759 if (entry_seqnum
!= dom_seqnum
) {
4760 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4761 (int)entry_seqnum
));
4764 entry_timeout
= BVAL(data
.dptr
, 4);
4765 if (time(NULL
) > (time_t)entry_timeout
) {
4766 DEBUG(10, ("Entry has timed out\n"));
4771 resp
->data
= (uint8_t *)talloc_memdup(mem_ctx
, data
.dptr
+ 12,
4773 if (resp
->data
== NULL
) {
4774 DEBUG(10, ("talloc failed\n"));
4777 resp
->length
= data
.dsize
- 12;
4781 SAFE_FREE(data
.dptr
);
4785 void wcache_store_ndr(struct winbindd_domain
*domain
, uint32_t opnum
,
4786 const DATA_BLOB
*req
, const DATA_BLOB
*resp
)
4789 uint32_t dom_seqnum
, last_check
;
4792 if (!wcache_opnum_cacheable(opnum
) ||
4793 is_my_own_sam_domain(domain
) ||
4794 is_builtin_domain(domain
)) {
4798 if (wcache
->tdb
== NULL
) {
4802 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
, &last_check
)) {
4803 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4808 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4812 timeout
= time(NULL
) + lp_winbind_cache_time();
4814 data
.dsize
= resp
->length
+ 12;
4815 data
.dptr
= talloc_array(key
.dptr
, uint8_t, data
.dsize
);
4816 if (data
.dptr
== NULL
) {
4820 SIVAL(data
.dptr
, 0, dom_seqnum
);
4821 SBVAL(data
.dptr
, 4, timeout
);
4822 memcpy(data
.dptr
+ 12, resp
->data
, resp
->length
);
4824 tdb_store(wcache
->tdb
, key
, data
, 0);
4827 TALLOC_FREE(key
.dptr
);