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(talloc_tos(), "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
)
857 struct dom_sid_buf sid_string
;
858 centry_put_string(centry
, dom_sid_str_buf(sid
, &sid_string
));
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 struct dom_sid_buf tmp
;
1249 return NT_STATUS_INTERNAL_DB_ERROR
;
1252 if (is_null_sid(sid
)) {
1253 return NT_STATUS_INVALID_SID
;
1256 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1257 return NT_STATUS_INVALID_SID
;
1260 fstr_sprintf(key_str
, "CRED/%s", dom_sid_str_buf(sid
, &tmp
));
1262 ret
= tdb_exists(cache
->tdb
, string_tdb_data(key_str
));
1264 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1267 return NT_STATUS_OK
;
1270 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1271 as new salted ones. */
1273 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
1274 TALLOC_CTX
*mem_ctx
,
1275 const struct dom_sid
*sid
,
1276 const uint8_t **cached_nt_pass
,
1277 const uint8_t **cached_salt
)
1279 struct winbind_cache
*cache
= get_cache(domain
);
1280 struct cache_entry
*centry
= NULL
;
1283 struct dom_sid_buf sidstr
;
1286 return NT_STATUS_INTERNAL_DB_ERROR
;
1289 if (is_null_sid(sid
)) {
1290 return NT_STATUS_INVALID_SID
;
1293 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1294 return NT_STATUS_INVALID_SID
;
1297 /* Try and get a salted cred first. If we can't
1298 fall back to an unsalted cred. */
1300 centry
= wcache_fetch(cache
, domain
, "CRED/%s",
1301 dom_sid_str_buf(sid
, &sidstr
));
1303 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1304 dom_sid_str_buf(sid
, &sidstr
)));
1305 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1309 * We don't use the time element at this moment,
1310 * but we have to consume it, so that we don't
1311 * neet to change the disk format of the cache.
1313 (void)centry_time(centry
);
1315 /* In the salted case this isn't actually the nt_hash itself,
1316 but the MD5 of the salt + nt_hash. Let the caller
1317 sort this out. It can tell as we only return the cached_salt
1318 if we are returning a salted cred. */
1320 *cached_nt_pass
= (const uint8_t *)centry_hash16(centry
, mem_ctx
);
1321 if (*cached_nt_pass
== NULL
) {
1323 dom_sid_str_buf(sid
, &sidstr
);
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
.buf
);
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 dom_sid_str_buf(sid
, &sidstr
),
1350 nt_errstr(status
) ));
1352 centry_free(centry
);
1356 /* Store creds for a SID - only writes out new salted ones. */
1358 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1359 const struct dom_sid
*sid
,
1360 const uint8_t nt_pass
[NT_HASH_LEN
])
1362 struct cache_entry
*centry
;
1363 struct dom_sid_buf sid_str
;
1365 uint8_t cred_salt
[NT_HASH_LEN
];
1366 uint8_t salted_hash
[NT_HASH_LEN
];
1368 if (is_null_sid(sid
)) {
1369 return NT_STATUS_INVALID_SID
;
1372 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1373 return NT_STATUS_INVALID_SID
;
1376 centry
= centry_start(domain
, NT_STATUS_OK
);
1378 return NT_STATUS_INTERNAL_DB_ERROR
;
1381 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1383 centry_put_time(centry
, time(NULL
));
1385 /* Create a salt and then salt the hash. */
1386 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1387 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1389 centry_put_hash16(centry
, salted_hash
);
1390 centry_put_hash16(centry
, cred_salt
);
1391 centry_end(centry
, "CRED/%s", dom_sid_str_buf(sid
, &sid_str
));
1393 DEBUG(10,("wcache_save_creds: %s\n", sid_str
.buf
));
1395 centry_free(centry
);
1397 return NT_STATUS_OK
;
1401 /* Query display info. This is the basic user list fn */
1402 NTSTATUS
wb_cache_query_user_list(struct winbindd_domain
*domain
,
1403 TALLOC_CTX
*mem_ctx
,
1406 struct winbind_cache
*cache
= get_cache(domain
);
1407 struct cache_entry
*centry
= NULL
;
1408 uint32_t num_rids
= 0;
1409 uint32_t *rids
= NULL
;
1411 unsigned int i
, retry
;
1412 bool old_status
= domain
->online
;
1419 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1424 num_rids
= centry_uint32(centry
);
1426 if (num_rids
== 0) {
1430 rids
= talloc_array(mem_ctx
, uint32_t, num_rids
);
1432 centry_free(centry
);
1433 return NT_STATUS_NO_MEMORY
;
1436 for (i
=0; i
<num_rids
; i
++) {
1437 rids
[i
] = centry_uint32(centry
);
1441 status
= centry
->status
;
1443 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1444 domain
->name
, nt_errstr(status
) ));
1446 centry_free(centry
);
1451 /* Return status value returned by seq number check */
1453 if (!NT_STATUS_IS_OK(domain
->last_status
))
1454 return domain
->last_status
;
1456 /* Put the query_user_list() in a retry loop. There appears to be
1457 * some bug either with Windows 2000 or Samba's handling of large
1458 * rpc replies. This manifests itself as sudden disconnection
1459 * at a random point in the enumeration of a large (60k) user list.
1460 * The retry loop simply tries the operation again. )-: It's not
1461 * pretty but an acceptable workaround until we work out what the
1462 * real problem is. */
1467 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1471 status
= domain
->backend
->query_user_list(domain
, mem_ctx
,
1473 num_rids
= talloc_array_length(rids
);
1475 if (!NT_STATUS_IS_OK(status
)) {
1476 DEBUG(3, ("query_user_list: returned 0x%08x, "
1477 "retrying\n", NT_STATUS_V(status
)));
1479 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1480 DEBUG(3, ("query_user_list: flushing "
1481 "connection cache\n"));
1482 invalidate_cm_connection(domain
);
1484 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1485 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1486 if (!domain
->internal
&& old_status
) {
1487 set_domain_offline(domain
);
1489 /* store partial response. */
1492 * humm, what about the status used for cache?
1493 * Should it be NT_STATUS_OK?
1498 * domain is offline now, and there is no user entries,
1499 * try to fetch from cache again.
1501 if (cache
->tdb
&& !domain
->online
&& !domain
->internal
&& old_status
) {
1502 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1503 /* partial response... */
1507 goto do_fetch_cache
;
1514 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1518 refresh_sequence_number(domain
);
1519 if (!NT_STATUS_IS_OK(status
)) {
1522 centry
= centry_start(domain
, status
);
1525 centry_put_uint32(centry
, num_rids
);
1526 for (i
=0; i
<num_rids
; i
++) {
1527 centry_put_uint32(centry
, rids
[i
]);
1529 centry_end(centry
, "UL/%s", domain
->name
);
1530 centry_free(centry
);
1538 /* list all domain groups */
1539 NTSTATUS
wb_cache_enum_dom_groups(struct winbindd_domain
*domain
,
1540 TALLOC_CTX
*mem_ctx
,
1541 uint32_t *num_entries
,
1542 struct wb_acct_info
**info
)
1544 struct winbind_cache
*cache
= get_cache(domain
);
1545 struct cache_entry
*centry
= NULL
;
1550 old_status
= domain
->online
;
1554 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1559 *num_entries
= centry_uint32(centry
);
1561 if (*num_entries
== 0)
1564 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1566 smb_panic_fn("enum_dom_groups out of memory");
1568 for (i
=0; i
<(*num_entries
); i
++) {
1569 (*info
)[i
].acct_name
= centry_string(centry
, (*info
));
1570 (*info
)[i
].acct_desc
= centry_string(centry
, (*info
));
1571 (*info
)[i
].rid
= centry_uint32(centry
);
1575 status
= centry
->status
;
1577 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1578 domain
->name
, nt_errstr(status
) ));
1580 centry_free(centry
);
1587 /* Return status value returned by seq number check */
1589 if (!NT_STATUS_IS_OK(domain
->last_status
))
1590 return domain
->last_status
;
1592 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1595 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1597 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1598 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1599 if (!domain
->internal
&& old_status
) {
1600 set_domain_offline(domain
);
1604 !domain
->internal
&&
1606 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1608 goto do_fetch_cache
;
1613 refresh_sequence_number(domain
);
1614 if (!NT_STATUS_IS_OK(status
)) {
1617 centry
= centry_start(domain
, status
);
1620 centry_put_uint32(centry
, *num_entries
);
1621 for (i
=0; i
<(*num_entries
); i
++) {
1622 centry_put_string(centry
, (*info
)[i
].acct_name
);
1623 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1624 centry_put_uint32(centry
, (*info
)[i
].rid
);
1626 centry_end(centry
, "GL/%s/domain", domain
->name
);
1627 centry_free(centry
);
1633 /* list all domain groups */
1634 NTSTATUS
wb_cache_enum_local_groups(struct winbindd_domain
*domain
,
1635 TALLOC_CTX
*mem_ctx
,
1636 uint32_t *num_entries
,
1637 struct wb_acct_info
**info
)
1639 struct winbind_cache
*cache
= get_cache(domain
);
1640 struct cache_entry
*centry
= NULL
;
1645 old_status
= domain
->online
;
1649 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1654 *num_entries
= centry_uint32(centry
);
1656 if (*num_entries
== 0)
1659 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1661 smb_panic_fn("enum_dom_groups out of memory");
1663 for (i
=0; i
<(*num_entries
); i
++) {
1664 (*info
)[i
].acct_name
= centry_string(centry
, (*info
));
1665 (*info
)[i
].acct_desc
= centry_string(centry
, (*info
));
1666 (*info
)[i
].rid
= centry_uint32(centry
);
1671 /* If we are returning cached data and the domain controller
1672 is down then we don't know whether the data is up to date
1673 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1676 if (wcache_server_down(domain
)) {
1677 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1678 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1680 status
= centry
->status
;
1682 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1683 domain
->name
, nt_errstr(status
) ));
1685 centry_free(centry
);
1692 /* Return status value returned by seq number check */
1694 if (!NT_STATUS_IS_OK(domain
->last_status
))
1695 return domain
->last_status
;
1697 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1700 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1702 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1703 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1704 if (!domain
->internal
&& old_status
) {
1705 set_domain_offline(domain
);
1708 !domain
->internal
&&
1711 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1713 goto do_fetch_cache
;
1718 refresh_sequence_number(domain
);
1719 if (!NT_STATUS_IS_OK(status
)) {
1722 centry
= centry_start(domain
, status
);
1725 centry_put_uint32(centry
, *num_entries
);
1726 for (i
=0; i
<(*num_entries
); i
++) {
1727 centry_put_string(centry
, (*info
)[i
].acct_name
);
1728 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1729 centry_put_uint32(centry
, (*info
)[i
].rid
);
1731 centry_end(centry
, "GL/%s/local", domain
->name
);
1732 centry_free(centry
);
1738 struct wcache_name_to_sid_state
{
1739 struct dom_sid
*sid
;
1740 enum lsa_SidType
*type
;
1745 static void wcache_name_to_sid_fn(const struct dom_sid
*sid
,
1746 enum lsa_SidType type
,
1750 struct wcache_name_to_sid_state
*state
= private_data
;
1753 *state
->type
= type
;
1754 state
->found
= (!expired
|| state
->offline
);
1757 static NTSTATUS
wcache_name_to_sid(struct winbindd_domain
*domain
,
1758 const char *domain_name
,
1760 struct dom_sid
*sid
,
1761 enum lsa_SidType
*type
)
1763 struct wcache_name_to_sid_state state
= {
1764 .sid
= sid
, .type
= type
, .found
= false,
1765 .offline
= is_domain_offline(domain
),
1769 ok
= namemap_cache_find_name(domain_name
, name
, wcache_name_to_sid_fn
,
1772 DBG_DEBUG("namemap_cache_find_name failed\n");
1773 return NT_STATUS_NOT_FOUND
;
1776 DBG_DEBUG("cache entry not found\n");
1777 return NT_STATUS_NOT_FOUND
;
1779 if (*type
== SID_NAME_UNKNOWN
) {
1780 return NT_STATUS_NONE_MAPPED
;
1783 return NT_STATUS_OK
;
1786 /* convert a single name to a sid in a domain */
1787 NTSTATUS
wb_cache_name_to_sid(struct winbindd_domain
*domain
,
1788 TALLOC_CTX
*mem_ctx
,
1789 const char *domain_name
,
1792 struct dom_sid
*sid
,
1793 enum lsa_SidType
*type
)
1797 const char *dom_name
;
1799 old_status
= domain
->online
;
1801 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1802 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1808 /* If the seq number check indicated that there is a problem
1809 * with this DC, then return that status... except for
1810 * access_denied. This is special because the dc may be in
1811 * "restrict anonymous = 1" mode, in which case it will deny
1812 * most unauthenticated operations, but *will* allow the LSA
1813 * name-to-sid that we try as a fallback. */
1815 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1816 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1817 return domain
->last_status
;
1819 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1822 winbindd_domain_init_backend(domain
);
1823 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
,
1824 name
, flags
, &dom_name
, sid
, type
);
1826 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1827 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1828 if (!domain
->internal
&& old_status
) {
1829 set_domain_offline(domain
);
1831 if (!domain
->internal
&&
1834 NTSTATUS cache_status
;
1835 cache_status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1836 return cache_status
;
1841 if (domain
->online
&&
1842 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1843 enum lsa_SidType save_type
= *type
;
1845 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1846 save_type
= SID_NAME_UNKNOWN
;
1849 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
,
1852 /* Only save the reverse mapping if this was not a UPN */
1853 if (!strchr(name
, '@')) {
1854 if (!strupper_m(discard_const_p(char, domain_name
))) {
1855 return NT_STATUS_INVALID_PARAMETER
;
1857 (void)strlower_m(discard_const_p(char, name
));
1858 wcache_save_sid_to_name(domain
, status
, sid
,
1859 dom_name
, name
, save_type
);
1866 struct wcache_sid_to_name_state
{
1867 TALLOC_CTX
*mem_ctx
;
1870 enum lsa_SidType
*type
;
1875 static void wcache_sid_to_name_fn(const char *domain
,
1877 enum lsa_SidType type
,
1881 struct wcache_sid_to_name_state
*state
= private_data
;
1883 *state
->domain_name
= talloc_strdup(state
->mem_ctx
, domain
);
1884 if (*state
->domain_name
== NULL
) {
1887 *state
->name
= talloc_strdup(state
->mem_ctx
, name
);
1888 if (*state
->name
== NULL
) {
1891 *state
->type
= type
;
1892 state
->found
= (!expired
|| state
->offline
);
1895 static NTSTATUS
wcache_sid_to_name(struct winbindd_domain
*domain
,
1896 const struct dom_sid
*sid
,
1897 TALLOC_CTX
*mem_ctx
,
1900 enum lsa_SidType
*type
)
1902 struct wcache_sid_to_name_state state
= {
1903 .mem_ctx
= mem_ctx
, .found
= false,
1904 .domain_name
= domain_name
, .name
= name
, .type
= type
,
1905 .offline
= is_domain_offline(domain
)
1909 ok
= namemap_cache_find_sid(sid
, wcache_sid_to_name_fn
, &state
);
1911 DBG_DEBUG("namemap_cache_find_name failed\n");
1912 return NT_STATUS_NOT_FOUND
;
1915 DBG_DEBUG("cache entry not found\n");
1916 return NT_STATUS_NOT_FOUND
;
1918 if (*type
== SID_NAME_UNKNOWN
) {
1919 return NT_STATUS_NONE_MAPPED
;
1922 return NT_STATUS_OK
;
1925 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1927 NTSTATUS
wb_cache_sid_to_name(struct winbindd_domain
*domain
,
1928 TALLOC_CTX
*mem_ctx
,
1929 const struct dom_sid
*sid
,
1932 enum lsa_SidType
*type
)
1937 old_status
= domain
->online
;
1938 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
1940 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1945 *domain_name
= NULL
;
1947 /* If the seq number check indicated that there is a problem
1948 * with this DC, then return that status... except for
1949 * access_denied. This is special because the dc may be in
1950 * "restrict anonymous = 1" mode, in which case it will deny
1951 * most unauthenticated operations, but *will* allow the LSA
1952 * sid-to-name that we try as a fallback. */
1954 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1955 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1956 return domain
->last_status
;
1958 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1961 winbindd_domain_init_backend(domain
);
1963 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1965 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1966 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1967 if (!domain
->internal
&& old_status
) {
1968 set_domain_offline(domain
);
1970 if (!domain
->internal
&&
1973 NTSTATUS cache_status
;
1974 cache_status
= wcache_sid_to_name(domain
, sid
, mem_ctx
,
1975 domain_name
, name
, type
);
1976 return cache_status
;
1980 if (!NT_STATUS_IS_OK(status
)) {
1983 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
1985 /* We can't save the name to sid mapping here, as with sid history a
1986 * later name2sid would give the wrong sid. */
1991 NTSTATUS
wb_cache_rids_to_names(struct winbindd_domain
*domain
,
1992 TALLOC_CTX
*mem_ctx
,
1993 const struct dom_sid
*domain_sid
,
1998 enum lsa_SidType
**types
)
2000 struct winbind_cache
*cache
= get_cache(domain
);
2002 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
2007 old_status
= domain
->online
;
2008 *domain_name
= NULL
;
2016 if (num_rids
== 0) {
2017 return NT_STATUS_OK
;
2020 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2021 *types
= talloc_array(mem_ctx
, enum lsa_SidType
, num_rids
);
2023 if ((*names
== NULL
) || (*types
== NULL
)) {
2024 result
= NT_STATUS_NO_MEMORY
;
2028 have_mapped
= have_unmapped
= false;
2030 for (i
=0; i
<num_rids
; i
++) {
2033 enum lsa_SidType type
;
2036 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2037 result
= NT_STATUS_INTERNAL_ERROR
;
2041 status
= wcache_sid_to_name(domain
, &sid
, *names
, &dom
,
2044 (*types
)[i
] = SID_NAME_UNKNOWN
;
2045 (*names
)[i
] = talloc_strdup(*names
, "");
2047 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2052 if (NT_STATUS_IS_OK(status
)) {
2056 if (*domain_name
== NULL
) {
2064 } else if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
2065 have_unmapped
= true;
2067 /* something's definitely wrong */
2074 return NT_STATUS_NONE_MAPPED
;
2076 if (!have_unmapped
) {
2077 return NT_STATUS_OK
;
2079 return STATUS_SOME_UNMAPPED
;
2083 TALLOC_FREE(*names
);
2084 TALLOC_FREE(*types
);
2086 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
2087 rids
, num_rids
, domain_name
,
2090 if (NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
2091 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2092 if (!domain
->internal
&& old_status
) {
2093 set_domain_offline(domain
);
2096 !domain
->internal
&&
2099 have_mapped
= have_unmapped
= false;
2101 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2102 if (*names
== NULL
) {
2103 result
= NT_STATUS_NO_MEMORY
;
2107 *types
= talloc_array(mem_ctx
, enum lsa_SidType
,
2109 if (*types
== NULL
) {
2110 result
= NT_STATUS_NO_MEMORY
;
2114 for (i
=0; i
<num_rids
; i
++) {
2117 enum lsa_SidType type
;
2120 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2121 result
= NT_STATUS_INTERNAL_ERROR
;
2125 status
= wcache_sid_to_name(domain
, &sid
,
2129 (*types
)[i
] = SID_NAME_UNKNOWN
;
2130 (*names
)[i
] = talloc_strdup(*names
, "");
2132 if (NT_STATUS_IS_OK(status
)) {
2136 if (*domain_name
== NULL
) {
2144 } else if (NT_STATUS_EQUAL(
2146 NT_STATUS_NONE_MAPPED
)) {
2147 have_unmapped
= true;
2149 /* something's definitely wrong */
2156 return NT_STATUS_NONE_MAPPED
;
2158 if (!have_unmapped
) {
2159 return NT_STATUS_OK
;
2161 return STATUS_SOME_UNMAPPED
;
2165 None of the queried rids has been found so save all negative entries
2167 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
2168 for (i
= 0; i
< num_rids
; i
++) {
2170 const char *name
= "";
2171 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
2172 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
2174 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2175 return NT_STATUS_INTERNAL_ERROR
;
2178 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2186 Some or all of the queried rids have been found.
2188 if (!NT_STATUS_IS_OK(result
) &&
2189 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
2193 refresh_sequence_number(domain
);
2195 for (i
=0; i
<num_rids
; i
++) {
2199 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2200 result
= NT_STATUS_INTERNAL_ERROR
;
2204 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
2205 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
2207 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2208 (*names
)[i
], (*types
)[i
]);
2214 TALLOC_FREE(*names
);
2215 TALLOC_FREE(*types
);
2219 static NTSTATUS
wcache_query_user(struct winbindd_domain
*domain
,
2220 TALLOC_CTX
*mem_ctx
,
2221 const struct dom_sid
*user_sid
,
2222 struct wbint_userinfo
*info
)
2224 struct winbind_cache
*cache
= get_cache(domain
);
2225 struct cache_entry
*centry
= NULL
;
2227 struct dom_sid_buf sid_string
;
2229 if (cache
->tdb
== NULL
) {
2230 return NT_STATUS_NOT_FOUND
;
2233 centry
= wcache_fetch(
2234 cache
, domain
, "U/%s", dom_sid_str_buf(user_sid
, &sid_string
));
2235 if (centry
== NULL
) {
2236 return NT_STATUS_NOT_FOUND
;
2240 * If we have an access denied cache entry and a cached info3
2241 * in the samlogon cache then do a query. This will force the
2242 * rpc back end to return the info3 data.
2245 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
) &&
2246 netsamlogon_cache_have(user_sid
)) {
2247 DEBUG(10, ("query_user: cached access denied and have cached "
2249 domain
->last_status
= NT_STATUS_OK
;
2250 centry_free(centry
);
2251 return NT_STATUS_NOT_FOUND
;
2254 /* if status is not ok then this is a negative hit
2255 and the rest of the data doesn't matter */
2256 status
= centry
->status
;
2257 if (NT_STATUS_IS_OK(status
)) {
2258 info
->domain_name
= centry_string(centry
, mem_ctx
);
2259 info
->acct_name
= centry_string(centry
, mem_ctx
);
2260 info
->full_name
= centry_string(centry
, mem_ctx
);
2261 info
->homedir
= centry_string(centry
, mem_ctx
);
2262 info
->shell
= centry_string(centry
, mem_ctx
);
2263 info
->uid
= centry_uint32(centry
);
2264 info
->primary_gid
= centry_uint32(centry
);
2265 info
->primary_group_name
= centry_string(centry
, mem_ctx
);
2266 centry_sid(centry
, &info
->user_sid
);
2267 centry_sid(centry
, &info
->group_sid
);
2270 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2271 "%s\n", domain
->name
, nt_errstr(status
) ));
2273 centry_free(centry
);
2279 * @brief Query a fullname from the username cache (for further gecos processing)
2281 * @param domain A pointer to the winbindd_domain struct.
2282 * @param mem_ctx The talloc context.
2283 * @param user_sid The user sid.
2284 * @param full_name A pointer to the full_name string.
2286 * @return NTSTATUS code
2288 NTSTATUS
wcache_query_user_fullname(struct winbindd_domain
*domain
,
2289 TALLOC_CTX
*mem_ctx
,
2290 const struct dom_sid
*user_sid
,
2291 const char **full_name
)
2294 struct wbint_userinfo info
;
2296 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, &info
);
2297 if (!NT_STATUS_IS_OK(status
)) {
2301 if (info
.full_name
!= NULL
) {
2302 *full_name
= talloc_strdup(mem_ctx
, info
.full_name
);
2303 if (*full_name
== NULL
) {
2304 return NT_STATUS_NO_MEMORY
;
2308 return NT_STATUS_OK
;
2311 static NTSTATUS
wcache_lookup_usergroups(struct winbindd_domain
*domain
,
2312 TALLOC_CTX
*mem_ctx
,
2313 const struct dom_sid
*user_sid
,
2314 uint32_t *pnum_sids
,
2315 struct dom_sid
**psids
)
2317 struct winbind_cache
*cache
= get_cache(domain
);
2318 struct cache_entry
*centry
= NULL
;
2320 uint32_t i
, num_sids
;
2321 struct dom_sid
*sids
;
2322 struct dom_sid_buf sid_string
;
2324 if (cache
->tdb
== NULL
) {
2325 return NT_STATUS_NOT_FOUND
;
2328 centry
= wcache_fetch(
2332 dom_sid_str_buf(user_sid
, &sid_string
));
2333 if (centry
== NULL
) {
2334 return NT_STATUS_NOT_FOUND
;
2337 /* If we have an access denied cache entry and a cached info3 in the
2338 samlogon cache then do a query. This will force the rpc back end
2339 to return the info3 data. */
2341 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)
2342 && netsamlogon_cache_have(user_sid
)) {
2343 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2345 domain
->last_status
= NT_STATUS_OK
;
2346 centry_free(centry
);
2347 return NT_STATUS_NOT_FOUND
;
2350 num_sids
= centry_uint32(centry
);
2351 sids
= talloc_array(mem_ctx
, struct dom_sid
, num_sids
);
2353 centry_free(centry
);
2354 return NT_STATUS_NO_MEMORY
;
2357 for (i
=0; i
<num_sids
; i
++) {
2358 centry_sid(centry
, &sids
[i
]);
2361 status
= centry
->status
;
2363 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2364 "status: %s\n", domain
->name
, nt_errstr(status
)));
2366 centry_free(centry
);
2368 *pnum_sids
= num_sids
;
2373 /* Lookup groups a user is a member of. */
2374 NTSTATUS
wb_cache_lookup_usergroups(struct winbindd_domain
*domain
,
2375 TALLOC_CTX
*mem_ctx
,
2376 const struct dom_sid
*user_sid
,
2377 uint32_t *num_groups
,
2378 struct dom_sid
**user_gids
)
2380 struct cache_entry
*centry
= NULL
;
2383 struct dom_sid_buf sid_string
;
2386 old_status
= domain
->online
;
2387 status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2388 num_groups
, user_gids
);
2389 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2394 (*user_gids
) = NULL
;
2396 /* Return status value returned by seq number check */
2398 if (!NT_STATUS_IS_OK(domain
->last_status
))
2399 return domain
->last_status
;
2401 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2404 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
2406 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2407 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2408 if (!domain
->internal
&& old_status
) {
2409 set_domain_offline(domain
);
2411 if (!domain
->internal
&&
2414 NTSTATUS cache_status
;
2415 cache_status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2416 num_groups
, user_gids
);
2417 return cache_status
;
2420 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
2424 refresh_sequence_number(domain
);
2425 if (!NT_STATUS_IS_OK(status
)) {
2428 centry
= centry_start(domain
, status
);
2432 centry_put_uint32(centry
, *num_groups
);
2433 for (i
=0; i
<(*num_groups
); i
++) {
2434 centry_put_sid(centry
, &(*user_gids
)[i
]);
2437 centry_end(centry
, "UG/%s", dom_sid_str_buf(user_sid
, &sid_string
));
2438 centry_free(centry
);
2444 static char *wcache_make_sidlist(TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2445 const struct dom_sid
*sids
)
2450 sidlist
= talloc_strdup(mem_ctx
, "");
2451 if (sidlist
== NULL
) {
2454 for (i
=0; i
<num_sids
; i
++) {
2455 struct dom_sid_buf tmp
;
2456 sidlist
= talloc_asprintf_append_buffer(
2459 dom_sid_str_buf(&sids
[i
], &tmp
));
2460 if (sidlist
== NULL
) {
2467 static NTSTATUS
wcache_lookup_useraliases(struct winbindd_domain
*domain
,
2468 TALLOC_CTX
*mem_ctx
,
2470 const struct dom_sid
*sids
,
2471 uint32_t *pnum_aliases
,
2472 uint32_t **paliases
)
2474 struct winbind_cache
*cache
= get_cache(domain
);
2475 struct cache_entry
*centry
= NULL
;
2476 uint32_t i
, num_aliases
;
2481 if (cache
->tdb
== NULL
) {
2482 return NT_STATUS_NOT_FOUND
;
2485 if (num_sids
== 0) {
2488 return NT_STATUS_OK
;
2491 /* We need to cache indexed by the whole list of SIDs, the aliases
2492 * resulting might come from any of the SIDs. */
2494 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2495 if (sidlist
== NULL
) {
2496 return NT_STATUS_NO_MEMORY
;
2499 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2500 TALLOC_FREE(sidlist
);
2501 if (centry
== NULL
) {
2502 return NT_STATUS_NOT_FOUND
;
2505 num_aliases
= centry_uint32(centry
);
2506 aliases
= talloc_array(mem_ctx
, uint32_t, num_aliases
);
2507 if (aliases
== NULL
) {
2508 centry_free(centry
);
2509 return NT_STATUS_NO_MEMORY
;
2512 for (i
=0; i
<num_aliases
; i
++) {
2513 aliases
[i
] = centry_uint32(centry
);
2516 status
= centry
->status
;
2518 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2519 "status %s\n", domain
->name
, nt_errstr(status
)));
2521 centry_free(centry
);
2523 *pnum_aliases
= num_aliases
;
2524 *paliases
= aliases
;
2529 NTSTATUS
wb_cache_lookup_useraliases(struct winbindd_domain
*domain
,
2530 TALLOC_CTX
*mem_ctx
,
2532 const struct dom_sid
*sids
,
2533 uint32_t *num_aliases
,
2534 uint32_t **alias_rids
)
2536 struct cache_entry
*centry
= NULL
;
2542 old_status
= domain
->online
;
2543 status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
2544 num_aliases
, alias_rids
);
2545 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2550 (*alias_rids
) = NULL
;
2552 if (!NT_STATUS_IS_OK(domain
->last_status
))
2553 return domain
->last_status
;
2555 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2556 "for domain %s\n", domain
->name
));
2558 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2559 if (sidlist
== NULL
) {
2560 return NT_STATUS_NO_MEMORY
;
2563 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2565 num_aliases
, alias_rids
);
2567 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2568 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2569 if (!domain
->internal
&& old_status
) {
2570 set_domain_offline(domain
);
2572 if (!domain
->internal
&&
2575 NTSTATUS cache_status
;
2576 cache_status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
,
2577 sids
, num_aliases
, alias_rids
);
2578 return cache_status
;
2582 refresh_sequence_number(domain
);
2583 if (!NT_STATUS_IS_OK(status
)) {
2586 centry
= centry_start(domain
, status
);
2589 centry_put_uint32(centry
, *num_aliases
);
2590 for (i
=0; i
<(*num_aliases
); i
++)
2591 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2592 centry_end(centry
, "UA%s", sidlist
);
2593 centry_free(centry
);
2599 static NTSTATUS
wcache_lookup_groupmem(struct winbindd_domain
*domain
,
2600 TALLOC_CTX
*mem_ctx
,
2601 const struct dom_sid
*group_sid
,
2602 uint32_t *num_names
,
2603 struct dom_sid
**sid_mem
, char ***names
,
2604 uint32_t **name_types
)
2606 struct winbind_cache
*cache
= get_cache(domain
);
2607 struct cache_entry
*centry
= NULL
;
2610 struct dom_sid_buf sid_string
;
2612 if (cache
->tdb
== NULL
) {
2613 return NT_STATUS_NOT_FOUND
;
2616 centry
= wcache_fetch(
2620 dom_sid_str_buf(group_sid
, &sid_string
));
2621 if (centry
== NULL
) {
2622 return NT_STATUS_NOT_FOUND
;
2629 *num_names
= centry_uint32(centry
);
2630 if (*num_names
== 0) {
2631 centry_free(centry
);
2632 return NT_STATUS_OK
;
2635 *sid_mem
= talloc_array(mem_ctx
, struct dom_sid
, *num_names
);
2636 *names
= talloc_array(mem_ctx
, char *, *num_names
);
2637 *name_types
= talloc_array(mem_ctx
, uint32_t, *num_names
);
2639 if ((*sid_mem
== NULL
) || (*names
== NULL
) || (*name_types
== NULL
)) {
2640 TALLOC_FREE(*sid_mem
);
2641 TALLOC_FREE(*names
);
2642 TALLOC_FREE(*name_types
);
2643 centry_free(centry
);
2644 return NT_STATUS_NO_MEMORY
;
2647 for (i
=0; i
<(*num_names
); i
++) {
2648 centry_sid(centry
, &(*sid_mem
)[i
]);
2649 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2650 (*name_types
)[i
] = centry_uint32(centry
);
2653 status
= centry
->status
;
2655 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2656 "status: %s\n", domain
->name
, nt_errstr(status
)));
2658 centry_free(centry
);
2662 NTSTATUS
wb_cache_lookup_groupmem(struct winbindd_domain
*domain
,
2663 TALLOC_CTX
*mem_ctx
,
2664 const struct dom_sid
*group_sid
,
2665 enum lsa_SidType type
,
2666 uint32_t *num_names
,
2667 struct dom_sid
**sid_mem
,
2669 uint32_t **name_types
)
2671 struct cache_entry
*centry
= NULL
;
2674 struct dom_sid_buf sid_string
;
2677 old_status
= domain
->online
;
2678 status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2679 sid_mem
, names
, name_types
);
2680 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2687 (*name_types
) = NULL
;
2689 /* Return status value returned by seq number check */
2691 if (!NT_STATUS_IS_OK(domain
->last_status
))
2692 return domain
->last_status
;
2694 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2697 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
,
2699 sid_mem
, names
, name_types
);
2701 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2702 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2703 if (!domain
->internal
&& old_status
) {
2704 set_domain_offline(domain
);
2706 if (!domain
->internal
&&
2709 NTSTATUS cache_status
;
2710 cache_status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
,
2711 num_names
, sid_mem
, names
,
2713 return cache_status
;
2717 refresh_sequence_number(domain
);
2718 if (!NT_STATUS_IS_OK(status
)) {
2721 centry
= centry_start(domain
, status
);
2724 centry_put_uint32(centry
, *num_names
);
2725 for (i
=0; i
<(*num_names
); i
++) {
2726 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2727 centry_put_string(centry
, (*names
)[i
]);
2728 centry_put_uint32(centry
, (*name_types
)[i
]);
2732 dom_sid_str_buf(group_sid
, &sid_string
));
2733 centry_free(centry
);
2739 /* find the sequence number for a domain */
2740 NTSTATUS
wb_cache_sequence_number(struct winbindd_domain
*domain
,
2743 refresh_sequence_number(domain
);
2745 *seq
= domain
->sequence_number
;
2747 return NT_STATUS_OK
;
2750 /* enumerate trusted domains
2751 * (we need to have the list of trustdoms in the cache when we go offline) -
2753 NTSTATUS
wb_cache_trusted_domains(struct winbindd_domain
*domain
,
2754 TALLOC_CTX
*mem_ctx
,
2755 struct netr_DomainTrustList
*trusts
)
2758 struct winbind_cache
*cache
;
2759 struct winbindd_tdc_domain
*dom_list
= NULL
;
2760 size_t num_domains
= 0;
2761 bool retval
= false;
2765 old_status
= domain
->online
;
2767 trusts
->array
= NULL
;
2769 cache
= get_cache(domain
);
2770 if (!cache
|| !cache
->tdb
) {
2774 if (domain
->online
) {
2778 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2779 if (!retval
|| !num_domains
|| !dom_list
) {
2780 TALLOC_FREE(dom_list
);
2785 trusts
->array
= talloc_zero_array(mem_ctx
, struct netr_DomainTrust
, num_domains
);
2786 if (!trusts
->array
) {
2787 TALLOC_FREE(dom_list
);
2788 return NT_STATUS_NO_MEMORY
;
2791 for (i
= 0; i
< num_domains
; i
++) {
2792 struct netr_DomainTrust
*trust
;
2793 struct dom_sid
*sid
;
2794 struct winbindd_domain
*dom
;
2796 dom
= find_domain_from_name_noinit(dom_list
[i
].domain_name
);
2797 if (dom
&& dom
->internal
) {
2801 trust
= &trusts
->array
[trusts
->count
];
2802 trust
->netbios_name
= talloc_strdup(trusts
->array
, dom_list
[i
].domain_name
);
2803 trust
->dns_name
= talloc_strdup(trusts
->array
, dom_list
[i
].dns_name
);
2804 sid
= talloc(trusts
->array
, struct dom_sid
);
2805 if (!trust
->netbios_name
|| !trust
->dns_name
||
2807 TALLOC_FREE(dom_list
);
2808 TALLOC_FREE(trusts
->array
);
2809 return NT_STATUS_NO_MEMORY
;
2812 trust
->trust_flags
= dom_list
[i
].trust_flags
;
2813 trust
->trust_attributes
= dom_list
[i
].trust_attribs
;
2814 trust
->trust_type
= dom_list
[i
].trust_type
;
2815 sid_copy(sid
, &dom_list
[i
].sid
);
2820 TALLOC_FREE(dom_list
);
2821 return NT_STATUS_OK
;
2824 /* Return status value returned by seq number check */
2826 if (!NT_STATUS_IS_OK(domain
->last_status
))
2827 return domain
->last_status
;
2829 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2832 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, trusts
);
2834 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2835 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2836 if (!domain
->internal
&& old_status
) {
2837 set_domain_offline(domain
);
2839 if (!domain
->internal
&&
2842 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2843 if (retval
&& num_domains
&& dom_list
) {
2844 TALLOC_FREE(trusts
->array
);
2846 goto do_fetch_cache
;
2850 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2851 * so that the generic centry handling still applies correctly -
2854 if (!NT_STATUS_IS_ERR(status
)) {
2855 status
= NT_STATUS_OK
;
2860 /* get lockout policy */
2861 NTSTATUS
wb_cache_lockout_policy(struct winbindd_domain
*domain
,
2862 TALLOC_CTX
*mem_ctx
,
2863 struct samr_DomInfo12
*policy
)
2865 struct winbind_cache
*cache
= get_cache(domain
);
2866 struct cache_entry
*centry
= NULL
;
2870 old_status
= domain
->online
;
2874 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2880 policy
->lockout_duration
= centry_nttime(centry
);
2881 policy
->lockout_window
= centry_nttime(centry
);
2882 policy
->lockout_threshold
= centry_uint16(centry
);
2884 status
= centry
->status
;
2886 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2887 domain
->name
, nt_errstr(status
) ));
2889 centry_free(centry
);
2893 ZERO_STRUCTP(policy
);
2895 /* Return status value returned by seq number check */
2897 if (!NT_STATUS_IS_OK(domain
->last_status
))
2898 return domain
->last_status
;
2900 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2903 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2905 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2906 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2907 if (!domain
->internal
&& old_status
) {
2908 set_domain_offline(domain
);
2911 !domain
->internal
&&
2914 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2916 goto do_fetch_cache
;
2921 refresh_sequence_number(domain
);
2922 if (!NT_STATUS_IS_OK(status
)) {
2925 wcache_save_lockout_policy(domain
, status
, policy
);
2930 /* get password policy */
2931 NTSTATUS
wb_cache_password_policy(struct winbindd_domain
*domain
,
2932 TALLOC_CTX
*mem_ctx
,
2933 struct samr_DomInfo1
*policy
)
2935 struct winbind_cache
*cache
= get_cache(domain
);
2936 struct cache_entry
*centry
= NULL
;
2940 old_status
= domain
->online
;
2944 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2950 policy
->min_password_length
= centry_uint16(centry
);
2951 policy
->password_history_length
= centry_uint16(centry
);
2952 policy
->password_properties
= centry_uint32(centry
);
2953 policy
->max_password_age
= centry_nttime(centry
);
2954 policy
->min_password_age
= centry_nttime(centry
);
2956 status
= centry
->status
;
2958 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2959 domain
->name
, nt_errstr(status
) ));
2961 centry_free(centry
);
2965 ZERO_STRUCTP(policy
);
2967 /* Return status value returned by seq number check */
2969 if (!NT_STATUS_IS_OK(domain
->last_status
))
2970 return domain
->last_status
;
2972 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2975 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
2977 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2978 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2979 if (!domain
->internal
&& old_status
) {
2980 set_domain_offline(domain
);
2983 !domain
->internal
&&
2986 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2988 goto do_fetch_cache
;
2993 refresh_sequence_number(domain
);
2994 if (!NT_STATUS_IS_OK(status
)) {
2997 wcache_save_password_policy(domain
, status
, policy
);
3003 /* Invalidate cached user and group lists coherently */
3005 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3008 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
3009 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
3010 tdb_delete(the_tdb
, kbuf
);
3015 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3017 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
3018 const struct dom_sid
*sid
)
3021 struct dom_sid_buf sid_string
;
3022 struct winbind_cache
*cache
;
3024 /* don't clear cached U/SID and UG/SID entries when we want to logon
3027 if (lp_winbind_offline_logon()) {
3034 cache
= get_cache(domain
);
3040 /* Clear U/SID cache entry */
3041 fstr_sprintf(key_str
, "U/%s", dom_sid_str_buf(sid
, &sid_string
));
3042 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3043 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3045 /* Clear UG/SID cache entry */
3046 fstr_sprintf(key_str
, "UG/%s", dom_sid_str_buf(sid
, &sid_string
));
3047 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3048 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3050 /* Samba/winbindd never needs this. */
3051 netsamlogon_clear_cached_user(sid
);
3054 bool wcache_invalidate_cache(void)
3056 struct winbindd_domain
*domain
;
3058 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3059 struct winbind_cache
*cache
= get_cache(domain
);
3061 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3062 "entries for %s\n", domain
->name
));
3065 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3074 bool wcache_invalidate_cache_noinit(void)
3076 struct winbindd_domain
*domain
;
3078 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3079 struct winbind_cache
*cache
;
3081 /* Skip uninitialized domains. */
3082 if (!domain
->initialized
&& !domain
->internal
) {
3086 cache
= get_cache(domain
);
3088 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3089 "entries for %s\n", domain
->name
));
3092 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3094 * Flushing cache has nothing to with domains.
3095 * return here if we successfully flushed once.
3096 * To avoid unnecessary traversing the cache.
3107 static bool init_wcache(void)
3111 if (wcache
== NULL
) {
3112 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
3113 ZERO_STRUCTP(wcache
);
3116 if (wcache
->tdb
!= NULL
)
3119 db_path
= wcache_path();
3120 if (db_path
== NULL
) {
3124 /* when working offline we must not clear the cache on restart */
3125 wcache
->tdb
= tdb_open_log(db_path
,
3126 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3127 TDB_INCOMPATIBLE_HASH
|
3128 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3129 O_RDWR
|O_CREAT
, 0600);
3130 TALLOC_FREE(db_path
);
3131 if (wcache
->tdb
== NULL
) {
3132 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3139 /************************************************************************
3140 This is called by the parent to initialize the cache file.
3141 We don't need sophisticated locking here as we know we're the
3143 ************************************************************************/
3145 bool initialize_winbindd_cache(void)
3147 bool cache_bad
= true;
3150 if (!init_wcache()) {
3151 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3155 /* Check version number. */
3156 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
3157 vers
== WINBINDD_CACHE_VERSION
) {
3164 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3165 "and re-creating with version number %d\n",
3166 WINBINDD_CACHE_VERSION
));
3168 tdb_close(wcache
->tdb
);
3171 db_path
= wcache_path();
3172 if (db_path
== NULL
) {
3176 if (unlink(db_path
) == -1) {
3177 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3180 TALLOC_FREE(db_path
);
3183 TALLOC_FREE(db_path
);
3184 if (!init_wcache()) {
3185 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3186 "init_wcache failed.\n"));
3190 /* Write the version. */
3191 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
3192 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3193 tdb_errorstr(wcache
->tdb
) ));
3198 tdb_close(wcache
->tdb
);
3203 void close_winbindd_cache(void)
3209 tdb_close(wcache
->tdb
);
3214 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*sid
,
3215 char **domain_name
, char **name
,
3216 enum lsa_SidType
*type
)
3218 struct winbindd_domain
*domain
;
3221 domain
= find_lookup_domain_from_sid(sid
);
3222 if (domain
== NULL
) {
3225 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
3227 return NT_STATUS_IS_OK(status
);
3230 bool lookup_cached_name(const char *namespace,
3231 const char *domain_name
,
3233 struct dom_sid
*sid
,
3234 enum lsa_SidType
*type
)
3236 struct winbindd_domain
*domain
;
3238 bool original_online_state
;
3240 domain
= find_lookup_domain_from_name(namespace);
3241 if (domain
== NULL
) {
3245 /* If we are doing a cached logon, temporarily set the domain
3246 offline so the cache won't expire the entry */
3248 original_online_state
= domain
->online
;
3249 domain
->online
= false;
3250 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
3251 domain
->online
= original_online_state
;
3253 return NT_STATUS_IS_OK(status
);
3257 * Cache a name to sid without checking the sequence number.
3258 * Used when caching from a trusted PAC.
3261 void cache_name2sid_trusted(struct winbindd_domain
*domain
,
3262 const char *domain_name
,
3264 enum lsa_SidType type
,
3265 const struct dom_sid
*sid
)
3268 * Ensure we store the mapping with the
3269 * existing sequence number from the cache.
3272 (void)fetch_cache_seqnum(domain
, time(NULL
));
3273 wcache_save_name_to_sid(domain
,
3281 void cache_name2sid(struct winbindd_domain
*domain
,
3282 const char *domain_name
, const char *name
,
3283 enum lsa_SidType type
, const struct dom_sid
*sid
)
3285 refresh_sequence_number(domain
);
3286 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
3291 * The original idea that this cache only contains centries has
3292 * been blurred - now other stuff gets put in here. Ensure we
3293 * ignore these things on cleanup.
3296 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
3297 TDB_DATA dbuf
, void *state
)
3299 struct cache_entry
*centry
;
3301 if (is_non_centry_key(kbuf
)) {
3305 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
3310 if (!NT_STATUS_IS_OK(centry
->status
)) {
3311 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
3312 tdb_delete(the_tdb
, kbuf
);
3315 centry_free(centry
);
3319 /* flush the cache */
3320 static void wcache_flush_cache(void)
3327 tdb_close(wcache
->tdb
);
3330 if (!winbindd_use_cache()) {
3334 db_path
= wcache_path();
3335 if (db_path
== NULL
) {
3339 /* when working offline we must not clear the cache on restart */
3340 wcache
->tdb
= tdb_open_log(db_path
,
3341 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3342 TDB_INCOMPATIBLE_HASH
|
3343 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3344 O_RDWR
|O_CREAT
, 0600);
3345 TALLOC_FREE(db_path
);
3347 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3351 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
3353 DEBUG(10,("wcache_flush_cache success\n"));
3356 /* Count cached creds */
3358 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3361 int *cred_count
= (int*)state
;
3363 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3369 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
3371 struct winbind_cache
*cache
= get_cache(domain
);
3376 return NT_STATUS_INTERNAL_DB_ERROR
;
3379 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
3381 return NT_STATUS_OK
;
3385 struct cred_list
*prev
, *next
;
3390 static struct cred_list
*wcache_cred_list
;
3392 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3395 struct cred_list
*cred
;
3397 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3399 cred
= SMB_MALLOC_P(struct cred_list
);
3401 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3407 /* save a copy of the key */
3409 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
3410 DLIST_ADD(wcache_cred_list
, cred
);
3416 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
3418 struct winbind_cache
*cache
= get_cache(domain
);
3421 struct cred_list
*cred
, *next
, *oldest
= NULL
;
3424 return NT_STATUS_INTERNAL_DB_ERROR
;
3427 /* we possibly already have an entry */
3428 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
3431 struct dom_sid_buf tmp
;
3433 DEBUG(11,("we already have an entry, deleting that\n"));
3435 fstr_sprintf(key_str
, "CRED/%s", dom_sid_str_buf(sid
, &tmp
));
3437 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3439 return NT_STATUS_OK
;
3442 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
3444 return NT_STATUS_OK
;
3445 } else if ((ret
< 0) || (wcache_cred_list
== NULL
)) {
3446 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3449 ZERO_STRUCTP(oldest
);
3451 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
3456 data
= tdb_fetch(cache
->tdb
, string_tdb_data(cred
->name
));
3458 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3460 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3464 t
= IVAL(data
.dptr
, 0);
3465 SAFE_FREE(data
.dptr
);
3468 oldest
= SMB_MALLOC_P(struct cred_list
);
3469 if (oldest
== NULL
) {
3470 status
= NT_STATUS_NO_MEMORY
;
3474 fstrcpy(oldest
->name
, cred
->name
);
3475 oldest
->created
= t
;
3479 if (t
< oldest
->created
) {
3480 fstrcpy(oldest
->name
, cred
->name
);
3481 oldest
->created
= t
;
3485 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3486 status
= NT_STATUS_OK
;
3488 status
= NT_STATUS_UNSUCCESSFUL
;
3491 for (cred
= wcache_cred_list
; cred
; cred
= next
) {
3493 DLIST_REMOVE(wcache_cred_list
, cred
);
3501 /* Change the global online/offline state. */
3502 bool set_global_winbindd_state_offline(void)
3506 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3508 /* Only go offline if someone has created
3509 the key "WINBINDD_OFFLINE" in the cache tdb. */
3511 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3512 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3516 if (!lp_winbind_offline_logon()) {
3517 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3521 if (global_winbindd_offline_state
) {
3522 /* Already offline. */
3526 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
3528 if (!data
.dptr
|| data
.dsize
!= 4) {
3529 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3530 SAFE_FREE(data
.dptr
);
3533 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3534 global_winbindd_offline_state
= true;
3535 SAFE_FREE(data
.dptr
);
3540 void set_global_winbindd_state_online(void)
3542 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3544 if (!lp_winbind_offline_logon()) {
3545 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3549 if (!global_winbindd_offline_state
) {
3550 /* Already online. */
3553 global_winbindd_offline_state
= false;
3559 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3560 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3563 bool get_global_winbindd_state_offline(void)
3565 return global_winbindd_offline_state
;
3568 /***********************************************************************
3569 Validate functions for all possible cache tdb keys.
3570 ***********************************************************************/
3572 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3573 struct tdb_validation_status
*state
)
3575 struct cache_entry
*centry
;
3577 centry
= SMB_XMALLOC_P(struct cache_entry
);
3578 centry
->data
= (unsigned char *)smb_memdup(data
.dptr
, data
.dsize
);
3579 if (!centry
->data
) {
3583 centry
->len
= data
.dsize
;
3586 if (centry
->len
< 16) {
3587 /* huh? corrupt cache? */
3588 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3589 "(len < 16) ?\n", kstr
));
3590 centry_free(centry
);
3591 state
->bad_entry
= true;
3592 state
->success
= false;
3596 centry
->status
= NT_STATUS(centry_uint32(centry
));
3597 centry
->sequence_number
= centry_uint32(centry
);
3598 centry
->timeout
= centry_uint64_t(centry
);
3602 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3603 struct tdb_validation_status
*state
)
3605 if (dbuf
.dsize
!= 8) {
3606 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3607 keystr
, (unsigned int)dbuf
.dsize
));
3608 state
->bad_entry
= true;
3614 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3615 struct tdb_validation_status
*state
)
3617 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3624 (void)centry_string(centry
, mem_ctx
);
3625 (void)centry_string(centry
, mem_ctx
);
3626 (void)centry_string(centry
, mem_ctx
);
3627 (void)centry_string(centry
, mem_ctx
);
3628 (void)centry_string(centry
, mem_ctx
);
3629 (void)centry_uint32(centry
);
3630 (void)centry_uint32(centry
);
3631 (void)centry_string(centry
, mem_ctx
);
3632 (void)centry_sid(centry
, &sid
);
3633 (void)centry_sid(centry
, &sid
);
3635 centry_free(centry
);
3637 if (!(state
->success
)) {
3640 DEBUG(10,("validate_u: %s ok\n", keystr
));
3644 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3645 struct tdb_validation_status
*state
)
3647 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3653 (void)centry_nttime(centry
);
3654 (void)centry_nttime(centry
);
3655 (void)centry_uint16(centry
);
3657 centry_free(centry
);
3659 if (!(state
->success
)) {
3662 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3666 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3667 struct tdb_validation_status
*state
)
3669 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3675 (void)centry_uint16(centry
);
3676 (void)centry_uint16(centry
);
3677 (void)centry_uint32(centry
);
3678 (void)centry_nttime(centry
);
3679 (void)centry_nttime(centry
);
3681 centry_free(centry
);
3683 if (!(state
->success
)) {
3686 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3690 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3691 struct tdb_validation_status
*state
)
3693 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3699 (void)centry_time(centry
);
3700 (void)centry_hash16(centry
, mem_ctx
);
3702 /* We only have 17 bytes more data in the salted cred case. */
3703 if (centry
->len
- centry
->ofs
== 17) {
3704 (void)centry_hash16(centry
, mem_ctx
);
3707 centry_free(centry
);
3709 if (!(state
->success
)) {
3712 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3716 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3717 struct tdb_validation_status
*state
)
3719 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3720 int32_t num_entries
, i
;
3726 num_entries
= (int32_t)centry_uint32(centry
);
3728 for (i
=0; i
< num_entries
; i
++) {
3729 (void)centry_uint32(centry
);
3732 centry_free(centry
);
3734 if (!(state
->success
)) {
3737 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3741 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3742 struct tdb_validation_status
*state
)
3744 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3745 int32_t num_entries
, i
;
3751 num_entries
= centry_uint32(centry
);
3753 for (i
=0; i
< num_entries
; i
++) {
3754 (void)centry_string(centry
, mem_ctx
);
3755 (void)centry_string(centry
, mem_ctx
);
3756 (void)centry_uint32(centry
);
3759 centry_free(centry
);
3761 if (!(state
->success
)) {
3764 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3768 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3769 struct tdb_validation_status
*state
)
3771 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3772 int32_t num_groups
, i
;
3778 num_groups
= centry_uint32(centry
);
3780 for (i
=0; i
< num_groups
; i
++) {
3782 centry_sid(centry
, &sid
);
3785 centry_free(centry
);
3787 if (!(state
->success
)) {
3790 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3794 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3795 struct tdb_validation_status
*state
)
3797 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3798 int32_t num_aliases
, i
;
3804 num_aliases
= centry_uint32(centry
);
3806 for (i
=0; i
< num_aliases
; i
++) {
3807 (void)centry_uint32(centry
);
3810 centry_free(centry
);
3812 if (!(state
->success
)) {
3815 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3819 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3820 struct tdb_validation_status
*state
)
3822 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3823 int32_t num_names
, i
;
3829 num_names
= centry_uint32(centry
);
3831 for (i
=0; i
< num_names
; i
++) {
3833 centry_sid(centry
, &sid
);
3834 (void)centry_string(centry
, mem_ctx
);
3835 (void)centry_uint32(centry
);
3838 centry_free(centry
);
3840 if (!(state
->success
)) {
3843 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3847 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3848 struct tdb_validation_status
*state
)
3850 /* Can't say anything about this other than must be nonzero. */
3851 if (dbuf
.dsize
== 0) {
3852 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3854 state
->bad_entry
= true;
3855 state
->success
= false;
3859 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3863 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3864 struct tdb_validation_status
*state
)
3866 /* Can't say anything about this other than must be nonzero. */
3867 if (dbuf
.dsize
== 0) {
3868 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3870 state
->bad_entry
= true;
3871 state
->success
= false;
3875 DEBUG(10,("validate_de: %s ok\n", keystr
));
3879 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3881 struct tdb_validation_status
*state
)
3883 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3889 (void)centry_string( centry
, mem_ctx
);
3891 centry_free(centry
);
3893 if (!(state
->success
)) {
3896 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3900 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3902 struct tdb_validation_status
*state
)
3904 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3910 (void)centry_string( centry
, mem_ctx
);
3912 centry_free(centry
);
3914 if (!(state
->success
)) {
3917 DBG_DEBUG("%s ok\n", keystr
);
3921 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3923 struct tdb_validation_status
*state
)
3925 if (dbuf
.dsize
== 0) {
3926 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3927 "key %s (len ==0) ?\n", keystr
));
3928 state
->bad_entry
= true;
3929 state
->success
= false;
3933 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3934 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3938 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3939 struct tdb_validation_status
*state
)
3941 if (dbuf
.dsize
!= 4) {
3942 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3943 keystr
, (unsigned int)dbuf
.dsize
));
3944 state
->bad_entry
= true;
3945 state
->success
= false;
3948 DEBUG(10,("validate_offline: %s ok\n", keystr
));
3952 static int validate_ndr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3953 struct tdb_validation_status
*state
)
3956 * Ignore validation for now. The proper way to do this is with a
3957 * checksum. Just pure parsing does not really catch much.
3962 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3963 struct tdb_validation_status
*state
)
3965 if (dbuf
.dsize
!= 4) {
3966 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3967 "key %s (len %u != 4) ?\n",
3968 keystr
, (unsigned int)dbuf
.dsize
));
3969 state
->bad_entry
= true;
3970 state
->success
= false;
3974 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
3978 /***********************************************************************
3979 A list of all possible cache tdb keys with associated validation
3981 ***********************************************************************/
3983 struct key_val_struct
{
3984 const char *keyname
;
3985 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
3987 {"SEQNUM/", validate_seqnum
},
3989 {"LOC_POL/", validate_loc_pol
},
3990 {"PWD_POL/", validate_pwd_pol
},
3991 {"CRED/", validate_cred
},
3992 {"UL/", validate_ul
},
3993 {"GL/", validate_gl
},
3994 {"UG/", validate_ug
},
3995 {"UA", validate_ua
},
3996 {"GM/", validate_gm
},
3997 {"DR/", validate_dr
},
3998 {"DE/", validate_de
},
3999 {"TRUSTDOMCACHE/", validate_trustdomcache
},
4000 {"NSS/NA/", validate_nss_na
},
4001 {"NSS/AN/", validate_nss_an
},
4002 {"WINBINDD_OFFLINE", validate_offline
},
4003 {"NDR/", validate_ndr
},
4004 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
4008 /***********************************************************************
4009 Function to look at every entry in the tdb and validate it as far as
4011 ***********************************************************************/
4013 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
4016 unsigned int max_key_len
= 1024;
4017 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
4019 /* Paranoia check. */
4020 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0 ||
4021 strncmp("NDR/", (const char *)kbuf
.dptr
, 4) == 0) {
4022 max_key_len
= 1024 * 1024;
4024 if (kbuf
.dsize
> max_key_len
) {
4025 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4027 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
4031 for (i
= 0; key_val
[i
].keyname
; i
++) {
4032 size_t namelen
= strlen(key_val
[i
].keyname
);
4033 if (kbuf
.dsize
>= namelen
&& (
4034 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
4035 TALLOC_CTX
*mem_ctx
;
4039 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
4043 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
4044 keystr
[kbuf
.dsize
] = '\0';
4046 mem_ctx
= talloc_init("validate_ctx");
4052 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
4056 talloc_destroy(mem_ctx
);
4061 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4062 dump_data(0, (uint8_t *)kbuf
.dptr
, kbuf
.dsize
);
4063 DEBUG(0,("data :\n"));
4064 dump_data(0, (uint8_t *)dbuf
.dptr
, dbuf
.dsize
);
4065 v_state
->unknown_key
= true;
4066 v_state
->success
= false;
4067 return 1; /* terminate. */
4070 static void validate_panic(const char *const why
)
4072 DEBUG(0,("validating cache: would panic %s\n", why
));
4073 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4077 static int wbcache_update_centry_fn(TDB_CONTEXT
*tdb
,
4085 if (is_non_centry_key(key
)) {
4089 if (data
.dptr
== NULL
|| data
.dsize
== 0) {
4090 if (tdb_delete(tdb
, key
) < 0) {
4091 DEBUG(0, ("tdb_delete for [%s] failed!\n",
4097 /* add timeout to blob (uint64_t) */
4098 blob
.dsize
= data
.dsize
+ 8;
4100 blob
.dptr
= SMB_XMALLOC_ARRAY(uint8_t, blob
.dsize
);
4101 if (blob
.dptr
== NULL
) {
4104 memset(blob
.dptr
, 0, blob
.dsize
);
4106 /* copy status and seqnum */
4107 memcpy(blob
.dptr
, data
.dptr
, 8);
4110 ctimeout
= lp_winbind_cache_time() + time(NULL
);
4111 SBVAL(blob
.dptr
, 8, ctimeout
);
4114 memcpy(blob
.dptr
+ 16, data
.dptr
+ 8, data
.dsize
- 8);
4116 if (tdb_store(tdb
, key
, blob
, TDB_REPLACE
) < 0) {
4117 DEBUG(0, ("tdb_store to update [%s] failed!\n",
4119 SAFE_FREE(blob
.dptr
);
4123 SAFE_FREE(blob
.dptr
);
4127 static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT
*tdb
)
4131 DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
4133 rc
= tdb_traverse(tdb
, wbcache_update_centry_fn
, NULL
);
4141 /***********************************************************************
4142 Try and validate every entry in the winbindd cache. If we fail here,
4143 delete the cache tdb and return non-zero.
4144 ***********************************************************************/
4146 int winbindd_validate_cache(void)
4149 char *tdb_path
= NULL
;
4150 TDB_CONTEXT
*tdb
= NULL
;
4154 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4155 smb_panic_fn
= validate_panic
;
4157 tdb_path
= wcache_path();
4158 if (tdb_path
== NULL
) {
4162 tdb
= tdb_open_log(tdb_path
,
4163 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
4164 TDB_INCOMPATIBLE_HASH
|
4165 ( lp_winbind_offline_logon()
4167 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
4171 DEBUG(0, ("winbindd_validate_cache: "
4172 "error opening/initializing tdb\n"));
4176 /* Version check and upgrade code. */
4177 if (!tdb_fetch_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers_id
)) {
4178 DEBUG(10, ("Fresh database\n"));
4179 tdb_store_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
);
4180 vers_id
= WINBINDD_CACHE_VERSION
;
4183 if (vers_id
!= WINBINDD_CACHE_VERSION
) {
4184 if (vers_id
== WINBINDD_CACHE_VER1
) {
4185 ok
= wbcache_upgrade_v1_to_v2(tdb
);
4187 DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
4192 tdb_store_uint32(tdb
,
4193 WINBINDD_CACHE_VERSION_KEYSTR
,
4194 WINBINDD_CACHE_VERSION
);
4195 vers_id
= WINBINDD_CACHE_VER2
;
4201 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
4204 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4205 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
4210 TALLOC_FREE(tdb_path
);
4211 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4212 smb_panic_fn
= smb_panic
;
4216 /***********************************************************************
4217 Try and validate every entry in the winbindd cache.
4218 ***********************************************************************/
4220 int winbindd_validate_cache_nobackup(void)
4225 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4226 smb_panic_fn
= validate_panic
;
4228 tdb_path
= wcache_path();
4229 if (tdb_path
== NULL
) {
4230 goto err_panic_restore
;
4233 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
4234 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
4236 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
4240 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4244 TALLOC_FREE(tdb_path
);
4246 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4248 smb_panic_fn
= smb_panic
;
4252 bool winbindd_cache_validate_and_initialize(void)
4254 close_winbindd_cache();
4256 if (lp_winbind_offline_logon()) {
4257 if (winbindd_validate_cache() < 0) {
4258 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4259 "could be restored.\n"));
4263 return initialize_winbindd_cache();
4266 /*********************************************************************
4267 ********************************************************************/
4269 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
4270 struct winbindd_tdc_domain
**domains
,
4271 size_t *num_domains
)
4273 struct winbindd_tdc_domain
*list
= NULL
;
4275 bool set_only
= false;
4277 /* don't allow duplicates */
4282 for ( i
=0; i
< (*num_domains
); i
++ ) {
4283 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
4284 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4295 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, 1 );
4298 list
= talloc_realloc( *domains
, *domains
,
4299 struct winbindd_tdc_domain
,
4304 ZERO_STRUCT( list
[idx
] );
4310 list
[idx
].domain_name
= talloc_strdup(list
, new_dom
->name
);
4311 if (list
[idx
].domain_name
== NULL
) {
4314 if (new_dom
->alt_name
!= NULL
) {
4315 list
[idx
].dns_name
= talloc_strdup(list
, new_dom
->alt_name
);
4316 if (list
[idx
].dns_name
== NULL
) {
4321 if ( !is_null_sid( &new_dom
->sid
) ) {
4322 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
4324 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
4327 if ( new_dom
->domain_flags
!= 0x0 )
4328 list
[idx
].trust_flags
= new_dom
->domain_flags
;
4330 if ( new_dom
->domain_type
!= 0x0 )
4331 list
[idx
].trust_type
= new_dom
->domain_type
;
4333 if ( new_dom
->domain_trust_attribs
!= 0x0 )
4334 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
4338 *num_domains
= idx
+ 1;
4344 /*********************************************************************
4345 ********************************************************************/
4347 static TDB_DATA
make_tdc_key( const char *domain_name
)
4349 char *keystr
= NULL
;
4350 TDB_DATA key
= { NULL
, 0 };
4352 if ( !domain_name
) {
4353 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4357 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
4360 key
= string_term_tdb_data(keystr
);
4365 /*********************************************************************
4366 ********************************************************************/
4368 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
4370 unsigned char **buf
)
4372 unsigned char *buffer
= NULL
;
4377 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4385 /* Store the number of array items first */
4386 len
+= tdb_pack( buffer
? buffer
+len
: NULL
,
4387 buffer
? buflen
-len
: 0, "d",
4390 /* now pack each domain trust record */
4391 for ( i
=0; i
<num_domains
; i
++ ) {
4393 struct dom_sid_buf tmp
;
4396 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4397 domains
[i
].domain_name
,
4398 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
4401 len
+= tdb_pack( buffer
? buffer
+len
: NULL
,
4402 buffer
? buflen
-len
: 0, "fffddd",
4403 domains
[i
].domain_name
,
4404 domains
[i
].dns_name
? domains
[i
].dns_name
: "",
4405 dom_sid_str_buf(&domains
[i
].sid
, &tmp
),
4406 domains
[i
].trust_flags
,
4407 domains
[i
].trust_attribs
,
4408 domains
[i
].trust_type
);
4411 if ( buflen
< len
) {
4413 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
4414 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4428 /*********************************************************************
4429 ********************************************************************/
4431 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
4432 struct winbindd_tdc_domain
**domains
)
4434 fstring domain_name
, dns_name
, sid_string
;
4435 uint32_t type
, attribs
, flags
;
4439 struct winbindd_tdc_domain
*list
= NULL
;
4441 /* get the number of domains */
4442 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
4444 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4448 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, num_domains
);
4450 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4454 for ( i
=0; i
<num_domains
; i
++ ) {
4457 this_len
= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
4465 if ( this_len
== -1 ) {
4466 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4467 TALLOC_FREE( list
);
4472 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4473 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4474 domain_name
, dns_name
, sid_string
,
4475 flags
, attribs
, type
));
4477 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
4478 list
[i
].dns_name
= NULL
;
4479 if (dns_name
[0] != '\0') {
4480 list
[i
].dns_name
= talloc_strdup(list
, dns_name
);
4482 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
4483 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4486 list
[i
].trust_flags
= flags
;
4487 list
[i
].trust_attribs
= attribs
;
4488 list
[i
].trust_type
= type
;
4496 /*********************************************************************
4497 ********************************************************************/
4499 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
4501 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4502 TDB_DATA data
= { NULL
, 0 };
4508 /* See if we were asked to delete the cache entry */
4511 ret
= tdb_delete( wcache
->tdb
, key
);
4515 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4522 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4525 SAFE_FREE( data
.dptr
);
4526 SAFE_FREE( key
.dptr
);
4528 return ( ret
== 0 );
4531 /*********************************************************************
4532 ********************************************************************/
4534 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4536 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4537 TDB_DATA data
= { NULL
, 0 };
4545 data
= tdb_fetch( wcache
->tdb
, key
);
4547 SAFE_FREE( key
.dptr
);
4552 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4554 SAFE_FREE( data
.dptr
);
4562 /*********************************************************************
4563 ********************************************************************/
4565 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4567 struct winbindd_tdc_domain
*dom_list
= NULL
;
4568 size_t num_domains
= 0;
4570 struct dom_sid_buf buf
;
4572 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4573 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4574 domain
->name
, domain
->alt_name
,
4575 dom_sid_str_buf(&domain
->sid
, &buf
),
4576 domain
->domain_flags
,
4577 domain
->domain_trust_attribs
,
4578 domain
->domain_type
));
4580 if ( !init_wcache() ) {
4584 /* fetch the list */
4586 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4588 /* add the new domain */
4590 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4594 /* pack the domain */
4596 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4604 TALLOC_FREE( dom_list
);
4609 static struct winbindd_tdc_domain
*wcache_tdc_dup_domain(
4610 TALLOC_CTX
*mem_ctx
, const struct winbindd_tdc_domain
*src
)
4612 struct winbindd_tdc_domain
*dst
;
4614 dst
= talloc(mem_ctx
, struct winbindd_tdc_domain
);
4618 dst
->domain_name
= talloc_strdup(dst
, src
->domain_name
);
4619 if (dst
->domain_name
== NULL
) {
4623 dst
->dns_name
= NULL
;
4624 if (src
->dns_name
!= NULL
) {
4625 dst
->dns_name
= talloc_strdup(dst
, src
->dns_name
);
4626 if (dst
->dns_name
== NULL
) {
4631 sid_copy(&dst
->sid
, &src
->sid
);
4632 dst
->trust_flags
= src
->trust_flags
;
4633 dst
->trust_type
= src
->trust_type
;
4634 dst
->trust_attribs
= src
->trust_attribs
;
4641 /*********************************************************************
4642 ********************************************************************/
4644 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4646 struct winbindd_tdc_domain
*dom_list
= NULL
;
4647 size_t num_domains
= 0;
4649 struct winbindd_tdc_domain
*d
= NULL
;
4651 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4653 if ( !init_wcache() ) {
4657 /* fetch the list */
4659 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4661 for ( i
=0; i
<num_domains
; i
++ ) {
4662 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4663 strequal(name
, dom_list
[i
].dns_name
) )
4665 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4668 d
= wcache_tdc_dup_domain(ctx
, &dom_list
[i
]);
4673 TALLOC_FREE( dom_list
);
4678 /*********************************************************************
4679 ********************************************************************/
4681 void wcache_tdc_clear( void )
4683 if ( !init_wcache() )
4686 wcache_tdc_store_list( NULL
, 0 );
4691 static bool wcache_ndr_key(TALLOC_CTX
*mem_ctx
, const char *domain_name
,
4692 uint32_t opnum
, const DATA_BLOB
*req
,
4698 key
= talloc_asprintf(mem_ctx
, "NDR/%s/%d/", domain_name
, (int)opnum
);
4702 keylen
= talloc_get_size(key
) - 1;
4704 key
= talloc_realloc(mem_ctx
, key
, char, keylen
+ req
->length
);
4708 memcpy(key
+ keylen
, req
->data
, req
->length
);
4710 pkey
->dptr
= (uint8_t *)key
;
4711 pkey
->dsize
= talloc_get_size(key
);
4715 static bool wcache_opnum_cacheable(uint32_t opnum
)
4718 case NDR_WBINT_PING
:
4719 case NDR_WBINT_QUERYSEQUENCENUMBER
:
4720 case NDR_WBINT_ALLOCATEUID
:
4721 case NDR_WBINT_ALLOCATEGID
:
4722 case NDR_WBINT_CHECKMACHINEACCOUNT
:
4723 case NDR_WBINT_CHANGEMACHINEACCOUNT
:
4724 case NDR_WBINT_PINGDC
:
4730 bool wcache_fetch_ndr(TALLOC_CTX
*mem_ctx
, struct winbindd_domain
*domain
,
4731 uint32_t opnum
, const DATA_BLOB
*req
, DATA_BLOB
*resp
)
4736 if (!wcache_opnum_cacheable(opnum
) ||
4737 is_my_own_sam_domain(domain
) ||
4738 is_builtin_domain(domain
)) {
4742 if (wcache
->tdb
== NULL
) {
4746 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4749 data
= tdb_fetch(wcache
->tdb
, key
);
4750 TALLOC_FREE(key
.dptr
);
4752 if (data
.dptr
== NULL
) {
4755 if (data
.dsize
< 12) {
4759 if (is_domain_online(domain
)) {
4760 uint32_t entry_seqnum
, dom_seqnum
, last_check
;
4761 uint64_t entry_timeout
;
4763 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
,
4767 entry_seqnum
= IVAL(data
.dptr
, 0);
4768 if (entry_seqnum
!= dom_seqnum
) {
4769 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4770 (int)entry_seqnum
));
4773 entry_timeout
= BVAL(data
.dptr
, 4);
4774 if (time(NULL
) > (time_t)entry_timeout
) {
4775 DEBUG(10, ("Entry has timed out\n"));
4780 resp
->data
= (uint8_t *)talloc_memdup(mem_ctx
, data
.dptr
+ 12,
4782 if (resp
->data
== NULL
) {
4783 DEBUG(10, ("talloc failed\n"));
4786 resp
->length
= data
.dsize
- 12;
4790 SAFE_FREE(data
.dptr
);
4794 void wcache_store_ndr(struct winbindd_domain
*domain
, uint32_t opnum
,
4795 const DATA_BLOB
*req
, const DATA_BLOB
*resp
)
4798 uint32_t dom_seqnum
, last_check
;
4801 if (!wcache_opnum_cacheable(opnum
) ||
4802 is_my_own_sam_domain(domain
) ||
4803 is_builtin_domain(domain
)) {
4807 if (wcache
->tdb
== NULL
) {
4811 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
, &last_check
)) {
4812 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4817 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4821 timeout
= time(NULL
) + lp_winbind_cache_time();
4823 data
.dsize
= resp
->length
+ 12;
4824 data
.dptr
= talloc_array(key
.dptr
, uint8_t, data
.dsize
);
4825 if (data
.dptr
== NULL
) {
4829 SIVAL(data
.dptr
, 0, dom_seqnum
);
4830 SBVAL(data
.dptr
, 4, timeout
);
4831 memcpy(data
.dptr
+ 12, resp
->data
, resp
->length
);
4833 tdb_store(wcache
->tdb
, key
, data
, 0);
4836 TALLOC_FREE(key
.dptr
);