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"
40 #define DBGC_CLASS DBGC_WINBIND
42 #define WINBINDD_CACHE_VER1 1 /* initial db version */
43 #define WINBINDD_CACHE_VER2 2 /* second version with timeouts for NDR entries */
45 #define WINBINDD_CACHE_VERSION WINBINDD_CACHE_VER2
46 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
48 extern struct winbindd_methods reconnect_methods
;
50 extern struct winbindd_methods reconnect_ads_methods
;
52 extern struct winbindd_methods builtin_passdb_methods
;
53 extern struct winbindd_methods sam_passdb_methods
;
55 static void wcache_flush_cache(void);
58 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
59 * Here are the list of entry types that are *not* stored
60 * as form struct cache_entry in the cache.
63 static const char *non_centry_keys
[] = {
66 WINBINDD_CACHE_VERSION_KEYSTR
,
70 /************************************************************************
71 Is this key a non-centry type ?
72 ************************************************************************/
74 static bool is_non_centry_key(TDB_DATA kbuf
)
78 if (kbuf
.dptr
== NULL
|| kbuf
.dsize
== 0) {
81 for (i
= 0; non_centry_keys
[i
] != NULL
; i
++) {
82 size_t namelen
= strlen(non_centry_keys
[i
]);
83 if (kbuf
.dsize
< namelen
) {
86 if (strncmp(non_centry_keys
[i
], (const char *)kbuf
.dptr
, namelen
) == 0) {
93 /* Global online/offline state - False when online. winbindd starts up online
94 and sets this to true if the first query fails and there's an entry in
95 the cache tdb telling us to stay offline. */
97 static bool global_winbindd_offline_state
;
99 struct winbind_cache
{
105 uint32_t sequence_number
;
111 void (*smb_panic_fn
)(const char *const why
) = smb_panic
;
113 static struct winbind_cache
*wcache
;
115 static char *wcache_path(void)
118 * Data needs to be kept persistent in state directory for
119 * running with "winbindd offline logon".
121 return state_path("winbindd_cache.tdb");
124 /* get the winbind_cache structure */
125 static struct winbind_cache
*get_cache(struct winbindd_domain
*domain
)
127 struct winbind_cache
*ret
= wcache
;
129 /* We have to know what type of domain we are dealing with first. */
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 OK. Listen up because I'm only going to say this once.
152 We have the following scenarios to consider
153 (a) trusted AD domains on a Samba DC,
154 (b) trusted AD domains and we are joined to a non-kerberos domain
155 (c) trusted AD domains and we are joined to a kerberos (AD) domain
157 For (a) we can always contact the trusted domain using krb5
158 since we have the domain trust account password
160 For (b) we can only use RPC since we have no way of
161 getting a krb5 ticket in our own domain
163 For (c) we can always use krb5 since we have a kerberos trust
169 if (domain
->backend
== NULL
) {
170 struct winbindd_domain
*our_domain
= domain
;
172 /* find our domain first so we can figure out if we
173 are joined to a kerberized domain */
175 if (!domain
->primary
) {
176 our_domain
= find_our_domain();
179 if ((our_domain
->active_directory
|| IS_DC
)
180 && domain
->active_directory
181 && !lp_winbind_rpc_only())
183 DBG_INFO("Setting ADS methods for domain %s\n",
185 domain
->backend
= &reconnect_ads_methods
;
188 #endif /* HAVE_ADS */
190 if (domain
->backend
== NULL
) {
191 DBG_INFO("Setting MS-RPC methods for domain %s\n", domain
->name
);
192 domain
->backend
= &reconnect_methods
;
199 ret
= SMB_XMALLOC_P(struct winbind_cache
);
203 wcache_flush_cache();
209 free a centry structure
211 static void centry_free(struct cache_entry
*centry
)
215 SAFE_FREE(centry
->data
);
219 static bool centry_check_bytes(struct cache_entry
*centry
, size_t nbytes
)
221 if (centry
->len
- centry
->ofs
< nbytes
) {
222 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
223 (unsigned int)nbytes
,
224 centry
->len
- centry
->ofs
));
231 pull a uint64_t from a cache entry
233 static uint64_t centry_uint64_t(struct cache_entry
*centry
)
237 if (!centry_check_bytes(centry
, 8)) {
238 smb_panic_fn("centry_uint64_t");
240 ret
= BVAL(centry
->data
, centry
->ofs
);
246 pull a uint32_t from a cache entry
248 static uint32_t centry_uint32(struct cache_entry
*centry
)
252 if (!centry_check_bytes(centry
, 4)) {
253 smb_panic_fn("centry_uint32");
255 ret
= IVAL(centry
->data
, centry
->ofs
);
261 pull a uint16_t from a cache entry
263 static uint16_t centry_uint16(struct cache_entry
*centry
)
266 if (!centry_check_bytes(centry
, 2)) {
267 smb_panic_fn("centry_uint16");
269 ret
= SVAL(centry
->data
, centry
->ofs
);
275 pull a uint8_t from a cache entry
277 static uint8_t centry_uint8(struct cache_entry
*centry
)
280 if (!centry_check_bytes(centry
, 1)) {
281 smb_panic_fn("centry_uint8");
283 ret
= CVAL(centry
->data
, centry
->ofs
);
289 pull a NTTIME from a cache entry
291 static NTTIME
centry_nttime(struct cache_entry
*centry
)
294 if (!centry_check_bytes(centry
, 8)) {
295 smb_panic_fn("centry_nttime");
297 ret
= IVAL(centry
->data
, centry
->ofs
);
299 ret
+= (uint64_t)IVAL(centry
->data
, centry
->ofs
) << 32;
305 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
307 static time_t centry_time(struct cache_entry
*centry
)
309 return (time_t)centry_nttime(centry
);
312 /* pull a string from a cache entry, using the supplied
315 static char *centry_string(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
320 len
= centry_uint8(centry
);
323 /* a deliberate NULL string */
327 if (!centry_check_bytes(centry
, (size_t)len
)) {
328 smb_panic_fn("centry_string");
331 ret
= talloc_array(mem_ctx
, char, len
+1);
333 smb_panic_fn("centry_string out of memory\n");
335 memcpy(ret
,centry
->data
+ centry
->ofs
, len
);
341 /* pull a hash16 from a cache entry, using the supplied
344 static char *centry_hash16(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
349 len
= centry_uint8(centry
);
352 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
357 if (!centry_check_bytes(centry
, 16)) {
361 ret
= talloc_array(mem_ctx
, char, 16);
363 smb_panic_fn("centry_hash out of memory\n");
365 memcpy(ret
,centry
->data
+ centry
->ofs
, 16);
370 /* pull a sid from a cache entry, using the supplied
373 static bool centry_sid(struct cache_entry
*centry
, struct dom_sid
*sid
)
378 sid_string
= centry_string(centry
, talloc_tos());
379 if (sid_string
== NULL
) {
382 ret
= string_to_sid(sid
, sid_string
);
383 TALLOC_FREE(sid_string
);
389 pull a NTSTATUS from a cache entry
391 static NTSTATUS
centry_ntstatus(struct cache_entry
*centry
)
395 status
= NT_STATUS(centry_uint32(centry
));
400 /* the server is considered down if it can't give us a sequence number */
401 static bool wcache_server_down(struct winbindd_domain
*domain
)
408 ret
= (domain
->sequence_number
== DOM_SEQUENCE_NONE
);
411 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
416 struct wcache_seqnum_state
{
418 uint32_t *last_seq_check
;
421 static int wcache_seqnum_parser(TDB_DATA key
, TDB_DATA data
,
424 struct wcache_seqnum_state
*state
= private_data
;
426 if (data
.dsize
!= 8) {
427 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
432 *state
->seqnum
= IVAL(data
.dptr
, 0);
433 *state
->last_seq_check
= IVAL(data
.dptr
, 4);
437 static bool wcache_fetch_seqnum(const char *domain_name
, uint32_t *seqnum
,
438 uint32_t *last_seq_check
)
440 struct wcache_seqnum_state state
= {
441 .seqnum
= seqnum
, .last_seq_check
= last_seq_check
443 size_t len
= strlen(domain_name
);
445 TDB_DATA key
= { .dptr
= (uint8_t *)keystr
, .dsize
= sizeof(keystr
) };
448 if (wcache
->tdb
== NULL
) {
449 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
453 snprintf(keystr
, sizeof(keystr
), "SEQNUM/%s", domain_name
);
455 ret
= tdb_parse_record(wcache
->tdb
, key
, wcache_seqnum_parser
,
460 static NTSTATUS
fetch_cache_seqnum( struct winbindd_domain
*domain
, time_t now
)
462 uint32_t last_check
, time_diff
;
464 if (!wcache_fetch_seqnum(domain
->name
, &domain
->sequence_number
,
466 return NT_STATUS_UNSUCCESSFUL
;
468 domain
->last_seq_check
= last_check
;
470 /* have we expired? */
472 time_diff
= now
- domain
->last_seq_check
;
473 if ( time_diff
> lp_winbind_cache_time() ) {
474 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
475 domain
->name
, domain
->sequence_number
,
476 (uint32_t)domain
->last_seq_check
));
477 return NT_STATUS_UNSUCCESSFUL
;
480 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
481 domain
->name
, domain
->sequence_number
,
482 (uint32_t)domain
->last_seq_check
));
487 bool wcache_store_seqnum(const char *domain_name
, uint32_t seqnum
,
488 time_t last_seq_check
)
490 size_t len
= strlen(domain_name
);
492 TDB_DATA key
= { .dptr
= (uint8_t *)keystr
, .dsize
= sizeof(keystr
) };
496 if (wcache
->tdb
== NULL
) {
497 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
501 snprintf(keystr
, sizeof(keystr
), "SEQNUM/%s", domain_name
);
503 SIVAL(buf
, 0, seqnum
);
504 SIVAL(buf
, 4, last_seq_check
);
506 ret
= tdb_store(wcache
->tdb
, key
, make_tdb_data(buf
, sizeof(buf
)),
509 DEBUG(10, ("tdb_store_bystring failed: %s\n",
510 tdb_errorstr(wcache
->tdb
)));
514 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
515 domain_name
, seqnum
, (unsigned)last_seq_check
));
520 static bool store_cache_seqnum( struct winbindd_domain
*domain
)
522 return wcache_store_seqnum(domain
->name
, domain
->sequence_number
,
523 domain
->last_seq_check
);
527 refresh the domain sequence number on timeout.
530 static void refresh_sequence_number(struct winbindd_domain
*domain
)
534 time_t t
= time(NULL
);
535 unsigned cache_time
= lp_winbind_cache_time();
537 if (is_domain_offline(domain
)) {
543 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
544 /* trying to reconnect is expensive, don't do it too often */
545 if (domain
->sequence_number
== DOM_SEQUENCE_NONE
) {
550 time_diff
= t
- domain
->last_seq_check
;
552 /* see if we have to refetch the domain sequence number */
553 if ((time_diff
< cache_time
) &&
554 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
555 NT_STATUS_IS_OK(domain
->last_status
)) {
556 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain
->name
));
560 /* try to get the sequence number from the tdb cache first */
561 /* this will update the timestamp as well */
563 status
= fetch_cache_seqnum( domain
, t
);
564 if (NT_STATUS_IS_OK(status
) &&
565 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
566 NT_STATUS_IS_OK(domain
->last_status
)) {
570 /* important! make sure that we know if this is a native
571 mode domain or not. And that we can contact it. */
573 if ( winbindd_can_contact_domain( domain
) ) {
574 status
= domain
->backend
->sequence_number(domain
,
575 &domain
->sequence_number
);
577 /* just use the current time */
578 status
= NT_STATUS_OK
;
579 domain
->sequence_number
= time(NULL
);
583 /* the above call could have set our domain->backend to NULL when
584 * coming from offline to online mode, make sure to reinitialize the
585 * backend - Guenther */
588 if (!NT_STATUS_IS_OK(status
)) {
589 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status
)));
590 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
593 domain
->last_status
= status
;
594 domain
->last_seq_check
= time(NULL
);
596 /* save the new sequence number in the cache */
597 store_cache_seqnum( domain
);
600 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
601 domain
->name
, domain
->sequence_number
));
607 decide if a cache entry has expired
609 static bool centry_expired(struct winbindd_domain
*domain
, const char *keystr
, struct cache_entry
*centry
)
611 /* If we've been told to be offline - stay in that state... */
612 if (lp_winbind_offline_logon() && global_winbindd_offline_state
) {
613 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
614 keystr
, domain
->name
));
618 /* when the domain is offline return the cached entry.
619 * This deals with transient offline states... */
621 if (!domain
->online
) {
622 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
623 keystr
, domain
->name
));
627 /* if the server is OK and our cache entry came from when it was down then
628 the entry is invalid */
629 if ((domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
630 (centry
->sequence_number
== DOM_SEQUENCE_NONE
)) {
631 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
632 keystr
, domain
->name
));
636 /* if the server is down or the cache entry is not older than the
637 current sequence number or it did not timeout then it is OK */
638 if (wcache_server_down(domain
)
639 || ((centry
->sequence_number
== domain
->sequence_number
)
640 && (centry
->timeout
> time(NULL
)))) {
641 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
642 keystr
, domain
->name
));
646 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
647 keystr
, domain
->name
));
653 static struct cache_entry
*wcache_fetch_raw(char *kstr
)
656 struct cache_entry
*centry
;
659 key
= string_tdb_data(kstr
);
660 data
= tdb_fetch(wcache
->tdb
, key
);
666 centry
= SMB_XMALLOC_P(struct cache_entry
);
667 centry
->data
= (unsigned char *)data
.dptr
;
668 centry
->len
= data
.dsize
;
671 if (centry
->len
< 16) {
672 /* huh? corrupt cache? */
673 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s "
674 "(len < 16)?\n", kstr
));
679 centry
->status
= centry_ntstatus(centry
);
680 centry
->sequence_number
= centry_uint32(centry
);
681 centry
->timeout
= centry_uint64_t(centry
);
686 static bool is_my_own_sam_domain(struct winbindd_domain
*domain
)
688 if (strequal(domain
->name
, get_global_sam_name()) &&
689 sid_check_is_our_sam(&domain
->sid
)) {
696 static bool is_builtin_domain(struct winbindd_domain
*domain
)
698 if (strequal(domain
->name
, "BUILTIN") &&
699 sid_check_is_builtin(&domain
->sid
)) {
707 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
708 number and return status
710 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
711 struct winbindd_domain
*domain
,
712 const char *format
, ...) PRINTF_ATTRIBUTE(3,4);
713 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
714 struct winbindd_domain
*domain
,
715 const char *format
, ...)
719 struct cache_entry
*centry
;
721 if (!winbindd_use_cache() ||
722 is_my_own_sam_domain(domain
) ||
723 is_builtin_domain(domain
)) {
727 refresh_sequence_number(domain
);
729 va_start(ap
, format
);
730 smb_xvasprintf(&kstr
, format
, ap
);
733 centry
= wcache_fetch_raw(kstr
);
734 if (centry
== NULL
) {
739 if (centry_expired(domain
, kstr
, centry
)) {
741 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
742 kstr
, domain
->name
));
749 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
750 kstr
, domain
->name
));
756 static void wcache_delete(const char *format
, ...) PRINTF_ATTRIBUTE(1,2);
757 static void wcache_delete(const char *format
, ...)
763 va_start(ap
, format
);
764 smb_xvasprintf(&kstr
, format
, ap
);
767 key
= string_tdb_data(kstr
);
769 tdb_delete(wcache
->tdb
, key
);
774 make sure we have at least len bytes available in a centry
776 static void centry_expand(struct cache_entry
*centry
, uint32_t len
)
778 if (centry
->len
- centry
->ofs
>= len
)
781 centry
->data
= SMB_REALLOC_ARRAY(centry
->data
, unsigned char,
784 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry
->len
));
785 smb_panic_fn("out of memory in centry_expand");
790 push a uint64_t into a centry
792 static void centry_put_uint64_t(struct cache_entry
*centry
, uint64_t v
)
794 centry_expand(centry
, 8);
795 SBVAL(centry
->data
, centry
->ofs
, v
);
800 push a uint32_t into a centry
802 static void centry_put_uint32(struct cache_entry
*centry
, uint32_t v
)
804 centry_expand(centry
, 4);
805 SIVAL(centry
->data
, centry
->ofs
, v
);
810 push a uint16_t into a centry
812 static void centry_put_uint16(struct cache_entry
*centry
, uint16_t v
)
814 centry_expand(centry
, 2);
815 SSVAL(centry
->data
, centry
->ofs
, v
);
820 push a uint8_t into a centry
822 static void centry_put_uint8(struct cache_entry
*centry
, uint8_t v
)
824 centry_expand(centry
, 1);
825 SCVAL(centry
->data
, centry
->ofs
, v
);
830 push a string into a centry
832 static void centry_put_string(struct cache_entry
*centry
, const char *s
)
837 /* null strings are marked as len 0xFFFF */
838 centry_put_uint8(centry
, 0xFF);
843 /* can't handle more than 254 char strings. Truncating is probably best */
845 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len
));
848 centry_put_uint8(centry
, len
);
849 centry_expand(centry
, len
);
850 memcpy(centry
->data
+ centry
->ofs
, s
, len
);
855 push a 16 byte hash into a centry - treat as 16 byte string.
857 static void centry_put_hash16(struct cache_entry
*centry
, const uint8_t val
[16])
859 centry_put_uint8(centry
, 16);
860 centry_expand(centry
, 16);
861 memcpy(centry
->data
+ centry
->ofs
, val
, 16);
865 static void centry_put_sid(struct cache_entry
*centry
, const struct dom_sid
*sid
)
868 centry_put_string(centry
, sid_to_fstring(sid_string
, sid
));
873 put NTSTATUS into a centry
875 static void centry_put_ntstatus(struct cache_entry
*centry
, NTSTATUS status
)
877 uint32_t status_value
= NT_STATUS_V(status
);
878 centry_put_uint32(centry
, status_value
);
883 push a NTTIME into a centry
885 static void centry_put_nttime(struct cache_entry
*centry
, NTTIME nt
)
887 centry_expand(centry
, 8);
888 SIVAL(centry
->data
, centry
->ofs
, nt
& 0xFFFFFFFF);
890 SIVAL(centry
->data
, centry
->ofs
, nt
>> 32);
895 push a time_t into a centry - use a 64 bit size.
896 NTTIME here is being used as a convenient 64-bit size.
898 static void centry_put_time(struct cache_entry
*centry
, time_t t
)
900 NTTIME nt
= (NTTIME
)t
;
901 centry_put_nttime(centry
, nt
);
905 start a centry for output. When finished, call centry_end()
907 static struct cache_entry
*centry_start(struct winbindd_domain
*domain
,
910 struct cache_entry
*centry
;
915 centry
= SMB_XMALLOC_P(struct cache_entry
);
917 centry
->len
= 8192; /* reasonable default */
918 centry
->data
= SMB_XMALLOC_ARRAY(uint8_t, centry
->len
);
920 centry
->sequence_number
= domain
->sequence_number
;
921 centry
->timeout
= lp_winbind_cache_time() + time(NULL
);
922 centry_put_ntstatus(centry
, status
);
923 centry_put_uint32(centry
, centry
->sequence_number
);
924 centry_put_uint64_t(centry
, centry
->timeout
);
929 finish a centry and write it to the tdb
931 static void centry_end(struct cache_entry
*centry
, const char *format
, ...) PRINTF_ATTRIBUTE(2,3);
932 static void centry_end(struct cache_entry
*centry
, const char *format
, ...)
938 if (!winbindd_use_cache()) {
942 va_start(ap
, format
);
943 smb_xvasprintf(&kstr
, format
, ap
);
946 key
= string_tdb_data(kstr
);
947 data
.dptr
= centry
->data
;
948 data
.dsize
= centry
->ofs
;
950 tdb_store(wcache
->tdb
, key
, data
, TDB_REPLACE
);
954 static void wcache_save_name_to_sid(struct winbindd_domain
*domain
,
955 NTSTATUS status
, const char *domain_name
,
956 const char *name
, const struct dom_sid
*sid
,
957 enum lsa_SidType type
)
959 struct cache_entry
*centry
;
962 centry
= centry_start(domain
, status
);
966 if ((domain_name
== NULL
) || (domain_name
[0] == '\0')) {
967 struct winbindd_domain
*mydomain
=
968 find_domain_from_sid_noinit(sid
);
969 if (mydomain
!= NULL
) {
970 domain_name
= mydomain
->name
;
974 centry_put_uint32(centry
, type
);
975 centry_put_sid(centry
, sid
);
976 fstrcpy(uname
, name
);
977 (void)strupper_m(uname
);
978 centry_end(centry
, "NS/%s/%s", domain_name
, uname
);
979 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name
,
980 uname
, sid_string_dbg(sid
), nt_errstr(status
)));
984 static void wcache_save_sid_to_name(struct winbindd_domain
*domain
, NTSTATUS status
,
985 const struct dom_sid
*sid
, const char *domain_name
, const char *name
, enum lsa_SidType type
)
987 struct cache_entry
*centry
;
990 centry
= centry_start(domain
, status
);
994 if ((domain_name
== NULL
) || (domain_name
[0] == '\0')) {
995 struct winbindd_domain
*mydomain
=
996 find_domain_from_sid_noinit(sid
);
997 if (mydomain
!= NULL
) {
998 domain_name
= mydomain
->name
;
1002 if (NT_STATUS_IS_OK(status
)) {
1003 centry_put_uint32(centry
, type
);
1004 centry_put_string(centry
, domain_name
);
1005 centry_put_string(centry
, name
);
1008 centry_end(centry
, "SN/%s", sid_to_fstring(sid_string
, sid
));
1009 DEBUG(10,("wcache_save_sid_to_name: %s -> %s\\%s (%s)\n", sid_string
,
1010 domain_name
, name
, nt_errstr(status
)));
1011 centry_free(centry
);
1014 static void wcache_save_lockout_policy(struct winbindd_domain
*domain
,
1016 struct samr_DomInfo12
*lockout_policy
)
1018 struct cache_entry
*centry
;
1020 centry
= centry_start(domain
, status
);
1024 centry_put_nttime(centry
, lockout_policy
->lockout_duration
);
1025 centry_put_nttime(centry
, lockout_policy
->lockout_window
);
1026 centry_put_uint16(centry
, lockout_policy
->lockout_threshold
);
1028 centry_end(centry
, "LOC_POL/%s", domain
->name
);
1030 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain
->name
));
1032 centry_free(centry
);
1037 static void wcache_save_password_policy(struct winbindd_domain
*domain
,
1039 struct samr_DomInfo1
*policy
)
1041 struct cache_entry
*centry
;
1043 centry
= centry_start(domain
, status
);
1047 centry_put_uint16(centry
, policy
->min_password_length
);
1048 centry_put_uint16(centry
, policy
->password_history_length
);
1049 centry_put_uint32(centry
, policy
->password_properties
);
1050 centry_put_nttime(centry
, policy
->max_password_age
);
1051 centry_put_nttime(centry
, policy
->min_password_age
);
1053 centry_end(centry
, "PWD_POL/%s", domain
->name
);
1055 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
1057 centry_free(centry
);
1060 /***************************************************************************
1061 ***************************************************************************/
1063 static void wcache_save_username_alias(struct winbindd_domain
*domain
,
1065 const char *name
, const char *alias
)
1067 struct cache_entry
*centry
;
1070 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1073 centry_put_string( centry
, alias
);
1075 fstrcpy(uname
, name
);
1076 (void)strupper_m(uname
);
1077 centry_end(centry
, "NSS/NA/%s", uname
);
1079 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name
, alias
));
1081 centry_free(centry
);
1084 static void wcache_save_alias_username(struct winbindd_domain
*domain
,
1086 const char *alias
, const char *name
)
1088 struct cache_entry
*centry
;
1091 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1094 centry_put_string( centry
, name
);
1096 fstrcpy(uname
, alias
);
1097 (void)strupper_m(uname
);
1098 centry_end(centry
, "NSS/AN/%s", uname
);
1100 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias
, name
));
1102 centry_free(centry
);
1105 /***************************************************************************
1106 ***************************************************************************/
1108 NTSTATUS
resolve_username_to_alias( TALLOC_CTX
*mem_ctx
,
1109 struct winbindd_domain
*domain
,
1110 const char *name
, char **alias
)
1112 struct winbind_cache
*cache
= get_cache(domain
);
1113 struct cache_entry
*centry
= NULL
;
1117 if ( domain
->internal
)
1118 return NT_STATUS_NOT_SUPPORTED
;
1123 upper_name
= talloc_strdup_upper(mem_ctx
, name
);
1124 if (upper_name
== NULL
) {
1125 return NT_STATUS_NO_MEMORY
;
1128 centry
= wcache_fetch(cache
, domain
, "NSS/NA/%s", upper_name
);
1130 talloc_free(upper_name
);
1135 status
= centry
->status
;
1137 if (!NT_STATUS_IS_OK(status
)) {
1138 centry_free(centry
);
1142 *alias
= centry_string( centry
, mem_ctx
);
1144 centry_free(centry
);
1146 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1147 name
, *alias
? *alias
: "(none)"));
1149 return (*alias
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1153 /* If its not in cache and we are offline, then fail */
1155 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1156 DEBUG(8,("resolve_username_to_alias: rejecting query "
1157 "in offline mode\n"));
1158 return NT_STATUS_NOT_FOUND
;
1161 status
= nss_map_to_alias( mem_ctx
, domain
->name
, name
, alias
);
1163 if ( NT_STATUS_IS_OK( status
) ) {
1164 wcache_save_username_alias(domain
, status
, name
, *alias
);
1167 if ( NT_STATUS_EQUAL( status
, NT_STATUS_NONE_MAPPED
) ) {
1168 wcache_save_username_alias(domain
, status
, name
, "(NULL)");
1171 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1172 nt_errstr(status
)));
1174 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1175 set_domain_offline( domain
);
1181 /***************************************************************************
1182 ***************************************************************************/
1184 NTSTATUS
resolve_alias_to_username( TALLOC_CTX
*mem_ctx
,
1185 struct winbindd_domain
*domain
,
1186 const char *alias
, char **name
)
1188 struct winbind_cache
*cache
= get_cache(domain
);
1189 struct cache_entry
*centry
= NULL
;
1193 if ( domain
->internal
)
1194 return NT_STATUS_NOT_SUPPORTED
;
1199 upper_name
= talloc_strdup(mem_ctx
, alias
);
1200 if (upper_name
== NULL
) {
1201 return NT_STATUS_NO_MEMORY
;
1203 if (!strupper_m(upper_name
)) {
1204 talloc_free(upper_name
);
1205 return NT_STATUS_INVALID_PARAMETER
;
1208 centry
= wcache_fetch(cache
, domain
, "NSS/AN/%s", upper_name
);
1210 talloc_free(upper_name
);
1215 status
= centry
->status
;
1217 if (!NT_STATUS_IS_OK(status
)) {
1218 centry_free(centry
);
1222 *name
= centry_string( centry
, mem_ctx
);
1224 centry_free(centry
);
1226 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1227 alias
, *name
? *name
: "(none)"));
1229 return (*name
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1233 /* If its not in cache and we are offline, then fail */
1235 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1236 DEBUG(8,("resolve_alias_to_username: rejecting query "
1237 "in offline mode\n"));
1238 return NT_STATUS_NOT_FOUND
;
1241 /* an alias cannot contain a domain prefix or '@' */
1243 if (strchr(alias
, '\\') || strchr(alias
, '@')) {
1244 DEBUG(10,("resolve_alias_to_username: skipping fully "
1245 "qualified name %s\n", alias
));
1246 return NT_STATUS_OBJECT_NAME_INVALID
;
1249 status
= nss_map_from_alias( mem_ctx
, domain
->name
, alias
, name
);
1251 if ( NT_STATUS_IS_OK( status
) ) {
1252 wcache_save_alias_username( domain
, status
, alias
, *name
);
1255 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1256 wcache_save_alias_username(domain
, status
, alias
, "(NULL)");
1259 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1260 nt_errstr(status
)));
1262 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1263 set_domain_offline( domain
);
1269 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
1271 struct winbind_cache
*cache
= get_cache(domain
);
1273 fstring key_str
, tmp
;
1277 return NT_STATUS_INTERNAL_DB_ERROR
;
1280 if (is_null_sid(sid
)) {
1281 return NT_STATUS_INVALID_SID
;
1284 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1285 return NT_STATUS_INVALID_SID
;
1288 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
1290 data
= tdb_fetch(cache
->tdb
, string_tdb_data(key_str
));
1292 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1295 SAFE_FREE(data
.dptr
);
1296 return NT_STATUS_OK
;
1299 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1300 as new salted ones. */
1302 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
1303 TALLOC_CTX
*mem_ctx
,
1304 const struct dom_sid
*sid
,
1305 const uint8_t **cached_nt_pass
,
1306 const uint8_t **cached_salt
)
1308 struct winbind_cache
*cache
= get_cache(domain
);
1309 struct cache_entry
*centry
= NULL
;
1315 return NT_STATUS_INTERNAL_DB_ERROR
;
1318 if (is_null_sid(sid
)) {
1319 return NT_STATUS_INVALID_SID
;
1322 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1323 return NT_STATUS_INVALID_SID
;
1326 /* Try and get a salted cred first. If we can't
1327 fall back to an unsalted cred. */
1329 centry
= wcache_fetch(cache
, domain
, "CRED/%s",
1330 sid_to_fstring(tmp
, sid
));
1332 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1333 sid_string_dbg(sid
)));
1334 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1338 * We don't use the time element at this moment,
1339 * but we have to consume it, so that we don't
1340 * neet to change the disk format of the cache.
1342 (void)centry_time(centry
);
1344 /* In the salted case this isn't actually the nt_hash itself,
1345 but the MD5 of the salt + nt_hash. Let the caller
1346 sort this out. It can tell as we only return the cached_salt
1347 if we are returning a salted cred. */
1349 *cached_nt_pass
= (const uint8_t *)centry_hash16(centry
, mem_ctx
);
1350 if (*cached_nt_pass
== NULL
) {
1353 sid_to_fstring(sidstr
, sid
);
1355 /* Bad (old) cred cache. Delete and pretend we
1357 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1359 wcache_delete("CRED/%s", sidstr
);
1360 centry_free(centry
);
1361 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1364 /* We only have 17 bytes more data in the salted cred case. */
1365 if (centry
->len
- centry
->ofs
== 17) {
1366 *cached_salt
= (const uint8_t *)centry_hash16(centry
, mem_ctx
);
1368 *cached_salt
= NULL
;
1371 dump_data_pw("cached_nt_pass", *cached_nt_pass
, NT_HASH_LEN
);
1373 dump_data_pw("cached_salt", *cached_salt
, NT_HASH_LEN
);
1376 status
= centry
->status
;
1378 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1379 sid_string_dbg(sid
), nt_errstr(status
) ));
1381 centry_free(centry
);
1385 /* Store creds for a SID - only writes out new salted ones. */
1387 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1388 const struct dom_sid
*sid
,
1389 const uint8_t nt_pass
[NT_HASH_LEN
])
1391 struct cache_entry
*centry
;
1394 uint8_t cred_salt
[NT_HASH_LEN
];
1395 uint8_t salted_hash
[NT_HASH_LEN
];
1397 if (is_null_sid(sid
)) {
1398 return NT_STATUS_INVALID_SID
;
1401 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1402 return NT_STATUS_INVALID_SID
;
1405 centry
= centry_start(domain
, NT_STATUS_OK
);
1407 return NT_STATUS_INTERNAL_DB_ERROR
;
1410 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1412 centry_put_time(centry
, time(NULL
));
1414 /* Create a salt and then salt the hash. */
1415 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1416 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1418 centry_put_hash16(centry
, salted_hash
);
1419 centry_put_hash16(centry
, cred_salt
);
1420 centry_end(centry
, "CRED/%s", sid_to_fstring(sid_string
, sid
));
1422 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1424 centry_free(centry
);
1426 return NT_STATUS_OK
;
1430 /* Query display info. This is the basic user list fn */
1431 NTSTATUS
wb_cache_query_user_list(struct winbindd_domain
*domain
,
1432 TALLOC_CTX
*mem_ctx
,
1435 struct winbind_cache
*cache
= get_cache(domain
);
1436 struct cache_entry
*centry
= NULL
;
1437 uint32_t num_rids
= 0;
1438 uint32_t *rids
= NULL
;
1440 unsigned int i
, retry
;
1441 bool old_status
= domain
->online
;
1448 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1453 num_rids
= centry_uint32(centry
);
1455 if (num_rids
== 0) {
1459 rids
= talloc_array(mem_ctx
, uint32_t, num_rids
);
1461 centry_free(centry
);
1462 return NT_STATUS_NO_MEMORY
;
1465 for (i
=0; i
<num_rids
; i
++) {
1466 rids
[i
] = centry_uint32(centry
);
1470 status
= centry
->status
;
1472 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1473 domain
->name
, nt_errstr(status
) ));
1475 centry_free(centry
);
1480 /* Return status value returned by seq number check */
1482 if (!NT_STATUS_IS_OK(domain
->last_status
))
1483 return domain
->last_status
;
1485 /* Put the query_user_list() in a retry loop. There appears to be
1486 * some bug either with Windows 2000 or Samba's handling of large
1487 * rpc replies. This manifests itself as sudden disconnection
1488 * at a random point in the enumeration of a large (60k) user list.
1489 * The retry loop simply tries the operation again. )-: It's not
1490 * pretty but an acceptable workaround until we work out what the
1491 * real problem is. */
1496 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1500 status
= domain
->backend
->query_user_list(domain
, mem_ctx
,
1502 num_rids
= talloc_array_length(rids
);
1504 if (!NT_STATUS_IS_OK(status
)) {
1505 DEBUG(3, ("query_user_list: returned 0x%08x, "
1506 "retrying\n", NT_STATUS_V(status
)));
1508 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1509 DEBUG(3, ("query_user_list: flushing "
1510 "connection cache\n"));
1511 invalidate_cm_connection(domain
);
1513 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1514 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1515 if (!domain
->internal
&& old_status
) {
1516 set_domain_offline(domain
);
1518 /* store partial response. */
1521 * humm, what about the status used for cache?
1522 * Should it be NT_STATUS_OK?
1527 * domain is offline now, and there is no user entries,
1528 * try to fetch from cache again.
1530 if (cache
->tdb
&& !domain
->online
&& !domain
->internal
&& old_status
) {
1531 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1532 /* partial response... */
1536 goto do_fetch_cache
;
1543 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1547 refresh_sequence_number(domain
);
1548 if (!NT_STATUS_IS_OK(status
)) {
1551 centry
= centry_start(domain
, status
);
1554 centry_put_uint32(centry
, num_rids
);
1555 for (i
=0; i
<num_rids
; i
++) {
1556 centry_put_uint32(centry
, rids
[i
]);
1558 centry_end(centry
, "UL/%s", domain
->name
);
1559 centry_free(centry
);
1567 /* list all domain groups */
1568 NTSTATUS
wb_cache_enum_dom_groups(struct winbindd_domain
*domain
,
1569 TALLOC_CTX
*mem_ctx
,
1570 uint32_t *num_entries
,
1571 struct wb_acct_info
**info
)
1573 struct winbind_cache
*cache
= get_cache(domain
);
1574 struct cache_entry
*centry
= NULL
;
1579 old_status
= domain
->online
;
1583 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1588 *num_entries
= centry_uint32(centry
);
1590 if (*num_entries
== 0)
1593 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1595 smb_panic_fn("enum_dom_groups out of memory");
1597 for (i
=0; i
<(*num_entries
); i
++) {
1598 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1599 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1600 (*info
)[i
].rid
= centry_uint32(centry
);
1604 status
= centry
->status
;
1606 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1607 domain
->name
, nt_errstr(status
) ));
1609 centry_free(centry
);
1616 /* Return status value returned by seq number check */
1618 if (!NT_STATUS_IS_OK(domain
->last_status
))
1619 return domain
->last_status
;
1621 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1624 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1626 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1627 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1628 if (!domain
->internal
&& old_status
) {
1629 set_domain_offline(domain
);
1633 !domain
->internal
&&
1635 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1637 goto do_fetch_cache
;
1642 refresh_sequence_number(domain
);
1643 if (!NT_STATUS_IS_OK(status
)) {
1646 centry
= centry_start(domain
, status
);
1649 centry_put_uint32(centry
, *num_entries
);
1650 for (i
=0; i
<(*num_entries
); i
++) {
1651 centry_put_string(centry
, (*info
)[i
].acct_name
);
1652 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1653 centry_put_uint32(centry
, (*info
)[i
].rid
);
1655 centry_end(centry
, "GL/%s/domain", domain
->name
);
1656 centry_free(centry
);
1662 /* list all domain groups */
1663 NTSTATUS
wb_cache_enum_local_groups(struct winbindd_domain
*domain
,
1664 TALLOC_CTX
*mem_ctx
,
1665 uint32_t *num_entries
,
1666 struct wb_acct_info
**info
)
1668 struct winbind_cache
*cache
= get_cache(domain
);
1669 struct cache_entry
*centry
= NULL
;
1674 old_status
= domain
->online
;
1678 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1683 *num_entries
= centry_uint32(centry
);
1685 if (*num_entries
== 0)
1688 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1690 smb_panic_fn("enum_dom_groups out of memory");
1692 for (i
=0; i
<(*num_entries
); i
++) {
1693 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1694 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1695 (*info
)[i
].rid
= centry_uint32(centry
);
1700 /* If we are returning cached data and the domain controller
1701 is down then we don't know whether the data is up to date
1702 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1705 if (wcache_server_down(domain
)) {
1706 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1707 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1709 status
= centry
->status
;
1711 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1712 domain
->name
, nt_errstr(status
) ));
1714 centry_free(centry
);
1721 /* Return status value returned by seq number check */
1723 if (!NT_STATUS_IS_OK(domain
->last_status
))
1724 return domain
->last_status
;
1726 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1729 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1731 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1732 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1733 if (!domain
->internal
&& old_status
) {
1734 set_domain_offline(domain
);
1737 !domain
->internal
&&
1740 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1742 goto do_fetch_cache
;
1747 refresh_sequence_number(domain
);
1748 if (!NT_STATUS_IS_OK(status
)) {
1751 centry
= centry_start(domain
, status
);
1754 centry_put_uint32(centry
, *num_entries
);
1755 for (i
=0; i
<(*num_entries
); i
++) {
1756 centry_put_string(centry
, (*info
)[i
].acct_name
);
1757 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1758 centry_put_uint32(centry
, (*info
)[i
].rid
);
1760 centry_end(centry
, "GL/%s/local", domain
->name
);
1761 centry_free(centry
);
1767 static NTSTATUS
wcache_name_to_sid(struct winbindd_domain
*domain
,
1768 const char *domain_name
,
1770 struct dom_sid
*sid
,
1771 enum lsa_SidType
*type
)
1773 struct winbind_cache
*cache
= get_cache(domain
);
1774 struct cache_entry
*centry
;
1778 if (cache
->tdb
== NULL
) {
1779 return NT_STATUS_NOT_FOUND
;
1782 uname
= talloc_strdup_upper(talloc_tos(), name
);
1783 if (uname
== NULL
) {
1784 return NT_STATUS_NO_MEMORY
;
1787 if ((domain_name
== NULL
) || (domain_name
[0] == '\0')) {
1788 domain_name
= domain
->name
;
1791 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1793 if (centry
== NULL
) {
1794 return NT_STATUS_NOT_FOUND
;
1797 status
= centry
->status
;
1798 if (NT_STATUS_IS_OK(status
)) {
1799 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1800 centry_sid(centry
, sid
);
1803 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1804 "%s\n", domain
->name
, nt_errstr(status
) ));
1806 centry_free(centry
);
1810 /* convert a single name to a sid in a domain */
1811 NTSTATUS
wb_cache_name_to_sid(struct winbindd_domain
*domain
,
1812 TALLOC_CTX
*mem_ctx
,
1813 const char *domain_name
,
1816 struct dom_sid
*sid
,
1817 enum lsa_SidType
*type
)
1822 old_status
= domain
->online
;
1824 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1825 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1831 /* If the seq number check indicated that there is a problem
1832 * with this DC, then return that status... except for
1833 * access_denied. This is special because the dc may be in
1834 * "restrict anonymous = 1" mode, in which case it will deny
1835 * most unauthenticated operations, but *will* allow the LSA
1836 * name-to-sid that we try as a fallback. */
1838 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1839 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1840 return domain
->last_status
;
1842 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1845 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
,
1846 name
, flags
, sid
, type
);
1848 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1849 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1850 if (!domain
->internal
&& old_status
) {
1851 set_domain_offline(domain
);
1853 if (!domain
->internal
&&
1856 NTSTATUS cache_status
;
1857 cache_status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1858 return cache_status
;
1862 refresh_sequence_number(domain
);
1864 if (domain
->online
&&
1865 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1866 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1868 /* Only save the reverse mapping if this was not a UPN */
1869 if (!strchr(name
, '@')) {
1870 if (!strupper_m(discard_const_p(char, domain_name
))) {
1871 return NT_STATUS_INVALID_PARAMETER
;
1873 (void)strlower_m(discard_const_p(char, name
));
1874 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1881 static NTSTATUS
wcache_sid_to_name(struct winbindd_domain
*domain
,
1882 const struct dom_sid
*sid
,
1883 TALLOC_CTX
*mem_ctx
,
1886 enum lsa_SidType
*type
)
1888 struct winbind_cache
*cache
= get_cache(domain
);
1889 struct cache_entry
*centry
;
1893 if (cache
->tdb
== NULL
) {
1894 return NT_STATUS_NOT_FOUND
;
1897 sid_string
= sid_string_tos(sid
);
1898 if (sid_string
== NULL
) {
1899 return NT_STATUS_NO_MEMORY
;
1902 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_string
);
1903 TALLOC_FREE(sid_string
);
1904 if (centry
== NULL
) {
1905 return NT_STATUS_NOT_FOUND
;
1908 if (NT_STATUS_IS_OK(centry
->status
)) {
1909 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1910 *domain_name
= centry_string(centry
, mem_ctx
);
1911 *name
= centry_string(centry
, mem_ctx
);
1914 status
= centry
->status
;
1915 centry_free(centry
);
1917 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1918 "%s\n", domain
->name
, nt_errstr(status
) ));
1923 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1925 NTSTATUS
wb_cache_sid_to_name(struct winbindd_domain
*domain
,
1926 TALLOC_CTX
*mem_ctx
,
1927 const struct dom_sid
*sid
,
1930 enum lsa_SidType
*type
)
1935 old_status
= domain
->online
;
1936 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
1938 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1943 *domain_name
= NULL
;
1945 /* If the seq number check indicated that there is a problem
1946 * with this DC, then return that status... except for
1947 * access_denied. This is special because the dc may be in
1948 * "restrict anonymous = 1" mode, in which case it will deny
1949 * most unauthenticated operations, but *will* allow the LSA
1950 * sid-to-name that we try as a fallback. */
1952 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1953 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1954 return domain
->last_status
;
1956 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1959 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1961 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1962 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1963 if (!domain
->internal
&& old_status
) {
1964 set_domain_offline(domain
);
1966 if (!domain
->internal
&&
1969 NTSTATUS cache_status
;
1970 cache_status
= wcache_sid_to_name(domain
, sid
, mem_ctx
,
1971 domain_name
, name
, type
);
1972 return cache_status
;
1976 refresh_sequence_number(domain
);
1977 if (!NT_STATUS_IS_OK(status
)) {
1980 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
1982 /* We can't save the name to sid mapping here, as with sid history a
1983 * later name2sid would give the wrong sid. */
1988 NTSTATUS
wb_cache_rids_to_names(struct winbindd_domain
*domain
,
1989 TALLOC_CTX
*mem_ctx
,
1990 const struct dom_sid
*domain_sid
,
1995 enum lsa_SidType
**types
)
1997 struct winbind_cache
*cache
= get_cache(domain
);
1999 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
2004 old_status
= domain
->online
;
2005 *domain_name
= NULL
;
2013 if (num_rids
== 0) {
2014 return NT_STATUS_OK
;
2017 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2018 *types
= talloc_array(mem_ctx
, enum lsa_SidType
, num_rids
);
2020 if ((*names
== NULL
) || (*types
== NULL
)) {
2021 result
= NT_STATUS_NO_MEMORY
;
2025 have_mapped
= have_unmapped
= false;
2027 for (i
=0; i
<num_rids
; i
++) {
2029 struct cache_entry
*centry
;
2032 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2033 result
= NT_STATUS_INTERNAL_ERROR
;
2037 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2038 sid_to_fstring(tmp
, &sid
));
2043 (*types
)[i
] = SID_NAME_UNKNOWN
;
2044 (*names
)[i
] = talloc_strdup(*names
, "");
2046 if (NT_STATUS_IS_OK(centry
->status
)) {
2049 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2051 dom
= centry_string(centry
, mem_ctx
);
2052 if (*domain_name
== NULL
) {
2058 (*names
)[i
] = centry_string(centry
, *names
);
2060 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)
2061 || NT_STATUS_EQUAL(centry
->status
, STATUS_SOME_UNMAPPED
)) {
2062 have_unmapped
= true;
2065 /* something's definitely wrong */
2066 result
= centry
->status
;
2067 centry_free(centry
);
2071 centry_free(centry
);
2075 return NT_STATUS_NONE_MAPPED
;
2077 if (!have_unmapped
) {
2078 return NT_STATUS_OK
;
2080 return STATUS_SOME_UNMAPPED
;
2084 TALLOC_FREE(*names
);
2085 TALLOC_FREE(*types
);
2087 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
2088 rids
, num_rids
, domain_name
,
2091 if (NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
2092 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2093 if (!domain
->internal
&& old_status
) {
2094 set_domain_offline(domain
);
2097 !domain
->internal
&&
2100 have_mapped
= have_unmapped
= false;
2102 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2103 if (*names
== NULL
) {
2104 result
= NT_STATUS_NO_MEMORY
;
2108 *types
= talloc_array(mem_ctx
, enum lsa_SidType
,
2110 if (*types
== NULL
) {
2111 result
= NT_STATUS_NO_MEMORY
;
2115 for (i
=0; i
<num_rids
; i
++) {
2117 struct cache_entry
*centry
;
2120 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2121 result
= NT_STATUS_INTERNAL_ERROR
;
2125 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2126 sid_to_fstring(tmp
, &sid
));
2128 (*types
)[i
] = SID_NAME_UNKNOWN
;
2129 (*names
)[i
] = talloc_strdup(*names
, "");
2133 (*types
)[i
] = SID_NAME_UNKNOWN
;
2134 (*names
)[i
] = talloc_strdup(*names
, "");
2136 if (NT_STATUS_IS_OK(centry
->status
)) {
2139 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2141 dom
= centry_string(centry
, mem_ctx
);
2142 if (*domain_name
== NULL
) {
2148 (*names
)[i
] = centry_string(centry
, *names
);
2150 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)) {
2151 have_unmapped
= true;
2154 /* something's definitely wrong */
2155 result
= centry
->status
;
2156 centry_free(centry
);
2160 centry_free(centry
);
2164 return NT_STATUS_NONE_MAPPED
;
2166 if (!have_unmapped
) {
2167 return NT_STATUS_OK
;
2169 return STATUS_SOME_UNMAPPED
;
2173 None of the queried rids has been found so save all negative entries
2175 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
2176 for (i
= 0; i
< num_rids
; i
++) {
2178 const char *name
= "";
2179 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
2180 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
2182 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2183 return NT_STATUS_INTERNAL_ERROR
;
2186 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2194 Some or all of the queried rids have been found.
2196 if (!NT_STATUS_IS_OK(result
) &&
2197 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
2201 refresh_sequence_number(domain
);
2203 for (i
=0; i
<num_rids
; i
++) {
2207 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2208 result
= NT_STATUS_INTERNAL_ERROR
;
2212 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
2213 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
2215 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2216 (*names
)[i
], (*types
)[i
]);
2222 TALLOC_FREE(*names
);
2223 TALLOC_FREE(*types
);
2227 NTSTATUS
wcache_query_user(struct winbindd_domain
*domain
,
2228 TALLOC_CTX
*mem_ctx
,
2229 const struct dom_sid
*user_sid
,
2230 struct wbint_userinfo
*info
)
2232 struct winbind_cache
*cache
= get_cache(domain
);
2233 struct cache_entry
*centry
= NULL
;
2237 if (cache
->tdb
== NULL
) {
2238 return NT_STATUS_NOT_FOUND
;
2241 sid_string
= sid_string_tos(user_sid
);
2242 if (sid_string
== NULL
) {
2243 return NT_STATUS_NO_MEMORY
;
2246 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string
);
2247 TALLOC_FREE(sid_string
);
2248 if (centry
== NULL
) {
2249 return NT_STATUS_NOT_FOUND
;
2253 * If we have an access denied cache entry and a cached info3
2254 * in the samlogon cache then do a query. This will force the
2255 * rpc back end to return the info3 data.
2258 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
) &&
2259 netsamlogon_cache_have(user_sid
)) {
2260 DEBUG(10, ("query_user: cached access denied and have cached "
2262 domain
->last_status
= NT_STATUS_OK
;
2263 centry_free(centry
);
2264 return NT_STATUS_NOT_FOUND
;
2267 /* if status is not ok then this is a negative hit
2268 and the rest of the data doesn't matter */
2269 status
= centry
->status
;
2270 if (NT_STATUS_IS_OK(status
)) {
2271 info
->domain_name
= centry_string(centry
, mem_ctx
);
2272 info
->acct_name
= centry_string(centry
, mem_ctx
);
2273 info
->full_name
= centry_string(centry
, mem_ctx
);
2274 info
->homedir
= centry_string(centry
, mem_ctx
);
2275 info
->shell
= centry_string(centry
, mem_ctx
);
2276 info
->uid
= centry_uint32(centry
);
2277 info
->primary_gid
= centry_uint32(centry
);
2278 info
->primary_group_name
= centry_string(centry
, mem_ctx
);
2279 centry_sid(centry
, &info
->user_sid
);
2280 centry_sid(centry
, &info
->group_sid
);
2283 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2284 "%s\n", domain
->name
, nt_errstr(status
) ));
2286 centry_free(centry
);
2292 * @brief Query a fullname from the username cache (for further gecos processing)
2294 * @param domain A pointer to the winbindd_domain struct.
2295 * @param mem_ctx The talloc context.
2296 * @param user_sid The user sid.
2297 * @param full_name A pointer to the full_name string.
2299 * @return NTSTATUS code
2301 NTSTATUS
wcache_query_user_fullname(struct winbindd_domain
*domain
,
2302 TALLOC_CTX
*mem_ctx
,
2303 const struct dom_sid
*user_sid
,
2304 const char **full_name
)
2307 struct wbint_userinfo info
;
2309 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, &info
);
2310 if (!NT_STATUS_IS_OK(status
)) {
2314 if (info
.full_name
!= NULL
) {
2315 *full_name
= talloc_strdup(mem_ctx
, info
.full_name
);
2316 if (*full_name
== NULL
) {
2317 return NT_STATUS_NO_MEMORY
;
2321 return NT_STATUS_OK
;
2324 NTSTATUS
wcache_lookup_usergroups(struct winbindd_domain
*domain
,
2325 TALLOC_CTX
*mem_ctx
,
2326 const struct dom_sid
*user_sid
,
2327 uint32_t *pnum_sids
,
2328 struct dom_sid
**psids
)
2330 struct winbind_cache
*cache
= get_cache(domain
);
2331 struct cache_entry
*centry
= NULL
;
2333 uint32_t i
, num_sids
;
2334 struct dom_sid
*sids
;
2337 if (cache
->tdb
== NULL
) {
2338 return NT_STATUS_NOT_FOUND
;
2341 centry
= wcache_fetch(cache
, domain
, "UG/%s",
2342 sid_to_fstring(sid_string
, user_sid
));
2343 if (centry
== NULL
) {
2344 return NT_STATUS_NOT_FOUND
;
2347 /* If we have an access denied cache entry and a cached info3 in the
2348 samlogon cache then do a query. This will force the rpc back end
2349 to return the info3 data. */
2351 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)
2352 && netsamlogon_cache_have(user_sid
)) {
2353 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2355 domain
->last_status
= NT_STATUS_OK
;
2356 centry_free(centry
);
2357 return NT_STATUS_NOT_FOUND
;
2360 num_sids
= centry_uint32(centry
);
2361 sids
= talloc_array(mem_ctx
, struct dom_sid
, num_sids
);
2363 centry_free(centry
);
2364 return NT_STATUS_NO_MEMORY
;
2367 for (i
=0; i
<num_sids
; i
++) {
2368 centry_sid(centry
, &sids
[i
]);
2371 status
= centry
->status
;
2373 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2374 "status: %s\n", domain
->name
, nt_errstr(status
)));
2376 centry_free(centry
);
2378 *pnum_sids
= num_sids
;
2383 /* Lookup groups a user is a member of. */
2384 NTSTATUS
wb_cache_lookup_usergroups(struct winbindd_domain
*domain
,
2385 TALLOC_CTX
*mem_ctx
,
2386 const struct dom_sid
*user_sid
,
2387 uint32_t *num_groups
,
2388 struct dom_sid
**user_gids
)
2390 struct cache_entry
*centry
= NULL
;
2396 old_status
= domain
->online
;
2397 status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2398 num_groups
, user_gids
);
2399 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2404 (*user_gids
) = NULL
;
2406 /* Return status value returned by seq number check */
2408 if (!NT_STATUS_IS_OK(domain
->last_status
))
2409 return domain
->last_status
;
2411 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2414 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
2416 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2417 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2418 if (!domain
->internal
&& old_status
) {
2419 set_domain_offline(domain
);
2421 if (!domain
->internal
&&
2424 NTSTATUS cache_status
;
2425 cache_status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2426 num_groups
, user_gids
);
2427 return cache_status
;
2430 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
2434 refresh_sequence_number(domain
);
2435 if (!NT_STATUS_IS_OK(status
)) {
2438 centry
= centry_start(domain
, status
);
2442 centry_put_uint32(centry
, *num_groups
);
2443 for (i
=0; i
<(*num_groups
); i
++) {
2444 centry_put_sid(centry
, &(*user_gids
)[i
]);
2447 centry_end(centry
, "UG/%s", sid_to_fstring(sid_string
, user_sid
));
2448 centry_free(centry
);
2454 static char *wcache_make_sidlist(TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2455 const struct dom_sid
*sids
)
2460 sidlist
= talloc_strdup(mem_ctx
, "");
2461 if (sidlist
== NULL
) {
2464 for (i
=0; i
<num_sids
; i
++) {
2466 sidlist
= talloc_asprintf_append_buffer(
2467 sidlist
, "/%s", sid_to_fstring(tmp
, &sids
[i
]));
2468 if (sidlist
== NULL
) {
2475 static NTSTATUS
wcache_lookup_useraliases(struct winbindd_domain
*domain
,
2476 TALLOC_CTX
*mem_ctx
,
2478 const struct dom_sid
*sids
,
2479 uint32_t *pnum_aliases
,
2480 uint32_t **paliases
)
2482 struct winbind_cache
*cache
= get_cache(domain
);
2483 struct cache_entry
*centry
= NULL
;
2484 uint32_t i
, num_aliases
;
2489 if (cache
->tdb
== NULL
) {
2490 return NT_STATUS_NOT_FOUND
;
2493 if (num_sids
== 0) {
2496 return NT_STATUS_OK
;
2499 /* We need to cache indexed by the whole list of SIDs, the aliases
2500 * resulting might come from any of the SIDs. */
2502 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2503 if (sidlist
== NULL
) {
2504 return NT_STATUS_NO_MEMORY
;
2507 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2508 TALLOC_FREE(sidlist
);
2509 if (centry
== NULL
) {
2510 return NT_STATUS_NOT_FOUND
;
2513 num_aliases
= centry_uint32(centry
);
2514 aliases
= talloc_array(mem_ctx
, uint32_t, num_aliases
);
2515 if (aliases
== NULL
) {
2516 centry_free(centry
);
2517 return NT_STATUS_NO_MEMORY
;
2520 for (i
=0; i
<num_aliases
; i
++) {
2521 aliases
[i
] = centry_uint32(centry
);
2524 status
= centry
->status
;
2526 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2527 "status %s\n", domain
->name
, nt_errstr(status
)));
2529 centry_free(centry
);
2531 *pnum_aliases
= num_aliases
;
2532 *paliases
= aliases
;
2537 NTSTATUS
wb_cache_lookup_useraliases(struct winbindd_domain
*domain
,
2538 TALLOC_CTX
*mem_ctx
,
2540 const struct dom_sid
*sids
,
2541 uint32_t *num_aliases
,
2542 uint32_t **alias_rids
)
2544 struct cache_entry
*centry
= NULL
;
2550 old_status
= domain
->online
;
2551 status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
2552 num_aliases
, alias_rids
);
2553 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2558 (*alias_rids
) = NULL
;
2560 if (!NT_STATUS_IS_OK(domain
->last_status
))
2561 return domain
->last_status
;
2563 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2564 "for domain %s\n", domain
->name
));
2566 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2567 if (sidlist
== NULL
) {
2568 return NT_STATUS_NO_MEMORY
;
2571 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2573 num_aliases
, alias_rids
);
2575 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2576 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2577 if (!domain
->internal
&& old_status
) {
2578 set_domain_offline(domain
);
2580 if (!domain
->internal
&&
2583 NTSTATUS cache_status
;
2584 cache_status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
,
2585 sids
, num_aliases
, alias_rids
);
2586 return cache_status
;
2590 refresh_sequence_number(domain
);
2591 if (!NT_STATUS_IS_OK(status
)) {
2594 centry
= centry_start(domain
, status
);
2597 centry_put_uint32(centry
, *num_aliases
);
2598 for (i
=0; i
<(*num_aliases
); i
++)
2599 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2600 centry_end(centry
, "UA%s", sidlist
);
2601 centry_free(centry
);
2607 static NTSTATUS
wcache_lookup_groupmem(struct winbindd_domain
*domain
,
2608 TALLOC_CTX
*mem_ctx
,
2609 const struct dom_sid
*group_sid
,
2610 uint32_t *num_names
,
2611 struct dom_sid
**sid_mem
, char ***names
,
2612 uint32_t **name_types
)
2614 struct winbind_cache
*cache
= get_cache(domain
);
2615 struct cache_entry
*centry
= NULL
;
2620 if (cache
->tdb
== NULL
) {
2621 return NT_STATUS_NOT_FOUND
;
2624 sid_string
= sid_string_tos(group_sid
);
2625 if (sid_string
== NULL
) {
2626 return NT_STATUS_NO_MEMORY
;
2629 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_string
);
2630 TALLOC_FREE(sid_string
);
2631 if (centry
== NULL
) {
2632 return NT_STATUS_NOT_FOUND
;
2639 *num_names
= centry_uint32(centry
);
2640 if (*num_names
== 0) {
2641 centry_free(centry
);
2642 return NT_STATUS_OK
;
2645 *sid_mem
= talloc_array(mem_ctx
, struct dom_sid
, *num_names
);
2646 *names
= talloc_array(mem_ctx
, char *, *num_names
);
2647 *name_types
= talloc_array(mem_ctx
, uint32_t, *num_names
);
2649 if ((*sid_mem
== NULL
) || (*names
== NULL
) || (*name_types
== NULL
)) {
2650 TALLOC_FREE(*sid_mem
);
2651 TALLOC_FREE(*names
);
2652 TALLOC_FREE(*name_types
);
2653 centry_free(centry
);
2654 return NT_STATUS_NO_MEMORY
;
2657 for (i
=0; i
<(*num_names
); i
++) {
2658 centry_sid(centry
, &(*sid_mem
)[i
]);
2659 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2660 (*name_types
)[i
] = centry_uint32(centry
);
2663 status
= centry
->status
;
2665 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2666 "status: %s\n", domain
->name
, nt_errstr(status
)));
2668 centry_free(centry
);
2672 NTSTATUS
wb_cache_lookup_groupmem(struct winbindd_domain
*domain
,
2673 TALLOC_CTX
*mem_ctx
,
2674 const struct dom_sid
*group_sid
,
2675 enum lsa_SidType type
,
2676 uint32_t *num_names
,
2677 struct dom_sid
**sid_mem
,
2679 uint32_t **name_types
)
2681 struct cache_entry
*centry
= NULL
;
2687 old_status
= domain
->online
;
2688 status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2689 sid_mem
, names
, name_types
);
2690 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2697 (*name_types
) = NULL
;
2699 /* Return status value returned by seq number check */
2701 if (!NT_STATUS_IS_OK(domain
->last_status
))
2702 return domain
->last_status
;
2704 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2707 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
,
2709 sid_mem
, names
, name_types
);
2711 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2712 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2713 if (!domain
->internal
&& old_status
) {
2714 set_domain_offline(domain
);
2716 if (!domain
->internal
&&
2719 NTSTATUS cache_status
;
2720 cache_status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
,
2721 num_names
, sid_mem
, names
,
2723 return cache_status
;
2727 refresh_sequence_number(domain
);
2728 if (!NT_STATUS_IS_OK(status
)) {
2731 centry
= centry_start(domain
, status
);
2734 centry_put_uint32(centry
, *num_names
);
2735 for (i
=0; i
<(*num_names
); i
++) {
2736 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2737 centry_put_string(centry
, (*names
)[i
]);
2738 centry_put_uint32(centry
, (*name_types
)[i
]);
2740 centry_end(centry
, "GM/%s", sid_to_fstring(sid_string
, group_sid
));
2741 centry_free(centry
);
2747 /* find the sequence number for a domain */
2748 NTSTATUS
wb_cache_sequence_number(struct winbindd_domain
*domain
,
2751 refresh_sequence_number(domain
);
2753 *seq
= domain
->sequence_number
;
2755 return NT_STATUS_OK
;
2758 /* enumerate trusted domains
2759 * (we need to have the list of trustdoms in the cache when we go offline) -
2761 NTSTATUS
wb_cache_trusted_domains(struct winbindd_domain
*domain
,
2762 TALLOC_CTX
*mem_ctx
,
2763 struct netr_DomainTrustList
*trusts
)
2766 struct winbind_cache
*cache
;
2767 struct winbindd_tdc_domain
*dom_list
= NULL
;
2768 size_t num_domains
= 0;
2769 bool retval
= false;
2773 old_status
= domain
->online
;
2775 trusts
->array
= NULL
;
2777 cache
= get_cache(domain
);
2778 if (!cache
|| !cache
->tdb
) {
2782 if (domain
->online
) {
2786 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2787 if (!retval
|| !num_domains
|| !dom_list
) {
2788 TALLOC_FREE(dom_list
);
2793 trusts
->array
= talloc_zero_array(mem_ctx
, struct netr_DomainTrust
, num_domains
);
2794 if (!trusts
->array
) {
2795 TALLOC_FREE(dom_list
);
2796 return NT_STATUS_NO_MEMORY
;
2799 for (i
= 0; i
< num_domains
; i
++) {
2800 struct netr_DomainTrust
*trust
;
2801 struct dom_sid
*sid
;
2802 struct winbindd_domain
*dom
;
2804 dom
= find_domain_from_name_noinit(dom_list
[i
].domain_name
);
2805 if (dom
&& dom
->internal
) {
2809 trust
= &trusts
->array
[trusts
->count
];
2810 trust
->netbios_name
= talloc_strdup(trusts
->array
, dom_list
[i
].domain_name
);
2811 trust
->dns_name
= talloc_strdup(trusts
->array
, dom_list
[i
].dns_name
);
2812 sid
= talloc(trusts
->array
, struct dom_sid
);
2813 if (!trust
->netbios_name
|| !trust
->dns_name
||
2815 TALLOC_FREE(dom_list
);
2816 TALLOC_FREE(trusts
->array
);
2817 return NT_STATUS_NO_MEMORY
;
2820 trust
->trust_flags
= dom_list
[i
].trust_flags
;
2821 trust
->trust_attributes
= dom_list
[i
].trust_attribs
;
2822 trust
->trust_type
= dom_list
[i
].trust_type
;
2823 sid_copy(sid
, &dom_list
[i
].sid
);
2828 TALLOC_FREE(dom_list
);
2829 return NT_STATUS_OK
;
2832 /* Return status value returned by seq number check */
2834 if (!NT_STATUS_IS_OK(domain
->last_status
))
2835 return domain
->last_status
;
2837 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2840 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, trusts
);
2842 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2843 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2844 if (!domain
->internal
&& old_status
) {
2845 set_domain_offline(domain
);
2847 if (!domain
->internal
&&
2850 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2851 if (retval
&& num_domains
&& dom_list
) {
2852 TALLOC_FREE(trusts
->array
);
2854 goto do_fetch_cache
;
2858 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2859 * so that the generic centry handling still applies correctly -
2862 if (!NT_STATUS_IS_ERR(status
)) {
2863 status
= NT_STATUS_OK
;
2868 /* get lockout policy */
2869 NTSTATUS
wb_cache_lockout_policy(struct winbindd_domain
*domain
,
2870 TALLOC_CTX
*mem_ctx
,
2871 struct samr_DomInfo12
*policy
)
2873 struct winbind_cache
*cache
= get_cache(domain
);
2874 struct cache_entry
*centry
= NULL
;
2878 old_status
= domain
->online
;
2882 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2888 policy
->lockout_duration
= centry_nttime(centry
);
2889 policy
->lockout_window
= centry_nttime(centry
);
2890 policy
->lockout_threshold
= centry_uint16(centry
);
2892 status
= centry
->status
;
2894 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2895 domain
->name
, nt_errstr(status
) ));
2897 centry_free(centry
);
2901 ZERO_STRUCTP(policy
);
2903 /* Return status value returned by seq number check */
2905 if (!NT_STATUS_IS_OK(domain
->last_status
))
2906 return domain
->last_status
;
2908 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2911 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2913 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2914 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2915 if (!domain
->internal
&& old_status
) {
2916 set_domain_offline(domain
);
2919 !domain
->internal
&&
2922 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2924 goto do_fetch_cache
;
2929 refresh_sequence_number(domain
);
2930 if (!NT_STATUS_IS_OK(status
)) {
2933 wcache_save_lockout_policy(domain
, status
, policy
);
2938 /* get password policy */
2939 NTSTATUS
wb_cache_password_policy(struct winbindd_domain
*domain
,
2940 TALLOC_CTX
*mem_ctx
,
2941 struct samr_DomInfo1
*policy
)
2943 struct winbind_cache
*cache
= get_cache(domain
);
2944 struct cache_entry
*centry
= NULL
;
2948 old_status
= domain
->online
;
2952 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2958 policy
->min_password_length
= centry_uint16(centry
);
2959 policy
->password_history_length
= centry_uint16(centry
);
2960 policy
->password_properties
= centry_uint32(centry
);
2961 policy
->max_password_age
= centry_nttime(centry
);
2962 policy
->min_password_age
= centry_nttime(centry
);
2964 status
= centry
->status
;
2966 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2967 domain
->name
, nt_errstr(status
) ));
2969 centry_free(centry
);
2973 ZERO_STRUCTP(policy
);
2975 /* Return status value returned by seq number check */
2977 if (!NT_STATUS_IS_OK(domain
->last_status
))
2978 return domain
->last_status
;
2980 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2983 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
2985 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2986 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2987 if (!domain
->internal
&& old_status
) {
2988 set_domain_offline(domain
);
2991 !domain
->internal
&&
2994 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2996 goto do_fetch_cache
;
3001 refresh_sequence_number(domain
);
3002 if (!NT_STATUS_IS_OK(status
)) {
3005 wcache_save_password_policy(domain
, status
, policy
);
3011 /* Invalidate cached user and group lists coherently */
3013 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3016 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
3017 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
3018 tdb_delete(the_tdb
, kbuf
);
3023 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3025 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
3026 const struct dom_sid
*sid
)
3028 fstring key_str
, sid_string
;
3029 struct winbind_cache
*cache
;
3031 /* don't clear cached U/SID and UG/SID entries when we want to logon
3034 if (lp_winbind_offline_logon()) {
3041 cache
= get_cache(domain
);
3047 /* Clear U/SID cache entry */
3048 fstr_sprintf(key_str
, "U/%s", sid_to_fstring(sid_string
, sid
));
3049 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3050 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3052 /* Clear UG/SID cache entry */
3053 fstr_sprintf(key_str
, "UG/%s", sid_to_fstring(sid_string
, sid
));
3054 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3055 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3057 /* Samba/winbindd never needs this. */
3058 netsamlogon_clear_cached_user(sid
);
3061 bool wcache_invalidate_cache(void)
3063 struct winbindd_domain
*domain
;
3065 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3066 struct winbind_cache
*cache
= get_cache(domain
);
3068 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3069 "entries for %s\n", domain
->name
));
3072 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3081 bool wcache_invalidate_cache_noinit(void)
3083 struct winbindd_domain
*domain
;
3085 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3086 struct winbind_cache
*cache
;
3088 /* Skip uninitialized domains. */
3089 if (!domain
->initialized
&& !domain
->internal
) {
3093 cache
= get_cache(domain
);
3095 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3096 "entries for %s\n", domain
->name
));
3099 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3101 * Flushing cache has nothing to with domains.
3102 * return here if we successfully flushed once.
3103 * To avoid unnecessary traversing the cache.
3114 bool init_wcache(void)
3118 if (wcache
== NULL
) {
3119 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
3120 ZERO_STRUCTP(wcache
);
3123 if (wcache
->tdb
!= NULL
)
3126 db_path
= wcache_path();
3127 if (db_path
== NULL
) {
3131 /* when working offline we must not clear the cache on restart */
3132 wcache
->tdb
= tdb_open_log(db_path
,
3133 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3134 TDB_INCOMPATIBLE_HASH
|
3135 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3136 O_RDWR
|O_CREAT
, 0600);
3137 TALLOC_FREE(db_path
);
3138 if (wcache
->tdb
== NULL
) {
3139 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3146 /************************************************************************
3147 This is called by the parent to initialize the cache file.
3148 We don't need sophisticated locking here as we know we're the
3150 ************************************************************************/
3152 bool initialize_winbindd_cache(void)
3154 bool cache_bad
= true;
3157 if (!init_wcache()) {
3158 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3162 /* Check version number. */
3163 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
3164 vers
== WINBINDD_CACHE_VERSION
) {
3171 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3172 "and re-creating with version number %d\n",
3173 WINBINDD_CACHE_VERSION
));
3175 tdb_close(wcache
->tdb
);
3178 db_path
= wcache_path();
3179 if (db_path
== NULL
) {
3183 if (unlink(db_path
) == -1) {
3184 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3187 TALLOC_FREE(db_path
);
3190 TALLOC_FREE(db_path
);
3191 if (!init_wcache()) {
3192 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3193 "init_wcache failed.\n"));
3197 /* Write the version. */
3198 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
3199 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3200 tdb_errorstr(wcache
->tdb
) ));
3205 tdb_close(wcache
->tdb
);
3210 void close_winbindd_cache(void)
3216 tdb_close(wcache
->tdb
);
3221 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*sid
,
3222 char **domain_name
, char **name
,
3223 enum lsa_SidType
*type
)
3225 struct winbindd_domain
*domain
;
3228 domain
= find_lookup_domain_from_sid(sid
);
3229 if (domain
== NULL
) {
3232 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
3234 return NT_STATUS_IS_OK(status
);
3237 bool lookup_cached_name(const char *domain_name
,
3239 struct dom_sid
*sid
,
3240 enum lsa_SidType
*type
)
3242 struct winbindd_domain
*domain
;
3244 bool original_online_state
;
3246 domain
= find_lookup_domain_from_name(domain_name
);
3247 if (domain
== NULL
) {
3251 /* If we are doing a cached logon, temporarily set the domain
3252 offline so the cache won't expire the entry */
3254 original_online_state
= domain
->online
;
3255 domain
->online
= false;
3256 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
3257 domain
->online
= original_online_state
;
3259 return NT_STATUS_IS_OK(status
);
3263 * Cache a name to sid without checking the sequence number.
3264 * Used when caching from a trusted PAC.
3267 void cache_name2sid_trusted(struct winbindd_domain
*domain
,
3268 const char *domain_name
,
3270 enum lsa_SidType type
,
3271 const struct dom_sid
*sid
)
3274 * Ensure we store the mapping with the
3275 * existing sequence number from the cache.
3278 (void)fetch_cache_seqnum(domain
, time(NULL
));
3279 wcache_save_name_to_sid(domain
,
3287 void cache_name2sid(struct winbindd_domain
*domain
,
3288 const char *domain_name
, const char *name
,
3289 enum lsa_SidType type
, const struct dom_sid
*sid
)
3291 refresh_sequence_number(domain
);
3292 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
3297 * The original idea that this cache only contains centries has
3298 * been blurred - now other stuff gets put in here. Ensure we
3299 * ignore these things on cleanup.
3302 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
3303 TDB_DATA dbuf
, void *state
)
3305 struct cache_entry
*centry
;
3307 if (is_non_centry_key(kbuf
)) {
3311 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
3316 if (!NT_STATUS_IS_OK(centry
->status
)) {
3317 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
3318 tdb_delete(the_tdb
, kbuf
);
3321 centry_free(centry
);
3325 /* flush the cache */
3326 static void wcache_flush_cache(void)
3333 tdb_close(wcache
->tdb
);
3336 if (!winbindd_use_cache()) {
3340 db_path
= wcache_path();
3341 if (db_path
== NULL
) {
3345 /* when working offline we must not clear the cache on restart */
3346 wcache
->tdb
= tdb_open_log(db_path
,
3347 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3348 TDB_INCOMPATIBLE_HASH
|
3349 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3350 O_RDWR
|O_CREAT
, 0600);
3351 TALLOC_FREE(db_path
);
3353 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3357 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
3359 DEBUG(10,("wcache_flush_cache success\n"));
3362 /* Count cached creds */
3364 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3367 int *cred_count
= (int*)state
;
3369 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3375 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
3377 struct winbind_cache
*cache
= get_cache(domain
);
3382 return NT_STATUS_INTERNAL_DB_ERROR
;
3385 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
3387 return NT_STATUS_OK
;
3391 struct cred_list
*prev
, *next
;
3396 static struct cred_list
*wcache_cred_list
;
3398 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3401 struct cred_list
*cred
;
3403 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3405 cred
= SMB_MALLOC_P(struct cred_list
);
3407 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3413 /* save a copy of the key */
3415 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
3416 DLIST_ADD(wcache_cred_list
, cred
);
3422 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
3424 struct winbind_cache
*cache
= get_cache(domain
);
3427 struct cred_list
*cred
, *next
, *oldest
= NULL
;
3430 return NT_STATUS_INTERNAL_DB_ERROR
;
3433 /* we possibly already have an entry */
3434 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
3436 fstring key_str
, tmp
;
3438 DEBUG(11,("we already have an entry, deleting that\n"));
3440 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
3442 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3444 return NT_STATUS_OK
;
3447 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
3449 return NT_STATUS_OK
;
3450 } else if ((ret
< 0) || (wcache_cred_list
== NULL
)) {
3451 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3454 ZERO_STRUCTP(oldest
);
3456 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
3461 data
= tdb_fetch(cache
->tdb
, string_tdb_data(cred
->name
));
3463 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3465 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3469 t
= IVAL(data
.dptr
, 0);
3470 SAFE_FREE(data
.dptr
);
3473 oldest
= SMB_MALLOC_P(struct cred_list
);
3474 if (oldest
== NULL
) {
3475 status
= NT_STATUS_NO_MEMORY
;
3479 fstrcpy(oldest
->name
, cred
->name
);
3480 oldest
->created
= t
;
3484 if (t
< oldest
->created
) {
3485 fstrcpy(oldest
->name
, cred
->name
);
3486 oldest
->created
= t
;
3490 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3491 status
= NT_STATUS_OK
;
3493 status
= NT_STATUS_UNSUCCESSFUL
;
3496 for (cred
= wcache_cred_list
; cred
; cred
= next
) {
3498 DLIST_REMOVE(wcache_cred_list
, cred
);
3506 /* Change the global online/offline state. */
3507 bool set_global_winbindd_state_offline(void)
3511 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3513 /* Only go offline if someone has created
3514 the key "WINBINDD_OFFLINE" in the cache tdb. */
3516 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3517 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3521 if (!lp_winbind_offline_logon()) {
3522 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3526 if (global_winbindd_offline_state
) {
3527 /* Already offline. */
3531 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
3533 if (!data
.dptr
|| data
.dsize
!= 4) {
3534 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3535 SAFE_FREE(data
.dptr
);
3538 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3539 global_winbindd_offline_state
= true;
3540 SAFE_FREE(data
.dptr
);
3545 void set_global_winbindd_state_online(void)
3547 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3549 if (!lp_winbind_offline_logon()) {
3550 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3554 if (!global_winbindd_offline_state
) {
3555 /* Already online. */
3558 global_winbindd_offline_state
= false;
3564 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3565 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3568 bool get_global_winbindd_state_offline(void)
3570 return global_winbindd_offline_state
;
3573 /***********************************************************************
3574 Validate functions for all possible cache tdb keys.
3575 ***********************************************************************/
3577 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3578 struct tdb_validation_status
*state
)
3580 struct cache_entry
*centry
;
3582 centry
= SMB_XMALLOC_P(struct cache_entry
);
3583 centry
->data
= (unsigned char *)smb_memdup(data
.dptr
, data
.dsize
);
3584 if (!centry
->data
) {
3588 centry
->len
= data
.dsize
;
3591 if (centry
->len
< 16) {
3592 /* huh? corrupt cache? */
3593 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3594 "(len < 16) ?\n", kstr
));
3595 centry_free(centry
);
3596 state
->bad_entry
= true;
3597 state
->success
= false;
3601 centry
->status
= NT_STATUS(centry_uint32(centry
));
3602 centry
->sequence_number
= centry_uint32(centry
);
3603 centry
->timeout
= centry_uint64_t(centry
);
3607 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3608 struct tdb_validation_status
*state
)
3610 if (dbuf
.dsize
!= 8) {
3611 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3612 keystr
, (unsigned int)dbuf
.dsize
));
3613 state
->bad_entry
= true;
3619 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3620 struct tdb_validation_status
*state
)
3622 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3627 (void)centry_uint32(centry
);
3628 if (NT_STATUS_IS_OK(centry
->status
)) {
3630 (void)centry_sid(centry
, &sid
);
3633 centry_free(centry
);
3635 if (!(state
->success
)) {
3638 DEBUG(10,("validate_ns: %s ok\n", keystr
));
3642 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3643 struct tdb_validation_status
*state
)
3645 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3650 if (NT_STATUS_IS_OK(centry
->status
)) {
3651 (void)centry_uint32(centry
);
3652 (void)centry_string(centry
, mem_ctx
);
3653 (void)centry_string(centry
, mem_ctx
);
3656 centry_free(centry
);
3658 if (!(state
->success
)) {
3661 DEBUG(10,("validate_sn: %s ok\n", keystr
));
3665 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3666 struct tdb_validation_status
*state
)
3668 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3675 (void)centry_string(centry
, mem_ctx
);
3676 (void)centry_string(centry
, mem_ctx
);
3677 (void)centry_string(centry
, mem_ctx
);
3678 (void)centry_string(centry
, mem_ctx
);
3679 (void)centry_string(centry
, mem_ctx
);
3680 (void)centry_uint32(centry
);
3681 (void)centry_uint32(centry
);
3682 (void)centry_string(centry
, mem_ctx
);
3683 (void)centry_sid(centry
, &sid
);
3684 (void)centry_sid(centry
, &sid
);
3686 centry_free(centry
);
3688 if (!(state
->success
)) {
3691 DEBUG(10,("validate_u: %s ok\n", keystr
));
3695 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3696 struct tdb_validation_status
*state
)
3698 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3704 (void)centry_nttime(centry
);
3705 (void)centry_nttime(centry
);
3706 (void)centry_uint16(centry
);
3708 centry_free(centry
);
3710 if (!(state
->success
)) {
3713 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3717 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3718 struct tdb_validation_status
*state
)
3720 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3726 (void)centry_uint16(centry
);
3727 (void)centry_uint16(centry
);
3728 (void)centry_uint32(centry
);
3729 (void)centry_nttime(centry
);
3730 (void)centry_nttime(centry
);
3732 centry_free(centry
);
3734 if (!(state
->success
)) {
3737 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3741 static int validate_cred(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
);
3750 (void)centry_time(centry
);
3751 (void)centry_hash16(centry
, mem_ctx
);
3753 /* We only have 17 bytes more data in the salted cred case. */
3754 if (centry
->len
- centry
->ofs
== 17) {
3755 (void)centry_hash16(centry
, mem_ctx
);
3758 centry_free(centry
);
3760 if (!(state
->success
)) {
3763 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3767 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3768 struct tdb_validation_status
*state
)
3770 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3771 int32_t num_entries
, i
;
3777 num_entries
= (int32_t)centry_uint32(centry
);
3779 for (i
=0; i
< num_entries
; i
++) {
3780 (void)centry_uint32(centry
);
3783 centry_free(centry
);
3785 if (!(state
->success
)) {
3788 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3792 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3793 struct tdb_validation_status
*state
)
3795 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3796 int32_t num_entries
, i
;
3802 num_entries
= centry_uint32(centry
);
3804 for (i
=0; i
< num_entries
; i
++) {
3805 (void)centry_string(centry
, mem_ctx
);
3806 (void)centry_string(centry
, mem_ctx
);
3807 (void)centry_uint32(centry
);
3810 centry_free(centry
);
3812 if (!(state
->success
)) {
3815 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3819 static int validate_ug(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_groups
, i
;
3829 num_groups
= centry_uint32(centry
);
3831 for (i
=0; i
< num_groups
; i
++) {
3833 centry_sid(centry
, &sid
);
3836 centry_free(centry
);
3838 if (!(state
->success
)) {
3841 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3845 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3846 struct tdb_validation_status
*state
)
3848 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3849 int32_t num_aliases
, i
;
3855 num_aliases
= centry_uint32(centry
);
3857 for (i
=0; i
< num_aliases
; i
++) {
3858 (void)centry_uint32(centry
);
3861 centry_free(centry
);
3863 if (!(state
->success
)) {
3866 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3870 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3871 struct tdb_validation_status
*state
)
3873 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3874 int32_t num_names
, i
;
3880 num_names
= centry_uint32(centry
);
3882 for (i
=0; i
< num_names
; i
++) {
3884 centry_sid(centry
, &sid
);
3885 (void)centry_string(centry
, mem_ctx
);
3886 (void)centry_uint32(centry
);
3889 centry_free(centry
);
3891 if (!(state
->success
)) {
3894 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3898 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3899 struct tdb_validation_status
*state
)
3901 /* Can't say anything about this other than must be nonzero. */
3902 if (dbuf
.dsize
== 0) {
3903 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3905 state
->bad_entry
= true;
3906 state
->success
= false;
3910 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3914 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3915 struct tdb_validation_status
*state
)
3917 /* Can't say anything about this other than must be nonzero. */
3918 if (dbuf
.dsize
== 0) {
3919 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3921 state
->bad_entry
= true;
3922 state
->success
= false;
3926 DEBUG(10,("validate_de: %s ok\n", keystr
));
3930 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3932 struct tdb_validation_status
*state
)
3934 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3940 (void)centry_string( centry
, mem_ctx
);
3942 centry_free(centry
);
3944 if (!(state
->success
)) {
3947 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3951 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3953 struct tdb_validation_status
*state
)
3955 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3961 (void)centry_string( centry
, mem_ctx
);
3963 centry_free(centry
);
3965 if (!(state
->success
)) {
3968 DBG_DEBUG("%s ok\n", keystr
);
3972 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3974 struct tdb_validation_status
*state
)
3976 if (dbuf
.dsize
== 0) {
3977 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3978 "key %s (len ==0) ?\n", keystr
));
3979 state
->bad_entry
= true;
3980 state
->success
= false;
3984 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3985 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3989 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3990 struct tdb_validation_status
*state
)
3992 if (dbuf
.dsize
!= 4) {
3993 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3994 keystr
, (unsigned int)dbuf
.dsize
));
3995 state
->bad_entry
= true;
3996 state
->success
= false;
3999 DEBUG(10,("validate_offline: %s ok\n", keystr
));
4003 static int validate_ndr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
4004 struct tdb_validation_status
*state
)
4007 * Ignore validation for now. The proper way to do this is with a
4008 * checksum. Just pure parsing does not really catch much.
4013 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
4014 struct tdb_validation_status
*state
)
4016 if (dbuf
.dsize
!= 4) {
4017 DEBUG(0, ("validate_cache_version: Corrupt cache for "
4018 "key %s (len %u != 4) ?\n",
4019 keystr
, (unsigned int)dbuf
.dsize
));
4020 state
->bad_entry
= true;
4021 state
->success
= false;
4025 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
4029 /***********************************************************************
4030 A list of all possible cache tdb keys with associated validation
4032 ***********************************************************************/
4034 struct key_val_struct
{
4035 const char *keyname
;
4036 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
4038 {"SEQNUM/", validate_seqnum
},
4039 {"NS/", validate_ns
},
4040 {"SN/", validate_sn
},
4042 {"LOC_POL/", validate_loc_pol
},
4043 {"PWD_POL/", validate_pwd_pol
},
4044 {"CRED/", validate_cred
},
4045 {"UL/", validate_ul
},
4046 {"GL/", validate_gl
},
4047 {"UG/", validate_ug
},
4048 {"UA", validate_ua
},
4049 {"GM/", validate_gm
},
4050 {"DR/", validate_dr
},
4051 {"DE/", validate_de
},
4052 {"TRUSTDOMCACHE/", validate_trustdomcache
},
4053 {"NSS/NA/", validate_nss_na
},
4054 {"NSS/AN/", validate_nss_an
},
4055 {"WINBINDD_OFFLINE", validate_offline
},
4056 {"NDR/", validate_ndr
},
4057 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
4061 /***********************************************************************
4062 Function to look at every entry in the tdb and validate it as far as
4064 ***********************************************************************/
4066 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
4069 unsigned int max_key_len
= 1024;
4070 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
4072 /* Paranoia check. */
4073 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0 ||
4074 strncmp("NDR/", (const char *)kbuf
.dptr
, 4) == 0) {
4075 max_key_len
= 1024 * 1024;
4077 if (kbuf
.dsize
> max_key_len
) {
4078 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4080 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
4084 for (i
= 0; key_val
[i
].keyname
; i
++) {
4085 size_t namelen
= strlen(key_val
[i
].keyname
);
4086 if (kbuf
.dsize
>= namelen
&& (
4087 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
4088 TALLOC_CTX
*mem_ctx
;
4092 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
4096 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
4097 keystr
[kbuf
.dsize
] = '\0';
4099 mem_ctx
= talloc_init("validate_ctx");
4105 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
4109 talloc_destroy(mem_ctx
);
4114 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4115 dump_data(0, (uint8_t *)kbuf
.dptr
, kbuf
.dsize
);
4116 DEBUG(0,("data :\n"));
4117 dump_data(0, (uint8_t *)dbuf
.dptr
, dbuf
.dsize
);
4118 v_state
->unknown_key
= true;
4119 v_state
->success
= false;
4120 return 1; /* terminate. */
4123 static void validate_panic(const char *const why
)
4125 DEBUG(0,("validating cache: would panic %s\n", why
));
4126 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4130 static int wbcache_update_centry_fn(TDB_CONTEXT
*tdb
,
4138 if (is_non_centry_key(key
)) {
4142 if (data
.dptr
== NULL
|| data
.dsize
== 0) {
4143 if (tdb_delete(tdb
, key
) < 0) {
4144 DEBUG(0, ("tdb_delete for [%s] failed!\n",
4150 /* add timeout to blob (uint64_t) */
4151 blob
.dsize
= data
.dsize
+ 8;
4153 blob
.dptr
= SMB_XMALLOC_ARRAY(uint8_t, blob
.dsize
);
4154 if (blob
.dptr
== NULL
) {
4157 memset(blob
.dptr
, 0, blob
.dsize
);
4159 /* copy status and seqnum */
4160 memcpy(blob
.dptr
, data
.dptr
, 8);
4163 ctimeout
= lp_winbind_cache_time() + time(NULL
);
4164 SBVAL(blob
.dptr
, 8, ctimeout
);
4167 memcpy(blob
.dptr
+ 16, data
.dptr
+ 8, data
.dsize
- 8);
4169 if (tdb_store(tdb
, key
, blob
, TDB_REPLACE
) < 0) {
4170 DEBUG(0, ("tdb_store to update [%s] failed!\n",
4172 SAFE_FREE(blob
.dptr
);
4176 SAFE_FREE(blob
.dptr
);
4180 static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT
*tdb
)
4184 DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
4186 rc
= tdb_traverse(tdb
, wbcache_update_centry_fn
, NULL
);
4194 /***********************************************************************
4195 Try and validate every entry in the winbindd cache. If we fail here,
4196 delete the cache tdb and return non-zero.
4197 ***********************************************************************/
4199 int winbindd_validate_cache(void)
4202 char *tdb_path
= NULL
;
4203 TDB_CONTEXT
*tdb
= NULL
;
4207 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4208 smb_panic_fn
= validate_panic
;
4210 tdb_path
= wcache_path();
4211 if (tdb_path
== NULL
) {
4215 tdb
= tdb_open_log(tdb_path
,
4216 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
4217 TDB_INCOMPATIBLE_HASH
|
4218 ( lp_winbind_offline_logon()
4220 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
4224 DEBUG(0, ("winbindd_validate_cache: "
4225 "error opening/initializing tdb\n"));
4229 /* Version check and upgrade code. */
4230 if (!tdb_fetch_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers_id
)) {
4231 DEBUG(10, ("Fresh database\n"));
4232 tdb_store_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
);
4233 vers_id
= WINBINDD_CACHE_VERSION
;
4236 if (vers_id
!= WINBINDD_CACHE_VERSION
) {
4237 if (vers_id
== WINBINDD_CACHE_VER1
) {
4238 ok
= wbcache_upgrade_v1_to_v2(tdb
);
4240 DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
4245 tdb_store_uint32(tdb
,
4246 WINBINDD_CACHE_VERSION_KEYSTR
,
4247 WINBINDD_CACHE_VERSION
);
4248 vers_id
= WINBINDD_CACHE_VER2
;
4254 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
4257 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4258 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
4263 TALLOC_FREE(tdb_path
);
4264 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4265 smb_panic_fn
= smb_panic
;
4269 /***********************************************************************
4270 Try and validate every entry in the winbindd cache.
4271 ***********************************************************************/
4273 int winbindd_validate_cache_nobackup(void)
4278 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4279 smb_panic_fn
= validate_panic
;
4281 tdb_path
= wcache_path();
4282 if (tdb_path
== NULL
) {
4283 goto err_panic_restore
;
4286 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
4287 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
4289 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
4293 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4297 TALLOC_FREE(tdb_path
);
4299 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4301 smb_panic_fn
= smb_panic
;
4305 bool winbindd_cache_validate_and_initialize(void)
4307 close_winbindd_cache();
4309 if (lp_winbind_offline_logon()) {
4310 if (winbindd_validate_cache() < 0) {
4311 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4312 "could be restored.\n"));
4316 return initialize_winbindd_cache();
4319 /*********************************************************************
4320 ********************************************************************/
4322 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
4323 struct winbindd_tdc_domain
**domains
,
4324 size_t *num_domains
)
4326 struct winbindd_tdc_domain
*list
= NULL
;
4328 bool set_only
= false;
4330 /* don't allow duplicates */
4335 for ( i
=0; i
< (*num_domains
); i
++ ) {
4336 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
4337 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4348 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, 1 );
4351 list
= talloc_realloc( *domains
, *domains
,
4352 struct winbindd_tdc_domain
,
4357 ZERO_STRUCT( list
[idx
] );
4363 list
[idx
].domain_name
= talloc_strdup(list
, new_dom
->name
);
4364 if (list
[idx
].domain_name
== NULL
) {
4367 if (new_dom
->alt_name
!= NULL
) {
4368 list
[idx
].dns_name
= talloc_strdup(list
, new_dom
->alt_name
);
4369 if (list
[idx
].dns_name
== NULL
) {
4374 if ( !is_null_sid( &new_dom
->sid
) ) {
4375 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
4377 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
4380 if ( new_dom
->domain_flags
!= 0x0 )
4381 list
[idx
].trust_flags
= new_dom
->domain_flags
;
4383 if ( new_dom
->domain_type
!= 0x0 )
4384 list
[idx
].trust_type
= new_dom
->domain_type
;
4386 if ( new_dom
->domain_trust_attribs
!= 0x0 )
4387 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
4391 *num_domains
= idx
+ 1;
4397 /*********************************************************************
4398 ********************************************************************/
4400 static TDB_DATA
make_tdc_key( const char *domain_name
)
4402 char *keystr
= NULL
;
4403 TDB_DATA key
= { NULL
, 0 };
4405 if ( !domain_name
) {
4406 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4410 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
4413 key
= string_term_tdb_data(keystr
);
4418 /*********************************************************************
4419 ********************************************************************/
4421 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
4423 unsigned char **buf
)
4425 unsigned char *buffer
= NULL
;
4430 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4438 /* Store the number of array items first */
4439 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
4442 /* now pack each domain trust record */
4443 for ( i
=0; i
<num_domains
; i
++ ) {
4448 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4449 domains
[i
].domain_name
,
4450 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
4453 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
4454 domains
[i
].domain_name
,
4455 domains
[i
].dns_name
? domains
[i
].dns_name
: "",
4456 sid_to_fstring(tmp
, &domains
[i
].sid
),
4457 domains
[i
].trust_flags
,
4458 domains
[i
].trust_attribs
,
4459 domains
[i
].trust_type
);
4462 if ( buflen
< len
) {
4464 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
4465 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4479 /*********************************************************************
4480 ********************************************************************/
4482 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
4483 struct winbindd_tdc_domain
**domains
)
4485 fstring domain_name
, dns_name
, sid_string
;
4486 uint32_t type
, attribs
, flags
;
4490 struct winbindd_tdc_domain
*list
= NULL
;
4492 /* get the number of domains */
4493 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
4495 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4499 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, num_domains
);
4501 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4505 for ( i
=0; i
<num_domains
; i
++ ) {
4508 this_len
= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
4516 if ( this_len
== -1 ) {
4517 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4518 TALLOC_FREE( list
);
4523 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4524 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4525 domain_name
, dns_name
, sid_string
,
4526 flags
, attribs
, type
));
4528 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
4529 list
[i
].dns_name
= NULL
;
4530 if (dns_name
[0] != '\0') {
4531 list
[i
].dns_name
= talloc_strdup(list
, dns_name
);
4533 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
4534 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4537 list
[i
].trust_flags
= flags
;
4538 list
[i
].trust_attribs
= attribs
;
4539 list
[i
].trust_type
= type
;
4547 /*********************************************************************
4548 ********************************************************************/
4550 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
4552 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4553 TDB_DATA data
= { NULL
, 0 };
4559 /* See if we were asked to delete the cache entry */
4562 ret
= tdb_delete( wcache
->tdb
, key
);
4566 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4573 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4576 SAFE_FREE( data
.dptr
);
4577 SAFE_FREE( key
.dptr
);
4579 return ( ret
== 0 );
4582 /*********************************************************************
4583 ********************************************************************/
4585 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4587 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4588 TDB_DATA data
= { NULL
, 0 };
4596 data
= tdb_fetch( wcache
->tdb
, key
);
4598 SAFE_FREE( key
.dptr
);
4603 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4605 SAFE_FREE( data
.dptr
);
4613 /*********************************************************************
4614 ********************************************************************/
4616 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4618 struct winbindd_tdc_domain
*dom_list
= NULL
;
4619 size_t num_domains
= 0;
4622 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4623 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4624 domain
->name
, domain
->alt_name
,
4625 sid_string_dbg(&domain
->sid
),
4626 domain
->domain_flags
,
4627 domain
->domain_trust_attribs
,
4628 domain
->domain_type
));
4630 if ( !init_wcache() ) {
4634 /* fetch the list */
4636 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4638 /* add the new domain */
4640 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4644 /* pack the domain */
4646 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4654 TALLOC_FREE( dom_list
);
4659 static struct winbindd_tdc_domain
*wcache_tdc_dup_domain(
4660 TALLOC_CTX
*mem_ctx
, const struct winbindd_tdc_domain
*src
)
4662 struct winbindd_tdc_domain
*dst
;
4664 dst
= talloc(mem_ctx
, struct winbindd_tdc_domain
);
4668 dst
->domain_name
= talloc_strdup(dst
, src
->domain_name
);
4669 if (dst
->domain_name
== NULL
) {
4673 dst
->dns_name
= NULL
;
4674 if (src
->dns_name
!= NULL
) {
4675 dst
->dns_name
= talloc_strdup(dst
, src
->dns_name
);
4676 if (dst
->dns_name
== NULL
) {
4681 sid_copy(&dst
->sid
, &src
->sid
);
4682 dst
->trust_flags
= src
->trust_flags
;
4683 dst
->trust_type
= src
->trust_type
;
4684 dst
->trust_attribs
= src
->trust_attribs
;
4691 /*********************************************************************
4692 ********************************************************************/
4694 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4696 struct winbindd_tdc_domain
*dom_list
= NULL
;
4697 size_t num_domains
= 0;
4699 struct winbindd_tdc_domain
*d
= NULL
;
4701 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4703 if ( !init_wcache() ) {
4707 /* fetch the list */
4709 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4711 for ( i
=0; i
<num_domains
; i
++ ) {
4712 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4713 strequal(name
, dom_list
[i
].dns_name
) )
4715 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4718 d
= wcache_tdc_dup_domain(ctx
, &dom_list
[i
]);
4723 TALLOC_FREE( dom_list
);
4728 /*********************************************************************
4729 ********************************************************************/
4731 void wcache_tdc_clear( void )
4733 if ( !init_wcache() )
4736 wcache_tdc_store_list( NULL
, 0 );
4741 static bool wcache_ndr_key(TALLOC_CTX
*mem_ctx
, const char *domain_name
,
4742 uint32_t opnum
, const DATA_BLOB
*req
,
4748 key
= talloc_asprintf(mem_ctx
, "NDR/%s/%d/", domain_name
, (int)opnum
);
4752 keylen
= talloc_get_size(key
) - 1;
4754 key
= talloc_realloc(mem_ctx
, key
, char, keylen
+ req
->length
);
4758 memcpy(key
+ keylen
, req
->data
, req
->length
);
4760 pkey
->dptr
= (uint8_t *)key
;
4761 pkey
->dsize
= talloc_get_size(key
);
4765 static bool wcache_opnum_cacheable(uint32_t opnum
)
4768 case NDR_WBINT_PING
:
4769 case NDR_WBINT_QUERYSEQUENCENUMBER
:
4770 case NDR_WBINT_ALLOCATEUID
:
4771 case NDR_WBINT_ALLOCATEGID
:
4772 case NDR_WBINT_CHECKMACHINEACCOUNT
:
4773 case NDR_WBINT_CHANGEMACHINEACCOUNT
:
4774 case NDR_WBINT_PINGDC
:
4780 bool wcache_fetch_ndr(TALLOC_CTX
*mem_ctx
, struct winbindd_domain
*domain
,
4781 uint32_t opnum
, const DATA_BLOB
*req
, DATA_BLOB
*resp
)
4786 if (!wcache_opnum_cacheable(opnum
) ||
4787 is_my_own_sam_domain(domain
) ||
4788 is_builtin_domain(domain
)) {
4792 if (wcache
->tdb
== NULL
) {
4796 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4799 data
= tdb_fetch(wcache
->tdb
, key
);
4800 TALLOC_FREE(key
.dptr
);
4802 if (data
.dptr
== NULL
) {
4805 if (data
.dsize
< 12) {
4809 if (!is_domain_offline(domain
)) {
4810 uint32_t entry_seqnum
, dom_seqnum
, last_check
;
4811 uint64_t entry_timeout
;
4813 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
,
4817 entry_seqnum
= IVAL(data
.dptr
, 0);
4818 if (entry_seqnum
!= dom_seqnum
) {
4819 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4820 (int)entry_seqnum
));
4823 entry_timeout
= BVAL(data
.dptr
, 4);
4824 if (time(NULL
) > entry_timeout
) {
4825 DEBUG(10, ("Entry has timed out\n"));
4830 resp
->data
= (uint8_t *)talloc_memdup(mem_ctx
, data
.dptr
+ 12,
4832 if (resp
->data
== NULL
) {
4833 DEBUG(10, ("talloc failed\n"));
4836 resp
->length
= data
.dsize
- 12;
4840 SAFE_FREE(data
.dptr
);
4844 void wcache_store_ndr(struct winbindd_domain
*domain
, uint32_t opnum
,
4845 const DATA_BLOB
*req
, const DATA_BLOB
*resp
)
4848 uint32_t dom_seqnum
, last_check
;
4851 if (!wcache_opnum_cacheable(opnum
) ||
4852 is_my_own_sam_domain(domain
) ||
4853 is_builtin_domain(domain
)) {
4857 if (wcache
->tdb
== NULL
) {
4861 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
, &last_check
)) {
4862 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4867 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4871 timeout
= time(NULL
) + lp_winbind_cache_time();
4873 data
.dsize
= resp
->length
+ 12;
4874 data
.dptr
= talloc_array(key
.dptr
, uint8_t, data
.dsize
);
4875 if (data
.dptr
== NULL
) {
4879 SIVAL(data
.dptr
, 0, dom_seqnum
);
4880 SBVAL(data
.dptr
, 4, timeout
);
4881 memcpy(data
.dptr
+ 12, resp
->data
, resp
->length
);
4883 tdb_store(wcache
->tdb
, key
, data
, 0);
4886 TALLOC_FREE(key
.dptr
);