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 NTSTATUS
wcache_lookup_useraliases(struct winbindd_domain
*domain
,
2476 TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2477 const struct dom_sid
*sids
,
2478 uint32_t *pnum_aliases
, uint32_t **paliases
)
2480 struct winbind_cache
*cache
= get_cache(domain
);
2481 struct cache_entry
*centry
= NULL
;
2482 uint32_t i
, num_aliases
;
2487 if (cache
->tdb
== NULL
) {
2488 return NT_STATUS_NOT_FOUND
;
2491 if (num_sids
== 0) {
2494 return NT_STATUS_OK
;
2497 /* We need to cache indexed by the whole list of SIDs, the aliases
2498 * resulting might come from any of the SIDs. */
2500 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2501 if (sidlist
== NULL
) {
2502 return NT_STATUS_NO_MEMORY
;
2505 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2506 TALLOC_FREE(sidlist
);
2507 if (centry
== NULL
) {
2508 return NT_STATUS_NOT_FOUND
;
2511 num_aliases
= centry_uint32(centry
);
2512 aliases
= talloc_array(mem_ctx
, uint32_t, num_aliases
);
2513 if (aliases
== NULL
) {
2514 centry_free(centry
);
2515 return NT_STATUS_NO_MEMORY
;
2518 for (i
=0; i
<num_aliases
; i
++) {
2519 aliases
[i
] = centry_uint32(centry
);
2522 status
= centry
->status
;
2524 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2525 "status %s\n", domain
->name
, nt_errstr(status
)));
2527 centry_free(centry
);
2529 *pnum_aliases
= num_aliases
;
2530 *paliases
= aliases
;
2535 NTSTATUS
wb_cache_lookup_useraliases(struct winbindd_domain
*domain
,
2536 TALLOC_CTX
*mem_ctx
,
2538 const struct dom_sid
*sids
,
2539 uint32_t *num_aliases
,
2540 uint32_t **alias_rids
)
2542 struct cache_entry
*centry
= NULL
;
2548 old_status
= domain
->online
;
2549 status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
2550 num_aliases
, alias_rids
);
2551 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2556 (*alias_rids
) = NULL
;
2558 if (!NT_STATUS_IS_OK(domain
->last_status
))
2559 return domain
->last_status
;
2561 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2562 "for domain %s\n", domain
->name
));
2564 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2565 if (sidlist
== NULL
) {
2566 return NT_STATUS_NO_MEMORY
;
2569 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2571 num_aliases
, alias_rids
);
2573 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2574 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2575 if (!domain
->internal
&& old_status
) {
2576 set_domain_offline(domain
);
2578 if (!domain
->internal
&&
2581 NTSTATUS cache_status
;
2582 cache_status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
,
2583 sids
, num_aliases
, alias_rids
);
2584 return cache_status
;
2588 refresh_sequence_number(domain
);
2589 if (!NT_STATUS_IS_OK(status
)) {
2592 centry
= centry_start(domain
, status
);
2595 centry_put_uint32(centry
, *num_aliases
);
2596 for (i
=0; i
<(*num_aliases
); i
++)
2597 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2598 centry_end(centry
, "UA%s", sidlist
);
2599 centry_free(centry
);
2605 static NTSTATUS
wcache_lookup_groupmem(struct winbindd_domain
*domain
,
2606 TALLOC_CTX
*mem_ctx
,
2607 const struct dom_sid
*group_sid
,
2608 uint32_t *num_names
,
2609 struct dom_sid
**sid_mem
, char ***names
,
2610 uint32_t **name_types
)
2612 struct winbind_cache
*cache
= get_cache(domain
);
2613 struct cache_entry
*centry
= NULL
;
2618 if (cache
->tdb
== NULL
) {
2619 return NT_STATUS_NOT_FOUND
;
2622 sid_string
= sid_string_tos(group_sid
);
2623 if (sid_string
== NULL
) {
2624 return NT_STATUS_NO_MEMORY
;
2627 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_string
);
2628 TALLOC_FREE(sid_string
);
2629 if (centry
== NULL
) {
2630 return NT_STATUS_NOT_FOUND
;
2637 *num_names
= centry_uint32(centry
);
2638 if (*num_names
== 0) {
2639 centry_free(centry
);
2640 return NT_STATUS_OK
;
2643 *sid_mem
= talloc_array(mem_ctx
, struct dom_sid
, *num_names
);
2644 *names
= talloc_array(mem_ctx
, char *, *num_names
);
2645 *name_types
= talloc_array(mem_ctx
, uint32_t, *num_names
);
2647 if ((*sid_mem
== NULL
) || (*names
== NULL
) || (*name_types
== NULL
)) {
2648 TALLOC_FREE(*sid_mem
);
2649 TALLOC_FREE(*names
);
2650 TALLOC_FREE(*name_types
);
2651 centry_free(centry
);
2652 return NT_STATUS_NO_MEMORY
;
2655 for (i
=0; i
<(*num_names
); i
++) {
2656 centry_sid(centry
, &(*sid_mem
)[i
]);
2657 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2658 (*name_types
)[i
] = centry_uint32(centry
);
2661 status
= centry
->status
;
2663 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2664 "status: %s\n", domain
->name
, nt_errstr(status
)));
2666 centry_free(centry
);
2670 NTSTATUS
wb_cache_lookup_groupmem(struct winbindd_domain
*domain
,
2671 TALLOC_CTX
*mem_ctx
,
2672 const struct dom_sid
*group_sid
,
2673 enum lsa_SidType type
,
2674 uint32_t *num_names
,
2675 struct dom_sid
**sid_mem
,
2677 uint32_t **name_types
)
2679 struct cache_entry
*centry
= NULL
;
2685 old_status
= domain
->online
;
2686 status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2687 sid_mem
, names
, name_types
);
2688 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2695 (*name_types
) = NULL
;
2697 /* Return status value returned by seq number check */
2699 if (!NT_STATUS_IS_OK(domain
->last_status
))
2700 return domain
->last_status
;
2702 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2705 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
,
2707 sid_mem
, names
, name_types
);
2709 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2710 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2711 if (!domain
->internal
&& old_status
) {
2712 set_domain_offline(domain
);
2714 if (!domain
->internal
&&
2717 NTSTATUS cache_status
;
2718 cache_status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
,
2719 num_names
, sid_mem
, names
,
2721 return cache_status
;
2725 refresh_sequence_number(domain
);
2726 if (!NT_STATUS_IS_OK(status
)) {
2729 centry
= centry_start(domain
, status
);
2732 centry_put_uint32(centry
, *num_names
);
2733 for (i
=0; i
<(*num_names
); i
++) {
2734 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2735 centry_put_string(centry
, (*names
)[i
]);
2736 centry_put_uint32(centry
, (*name_types
)[i
]);
2738 centry_end(centry
, "GM/%s", sid_to_fstring(sid_string
, group_sid
));
2739 centry_free(centry
);
2745 /* find the sequence number for a domain */
2746 NTSTATUS
wb_cache_sequence_number(struct winbindd_domain
*domain
,
2749 refresh_sequence_number(domain
);
2751 *seq
= domain
->sequence_number
;
2753 return NT_STATUS_OK
;
2756 /* enumerate trusted domains
2757 * (we need to have the list of trustdoms in the cache when we go offline) -
2759 NTSTATUS
wb_cache_trusted_domains(struct winbindd_domain
*domain
,
2760 TALLOC_CTX
*mem_ctx
,
2761 struct netr_DomainTrustList
*trusts
)
2764 struct winbind_cache
*cache
;
2765 struct winbindd_tdc_domain
*dom_list
= NULL
;
2766 size_t num_domains
= 0;
2767 bool retval
= false;
2771 old_status
= domain
->online
;
2773 trusts
->array
= NULL
;
2775 cache
= get_cache(domain
);
2776 if (!cache
|| !cache
->tdb
) {
2780 if (domain
->online
) {
2784 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2785 if (!retval
|| !num_domains
|| !dom_list
) {
2786 TALLOC_FREE(dom_list
);
2791 trusts
->array
= talloc_zero_array(mem_ctx
, struct netr_DomainTrust
, num_domains
);
2792 if (!trusts
->array
) {
2793 TALLOC_FREE(dom_list
);
2794 return NT_STATUS_NO_MEMORY
;
2797 for (i
= 0; i
< num_domains
; i
++) {
2798 struct netr_DomainTrust
*trust
;
2799 struct dom_sid
*sid
;
2800 struct winbindd_domain
*dom
;
2802 dom
= find_domain_from_name_noinit(dom_list
[i
].domain_name
);
2803 if (dom
&& dom
->internal
) {
2807 trust
= &trusts
->array
[trusts
->count
];
2808 trust
->netbios_name
= talloc_strdup(trusts
->array
, dom_list
[i
].domain_name
);
2809 trust
->dns_name
= talloc_strdup(trusts
->array
, dom_list
[i
].dns_name
);
2810 sid
= talloc(trusts
->array
, struct dom_sid
);
2811 if (!trust
->netbios_name
|| !trust
->dns_name
||
2813 TALLOC_FREE(dom_list
);
2814 TALLOC_FREE(trusts
->array
);
2815 return NT_STATUS_NO_MEMORY
;
2818 trust
->trust_flags
= dom_list
[i
].trust_flags
;
2819 trust
->trust_attributes
= dom_list
[i
].trust_attribs
;
2820 trust
->trust_type
= dom_list
[i
].trust_type
;
2821 sid_copy(sid
, &dom_list
[i
].sid
);
2826 TALLOC_FREE(dom_list
);
2827 return NT_STATUS_OK
;
2830 /* Return status value returned by seq number check */
2832 if (!NT_STATUS_IS_OK(domain
->last_status
))
2833 return domain
->last_status
;
2835 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2838 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, trusts
);
2840 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2841 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2842 if (!domain
->internal
&& old_status
) {
2843 set_domain_offline(domain
);
2845 if (!domain
->internal
&&
2848 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2849 if (retval
&& num_domains
&& dom_list
) {
2850 TALLOC_FREE(trusts
->array
);
2852 goto do_fetch_cache
;
2856 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2857 * so that the generic centry handling still applies correctly -
2860 if (!NT_STATUS_IS_ERR(status
)) {
2861 status
= NT_STATUS_OK
;
2866 /* get lockout policy */
2867 NTSTATUS
wb_cache_lockout_policy(struct winbindd_domain
*domain
,
2868 TALLOC_CTX
*mem_ctx
,
2869 struct samr_DomInfo12
*policy
)
2871 struct winbind_cache
*cache
= get_cache(domain
);
2872 struct cache_entry
*centry
= NULL
;
2876 old_status
= domain
->online
;
2880 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2886 policy
->lockout_duration
= centry_nttime(centry
);
2887 policy
->lockout_window
= centry_nttime(centry
);
2888 policy
->lockout_threshold
= centry_uint16(centry
);
2890 status
= centry
->status
;
2892 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2893 domain
->name
, nt_errstr(status
) ));
2895 centry_free(centry
);
2899 ZERO_STRUCTP(policy
);
2901 /* Return status value returned by seq number check */
2903 if (!NT_STATUS_IS_OK(domain
->last_status
))
2904 return domain
->last_status
;
2906 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2909 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2911 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2912 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2913 if (!domain
->internal
&& old_status
) {
2914 set_domain_offline(domain
);
2917 !domain
->internal
&&
2920 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2922 goto do_fetch_cache
;
2927 refresh_sequence_number(domain
);
2928 if (!NT_STATUS_IS_OK(status
)) {
2931 wcache_save_lockout_policy(domain
, status
, policy
);
2936 /* get password policy */
2937 NTSTATUS
wb_cache_password_policy(struct winbindd_domain
*domain
,
2938 TALLOC_CTX
*mem_ctx
,
2939 struct samr_DomInfo1
*policy
)
2941 struct winbind_cache
*cache
= get_cache(domain
);
2942 struct cache_entry
*centry
= NULL
;
2946 old_status
= domain
->online
;
2950 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2956 policy
->min_password_length
= centry_uint16(centry
);
2957 policy
->password_history_length
= centry_uint16(centry
);
2958 policy
->password_properties
= centry_uint32(centry
);
2959 policy
->max_password_age
= centry_nttime(centry
);
2960 policy
->min_password_age
= centry_nttime(centry
);
2962 status
= centry
->status
;
2964 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2965 domain
->name
, nt_errstr(status
) ));
2967 centry_free(centry
);
2971 ZERO_STRUCTP(policy
);
2973 /* Return status value returned by seq number check */
2975 if (!NT_STATUS_IS_OK(domain
->last_status
))
2976 return domain
->last_status
;
2978 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2981 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
2983 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2984 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2985 if (!domain
->internal
&& old_status
) {
2986 set_domain_offline(domain
);
2989 !domain
->internal
&&
2992 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2994 goto do_fetch_cache
;
2999 refresh_sequence_number(domain
);
3000 if (!NT_STATUS_IS_OK(status
)) {
3003 wcache_save_password_policy(domain
, status
, policy
);
3009 /* Invalidate cached user and group lists coherently */
3011 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3014 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
3015 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
3016 tdb_delete(the_tdb
, kbuf
);
3021 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3023 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
3024 const struct dom_sid
*sid
)
3026 fstring key_str
, sid_string
;
3027 struct winbind_cache
*cache
;
3029 /* don't clear cached U/SID and UG/SID entries when we want to logon
3032 if (lp_winbind_offline_logon()) {
3039 cache
= get_cache(domain
);
3045 /* Clear U/SID cache entry */
3046 fstr_sprintf(key_str
, "U/%s", sid_to_fstring(sid_string
, sid
));
3047 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3048 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3050 /* Clear UG/SID cache entry */
3051 fstr_sprintf(key_str
, "UG/%s", sid_to_fstring(sid_string
, sid
));
3052 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3053 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3055 /* Samba/winbindd never needs this. */
3056 netsamlogon_clear_cached_user(sid
);
3059 bool wcache_invalidate_cache(void)
3061 struct winbindd_domain
*domain
;
3063 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3064 struct winbind_cache
*cache
= get_cache(domain
);
3066 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3067 "entries for %s\n", domain
->name
));
3070 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3079 bool wcache_invalidate_cache_noinit(void)
3081 struct winbindd_domain
*domain
;
3083 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3084 struct winbind_cache
*cache
;
3086 /* Skip uninitialized domains. */
3087 if (!domain
->initialized
&& !domain
->internal
) {
3091 cache
= get_cache(domain
);
3093 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3094 "entries for %s\n", domain
->name
));
3097 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3099 * Flushing cache has nothing to with domains.
3100 * return here if we successfully flushed once.
3101 * To avoid unnecessary traversing the cache.
3112 bool init_wcache(void)
3116 if (wcache
== NULL
) {
3117 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
3118 ZERO_STRUCTP(wcache
);
3121 if (wcache
->tdb
!= NULL
)
3124 db_path
= wcache_path();
3125 if (db_path
== NULL
) {
3129 /* when working offline we must not clear the cache on restart */
3130 wcache
->tdb
= tdb_open_log(db_path
,
3131 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3132 TDB_INCOMPATIBLE_HASH
|
3133 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3134 O_RDWR
|O_CREAT
, 0600);
3135 TALLOC_FREE(db_path
);
3136 if (wcache
->tdb
== NULL
) {
3137 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3144 /************************************************************************
3145 This is called by the parent to initialize the cache file.
3146 We don't need sophisticated locking here as we know we're the
3148 ************************************************************************/
3150 bool initialize_winbindd_cache(void)
3152 bool cache_bad
= true;
3155 if (!init_wcache()) {
3156 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3160 /* Check version number. */
3161 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
3162 vers
== WINBINDD_CACHE_VERSION
) {
3169 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3170 "and re-creating with version number %d\n",
3171 WINBINDD_CACHE_VERSION
));
3173 tdb_close(wcache
->tdb
);
3176 db_path
= wcache_path();
3177 if (db_path
== NULL
) {
3181 if (unlink(db_path
) == -1) {
3182 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3185 TALLOC_FREE(db_path
);
3188 TALLOC_FREE(db_path
);
3189 if (!init_wcache()) {
3190 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3191 "init_wcache failed.\n"));
3195 /* Write the version. */
3196 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
3197 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3198 tdb_errorstr(wcache
->tdb
) ));
3203 tdb_close(wcache
->tdb
);
3208 void close_winbindd_cache(void)
3214 tdb_close(wcache
->tdb
);
3219 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*sid
,
3220 char **domain_name
, char **name
,
3221 enum lsa_SidType
*type
)
3223 struct winbindd_domain
*domain
;
3226 domain
= find_lookup_domain_from_sid(sid
);
3227 if (domain
== NULL
) {
3230 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
3232 return NT_STATUS_IS_OK(status
);
3235 bool lookup_cached_name(const char *domain_name
,
3237 struct dom_sid
*sid
,
3238 enum lsa_SidType
*type
)
3240 struct winbindd_domain
*domain
;
3242 bool original_online_state
;
3244 domain
= find_lookup_domain_from_name(domain_name
);
3245 if (domain
== NULL
) {
3249 /* If we are doing a cached logon, temporarily set the domain
3250 offline so the cache won't expire the entry */
3252 original_online_state
= domain
->online
;
3253 domain
->online
= false;
3254 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
3255 domain
->online
= original_online_state
;
3257 return NT_STATUS_IS_OK(status
);
3261 * Cache a name to sid without checking the sequence number.
3262 * Used when caching from a trusted PAC.
3265 void cache_name2sid_trusted(struct winbindd_domain
*domain
,
3266 const char *domain_name
,
3268 enum lsa_SidType type
,
3269 const struct dom_sid
*sid
)
3272 * Ensure we store the mapping with the
3273 * existing sequence number from the cache.
3276 (void)fetch_cache_seqnum(domain
, time(NULL
));
3277 wcache_save_name_to_sid(domain
,
3285 void cache_name2sid(struct winbindd_domain
*domain
,
3286 const char *domain_name
, const char *name
,
3287 enum lsa_SidType type
, const struct dom_sid
*sid
)
3289 refresh_sequence_number(domain
);
3290 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
3295 * The original idea that this cache only contains centries has
3296 * been blurred - now other stuff gets put in here. Ensure we
3297 * ignore these things on cleanup.
3300 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
3301 TDB_DATA dbuf
, void *state
)
3303 struct cache_entry
*centry
;
3305 if (is_non_centry_key(kbuf
)) {
3309 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
3314 if (!NT_STATUS_IS_OK(centry
->status
)) {
3315 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
3316 tdb_delete(the_tdb
, kbuf
);
3319 centry_free(centry
);
3323 /* flush the cache */
3324 static void wcache_flush_cache(void)
3331 tdb_close(wcache
->tdb
);
3334 if (!winbindd_use_cache()) {
3338 db_path
= wcache_path();
3339 if (db_path
== NULL
) {
3343 /* when working offline we must not clear the cache on restart */
3344 wcache
->tdb
= tdb_open_log(db_path
,
3345 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3346 TDB_INCOMPATIBLE_HASH
|
3347 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3348 O_RDWR
|O_CREAT
, 0600);
3349 TALLOC_FREE(db_path
);
3351 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3355 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
3357 DEBUG(10,("wcache_flush_cache success\n"));
3360 /* Count cached creds */
3362 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3365 int *cred_count
= (int*)state
;
3367 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3373 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
3375 struct winbind_cache
*cache
= get_cache(domain
);
3380 return NT_STATUS_INTERNAL_DB_ERROR
;
3383 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
3385 return NT_STATUS_OK
;
3389 struct cred_list
*prev
, *next
;
3394 static struct cred_list
*wcache_cred_list
;
3396 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3399 struct cred_list
*cred
;
3401 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3403 cred
= SMB_MALLOC_P(struct cred_list
);
3405 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3411 /* save a copy of the key */
3413 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
3414 DLIST_ADD(wcache_cred_list
, cred
);
3420 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
3422 struct winbind_cache
*cache
= get_cache(domain
);
3425 struct cred_list
*cred
, *next
, *oldest
= NULL
;
3428 return NT_STATUS_INTERNAL_DB_ERROR
;
3431 /* we possibly already have an entry */
3432 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
3434 fstring key_str
, tmp
;
3436 DEBUG(11,("we already have an entry, deleting that\n"));
3438 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
3440 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3442 return NT_STATUS_OK
;
3445 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
3447 return NT_STATUS_OK
;
3448 } else if ((ret
< 0) || (wcache_cred_list
== NULL
)) {
3449 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3452 ZERO_STRUCTP(oldest
);
3454 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
3459 data
= tdb_fetch(cache
->tdb
, string_tdb_data(cred
->name
));
3461 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3463 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3467 t
= IVAL(data
.dptr
, 0);
3468 SAFE_FREE(data
.dptr
);
3471 oldest
= SMB_MALLOC_P(struct cred_list
);
3472 if (oldest
== NULL
) {
3473 status
= NT_STATUS_NO_MEMORY
;
3477 fstrcpy(oldest
->name
, cred
->name
);
3478 oldest
->created
= t
;
3482 if (t
< oldest
->created
) {
3483 fstrcpy(oldest
->name
, cred
->name
);
3484 oldest
->created
= t
;
3488 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3489 status
= NT_STATUS_OK
;
3491 status
= NT_STATUS_UNSUCCESSFUL
;
3494 for (cred
= wcache_cred_list
; cred
; cred
= next
) {
3496 DLIST_REMOVE(wcache_cred_list
, cred
);
3504 /* Change the global online/offline state. */
3505 bool set_global_winbindd_state_offline(void)
3509 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3511 /* Only go offline if someone has created
3512 the key "WINBINDD_OFFLINE" in the cache tdb. */
3514 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3515 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3519 if (!lp_winbind_offline_logon()) {
3520 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3524 if (global_winbindd_offline_state
) {
3525 /* Already offline. */
3529 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
3531 if (!data
.dptr
|| data
.dsize
!= 4) {
3532 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3533 SAFE_FREE(data
.dptr
);
3536 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3537 global_winbindd_offline_state
= true;
3538 SAFE_FREE(data
.dptr
);
3543 void set_global_winbindd_state_online(void)
3545 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3547 if (!lp_winbind_offline_logon()) {
3548 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3552 if (!global_winbindd_offline_state
) {
3553 /* Already online. */
3556 global_winbindd_offline_state
= false;
3562 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3563 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3566 bool get_global_winbindd_state_offline(void)
3568 return global_winbindd_offline_state
;
3571 /***********************************************************************
3572 Validate functions for all possible cache tdb keys.
3573 ***********************************************************************/
3575 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3576 struct tdb_validation_status
*state
)
3578 struct cache_entry
*centry
;
3580 centry
= SMB_XMALLOC_P(struct cache_entry
);
3581 centry
->data
= (unsigned char *)smb_memdup(data
.dptr
, data
.dsize
);
3582 if (!centry
->data
) {
3586 centry
->len
= data
.dsize
;
3589 if (centry
->len
< 16) {
3590 /* huh? corrupt cache? */
3591 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3592 "(len < 16) ?\n", kstr
));
3593 centry_free(centry
);
3594 state
->bad_entry
= true;
3595 state
->success
= false;
3599 centry
->status
= NT_STATUS(centry_uint32(centry
));
3600 centry
->sequence_number
= centry_uint32(centry
);
3601 centry
->timeout
= centry_uint64_t(centry
);
3605 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3606 struct tdb_validation_status
*state
)
3608 if (dbuf
.dsize
!= 8) {
3609 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3610 keystr
, (unsigned int)dbuf
.dsize
));
3611 state
->bad_entry
= true;
3617 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3618 struct tdb_validation_status
*state
)
3620 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3625 (void)centry_uint32(centry
);
3626 if (NT_STATUS_IS_OK(centry
->status
)) {
3628 (void)centry_sid(centry
, &sid
);
3631 centry_free(centry
);
3633 if (!(state
->success
)) {
3636 DEBUG(10,("validate_ns: %s ok\n", keystr
));
3640 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3641 struct tdb_validation_status
*state
)
3643 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3648 if (NT_STATUS_IS_OK(centry
->status
)) {
3649 (void)centry_uint32(centry
);
3650 (void)centry_string(centry
, mem_ctx
);
3651 (void)centry_string(centry
, mem_ctx
);
3654 centry_free(centry
);
3656 if (!(state
->success
)) {
3659 DEBUG(10,("validate_sn: %s ok\n", keystr
));
3663 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3664 struct tdb_validation_status
*state
)
3666 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3673 (void)centry_string(centry
, mem_ctx
);
3674 (void)centry_string(centry
, mem_ctx
);
3675 (void)centry_string(centry
, mem_ctx
);
3676 (void)centry_string(centry
, mem_ctx
);
3677 (void)centry_string(centry
, mem_ctx
);
3678 (void)centry_uint32(centry
);
3679 (void)centry_uint32(centry
);
3680 (void)centry_string(centry
, mem_ctx
);
3681 (void)centry_sid(centry
, &sid
);
3682 (void)centry_sid(centry
, &sid
);
3684 centry_free(centry
);
3686 if (!(state
->success
)) {
3689 DEBUG(10,("validate_u: %s ok\n", keystr
));
3693 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3694 struct tdb_validation_status
*state
)
3696 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3702 (void)centry_nttime(centry
);
3703 (void)centry_nttime(centry
);
3704 (void)centry_uint16(centry
);
3706 centry_free(centry
);
3708 if (!(state
->success
)) {
3711 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3715 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3716 struct tdb_validation_status
*state
)
3718 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3724 (void)centry_uint16(centry
);
3725 (void)centry_uint16(centry
);
3726 (void)centry_uint32(centry
);
3727 (void)centry_nttime(centry
);
3728 (void)centry_nttime(centry
);
3730 centry_free(centry
);
3732 if (!(state
->success
)) {
3735 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3739 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3740 struct tdb_validation_status
*state
)
3742 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3748 (void)centry_time(centry
);
3749 (void)centry_hash16(centry
, mem_ctx
);
3751 /* We only have 17 bytes more data in the salted cred case. */
3752 if (centry
->len
- centry
->ofs
== 17) {
3753 (void)centry_hash16(centry
, mem_ctx
);
3756 centry_free(centry
);
3758 if (!(state
->success
)) {
3761 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3765 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3766 struct tdb_validation_status
*state
)
3768 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3769 int32_t num_entries
, i
;
3775 num_entries
= (int32_t)centry_uint32(centry
);
3777 for (i
=0; i
< num_entries
; i
++) {
3778 (void)centry_uint32(centry
);
3781 centry_free(centry
);
3783 if (!(state
->success
)) {
3786 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3790 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3791 struct tdb_validation_status
*state
)
3793 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3794 int32_t num_entries
, i
;
3800 num_entries
= centry_uint32(centry
);
3802 for (i
=0; i
< num_entries
; i
++) {
3803 (void)centry_string(centry
, mem_ctx
);
3804 (void)centry_string(centry
, mem_ctx
);
3805 (void)centry_uint32(centry
);
3808 centry_free(centry
);
3810 if (!(state
->success
)) {
3813 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3817 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3818 struct tdb_validation_status
*state
)
3820 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3821 int32_t num_groups
, i
;
3827 num_groups
= centry_uint32(centry
);
3829 for (i
=0; i
< num_groups
; i
++) {
3831 centry_sid(centry
, &sid
);
3834 centry_free(centry
);
3836 if (!(state
->success
)) {
3839 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3843 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3844 struct tdb_validation_status
*state
)
3846 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3847 int32_t num_aliases
, i
;
3853 num_aliases
= centry_uint32(centry
);
3855 for (i
=0; i
< num_aliases
; i
++) {
3856 (void)centry_uint32(centry
);
3859 centry_free(centry
);
3861 if (!(state
->success
)) {
3864 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3868 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3869 struct tdb_validation_status
*state
)
3871 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3872 int32_t num_names
, i
;
3878 num_names
= centry_uint32(centry
);
3880 for (i
=0; i
< num_names
; i
++) {
3882 centry_sid(centry
, &sid
);
3883 (void)centry_string(centry
, mem_ctx
);
3884 (void)centry_uint32(centry
);
3887 centry_free(centry
);
3889 if (!(state
->success
)) {
3892 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3896 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3897 struct tdb_validation_status
*state
)
3899 /* Can't say anything about this other than must be nonzero. */
3900 if (dbuf
.dsize
== 0) {
3901 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3903 state
->bad_entry
= true;
3904 state
->success
= false;
3908 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3912 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3913 struct tdb_validation_status
*state
)
3915 /* Can't say anything about this other than must be nonzero. */
3916 if (dbuf
.dsize
== 0) {
3917 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3919 state
->bad_entry
= true;
3920 state
->success
= false;
3924 DEBUG(10,("validate_de: %s ok\n", keystr
));
3928 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3930 struct tdb_validation_status
*state
)
3932 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3938 (void)centry_string( centry
, mem_ctx
);
3940 centry_free(centry
);
3942 if (!(state
->success
)) {
3945 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3949 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3951 struct tdb_validation_status
*state
)
3953 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3959 (void)centry_string( centry
, mem_ctx
);
3961 centry_free(centry
);
3963 if (!(state
->success
)) {
3966 DBG_DEBUG("%s ok\n", keystr
);
3970 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3972 struct tdb_validation_status
*state
)
3974 if (dbuf
.dsize
== 0) {
3975 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3976 "key %s (len ==0) ?\n", keystr
));
3977 state
->bad_entry
= true;
3978 state
->success
= false;
3982 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3983 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3987 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3988 struct tdb_validation_status
*state
)
3990 if (dbuf
.dsize
!= 4) {
3991 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3992 keystr
, (unsigned int)dbuf
.dsize
));
3993 state
->bad_entry
= true;
3994 state
->success
= false;
3997 DEBUG(10,("validate_offline: %s ok\n", keystr
));
4001 static int validate_ndr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
4002 struct tdb_validation_status
*state
)
4005 * Ignore validation for now. The proper way to do this is with a
4006 * checksum. Just pure parsing does not really catch much.
4011 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
4012 struct tdb_validation_status
*state
)
4014 if (dbuf
.dsize
!= 4) {
4015 DEBUG(0, ("validate_cache_version: Corrupt cache for "
4016 "key %s (len %u != 4) ?\n",
4017 keystr
, (unsigned int)dbuf
.dsize
));
4018 state
->bad_entry
= true;
4019 state
->success
= false;
4023 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
4027 /***********************************************************************
4028 A list of all possible cache tdb keys with associated validation
4030 ***********************************************************************/
4032 struct key_val_struct
{
4033 const char *keyname
;
4034 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
4036 {"SEQNUM/", validate_seqnum
},
4037 {"NS/", validate_ns
},
4038 {"SN/", validate_sn
},
4040 {"LOC_POL/", validate_loc_pol
},
4041 {"PWD_POL/", validate_pwd_pol
},
4042 {"CRED/", validate_cred
},
4043 {"UL/", validate_ul
},
4044 {"GL/", validate_gl
},
4045 {"UG/", validate_ug
},
4046 {"UA", validate_ua
},
4047 {"GM/", validate_gm
},
4048 {"DR/", validate_dr
},
4049 {"DE/", validate_de
},
4050 {"TRUSTDOMCACHE/", validate_trustdomcache
},
4051 {"NSS/NA/", validate_nss_na
},
4052 {"NSS/AN/", validate_nss_an
},
4053 {"WINBINDD_OFFLINE", validate_offline
},
4054 {"NDR/", validate_ndr
},
4055 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
4059 /***********************************************************************
4060 Function to look at every entry in the tdb and validate it as far as
4062 ***********************************************************************/
4064 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
4067 unsigned int max_key_len
= 1024;
4068 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
4070 /* Paranoia check. */
4071 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0 ||
4072 strncmp("NDR/", (const char *)kbuf
.dptr
, 4) == 0) {
4073 max_key_len
= 1024 * 1024;
4075 if (kbuf
.dsize
> max_key_len
) {
4076 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4078 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
4082 for (i
= 0; key_val
[i
].keyname
; i
++) {
4083 size_t namelen
= strlen(key_val
[i
].keyname
);
4084 if (kbuf
.dsize
>= namelen
&& (
4085 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
4086 TALLOC_CTX
*mem_ctx
;
4090 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
4094 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
4095 keystr
[kbuf
.dsize
] = '\0';
4097 mem_ctx
= talloc_init("validate_ctx");
4103 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
4107 talloc_destroy(mem_ctx
);
4112 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4113 dump_data(0, (uint8_t *)kbuf
.dptr
, kbuf
.dsize
);
4114 DEBUG(0,("data :\n"));
4115 dump_data(0, (uint8_t *)dbuf
.dptr
, dbuf
.dsize
);
4116 v_state
->unknown_key
= true;
4117 v_state
->success
= false;
4118 return 1; /* terminate. */
4121 static void validate_panic(const char *const why
)
4123 DEBUG(0,("validating cache: would panic %s\n", why
));
4124 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4128 static int wbcache_update_centry_fn(TDB_CONTEXT
*tdb
,
4136 if (is_non_centry_key(key
)) {
4140 if (data
.dptr
== NULL
|| data
.dsize
== 0) {
4141 if (tdb_delete(tdb
, key
) < 0) {
4142 DEBUG(0, ("tdb_delete for [%s] failed!\n",
4148 /* add timeout to blob (uint64_t) */
4149 blob
.dsize
= data
.dsize
+ 8;
4151 blob
.dptr
= SMB_XMALLOC_ARRAY(uint8_t, blob
.dsize
);
4152 if (blob
.dptr
== NULL
) {
4155 memset(blob
.dptr
, 0, blob
.dsize
);
4157 /* copy status and seqnum */
4158 memcpy(blob
.dptr
, data
.dptr
, 8);
4161 ctimeout
= lp_winbind_cache_time() + time(NULL
);
4162 SBVAL(blob
.dptr
, 8, ctimeout
);
4165 memcpy(blob
.dptr
+ 16, data
.dptr
+ 8, data
.dsize
- 8);
4167 if (tdb_store(tdb
, key
, blob
, TDB_REPLACE
) < 0) {
4168 DEBUG(0, ("tdb_store to update [%s] failed!\n",
4170 SAFE_FREE(blob
.dptr
);
4174 SAFE_FREE(blob
.dptr
);
4178 static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT
*tdb
)
4182 DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
4184 rc
= tdb_traverse(tdb
, wbcache_update_centry_fn
, NULL
);
4192 /***********************************************************************
4193 Try and validate every entry in the winbindd cache. If we fail here,
4194 delete the cache tdb and return non-zero.
4195 ***********************************************************************/
4197 int winbindd_validate_cache(void)
4200 char *tdb_path
= NULL
;
4201 TDB_CONTEXT
*tdb
= NULL
;
4205 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4206 smb_panic_fn
= validate_panic
;
4208 tdb_path
= wcache_path();
4209 if (tdb_path
== NULL
) {
4213 tdb
= tdb_open_log(tdb_path
,
4214 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
4215 TDB_INCOMPATIBLE_HASH
|
4216 ( lp_winbind_offline_logon()
4218 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
4222 DEBUG(0, ("winbindd_validate_cache: "
4223 "error opening/initializing tdb\n"));
4227 /* Version check and upgrade code. */
4228 if (!tdb_fetch_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers_id
)) {
4229 DEBUG(10, ("Fresh database\n"));
4230 tdb_store_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
);
4231 vers_id
= WINBINDD_CACHE_VERSION
;
4234 if (vers_id
!= WINBINDD_CACHE_VERSION
) {
4235 if (vers_id
== WINBINDD_CACHE_VER1
) {
4236 ok
= wbcache_upgrade_v1_to_v2(tdb
);
4238 DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
4243 tdb_store_uint32(tdb
,
4244 WINBINDD_CACHE_VERSION_KEYSTR
,
4245 WINBINDD_CACHE_VERSION
);
4246 vers_id
= WINBINDD_CACHE_VER2
;
4252 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
4255 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4256 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
4261 TALLOC_FREE(tdb_path
);
4262 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4263 smb_panic_fn
= smb_panic
;
4267 /***********************************************************************
4268 Try and validate every entry in the winbindd cache.
4269 ***********************************************************************/
4271 int winbindd_validate_cache_nobackup(void)
4276 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4277 smb_panic_fn
= validate_panic
;
4279 tdb_path
= wcache_path();
4280 if (tdb_path
== NULL
) {
4281 goto err_panic_restore
;
4284 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
4285 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
4287 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
4291 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4295 TALLOC_FREE(tdb_path
);
4297 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4299 smb_panic_fn
= smb_panic
;
4303 bool winbindd_cache_validate_and_initialize(void)
4305 close_winbindd_cache();
4307 if (lp_winbind_offline_logon()) {
4308 if (winbindd_validate_cache() < 0) {
4309 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4310 "could be restored.\n"));
4314 return initialize_winbindd_cache();
4317 /*********************************************************************
4318 ********************************************************************/
4320 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
4321 struct winbindd_tdc_domain
**domains
,
4322 size_t *num_domains
)
4324 struct winbindd_tdc_domain
*list
= NULL
;
4326 bool set_only
= false;
4328 /* don't allow duplicates */
4333 for ( i
=0; i
< (*num_domains
); i
++ ) {
4334 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
4335 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4346 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, 1 );
4349 list
= talloc_realloc( *domains
, *domains
,
4350 struct winbindd_tdc_domain
,
4355 ZERO_STRUCT( list
[idx
] );
4361 list
[idx
].domain_name
= talloc_strdup(list
, new_dom
->name
);
4362 if (list
[idx
].domain_name
== NULL
) {
4365 if (new_dom
->alt_name
!= NULL
) {
4366 list
[idx
].dns_name
= talloc_strdup(list
, new_dom
->alt_name
);
4367 if (list
[idx
].dns_name
== NULL
) {
4372 if ( !is_null_sid( &new_dom
->sid
) ) {
4373 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
4375 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
4378 if ( new_dom
->domain_flags
!= 0x0 )
4379 list
[idx
].trust_flags
= new_dom
->domain_flags
;
4381 if ( new_dom
->domain_type
!= 0x0 )
4382 list
[idx
].trust_type
= new_dom
->domain_type
;
4384 if ( new_dom
->domain_trust_attribs
!= 0x0 )
4385 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
4389 *num_domains
= idx
+ 1;
4395 /*********************************************************************
4396 ********************************************************************/
4398 static TDB_DATA
make_tdc_key( const char *domain_name
)
4400 char *keystr
= NULL
;
4401 TDB_DATA key
= { NULL
, 0 };
4403 if ( !domain_name
) {
4404 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4408 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
4411 key
= string_term_tdb_data(keystr
);
4416 /*********************************************************************
4417 ********************************************************************/
4419 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
4421 unsigned char **buf
)
4423 unsigned char *buffer
= NULL
;
4428 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4436 /* Store the number of array items first */
4437 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
4440 /* now pack each domain trust record */
4441 for ( i
=0; i
<num_domains
; i
++ ) {
4446 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4447 domains
[i
].domain_name
,
4448 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
4451 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
4452 domains
[i
].domain_name
,
4453 domains
[i
].dns_name
? domains
[i
].dns_name
: "",
4454 sid_to_fstring(tmp
, &domains
[i
].sid
),
4455 domains
[i
].trust_flags
,
4456 domains
[i
].trust_attribs
,
4457 domains
[i
].trust_type
);
4460 if ( buflen
< len
) {
4462 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
4463 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4477 /*********************************************************************
4478 ********************************************************************/
4480 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
4481 struct winbindd_tdc_domain
**domains
)
4483 fstring domain_name
, dns_name
, sid_string
;
4484 uint32_t type
, attribs
, flags
;
4488 struct winbindd_tdc_domain
*list
= NULL
;
4490 /* get the number of domains */
4491 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
4493 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4497 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, num_domains
);
4499 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4503 for ( i
=0; i
<num_domains
; i
++ ) {
4506 this_len
= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
4514 if ( this_len
== -1 ) {
4515 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4516 TALLOC_FREE( list
);
4521 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4522 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4523 domain_name
, dns_name
, sid_string
,
4524 flags
, attribs
, type
));
4526 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
4527 list
[i
].dns_name
= NULL
;
4528 if (dns_name
[0] != '\0') {
4529 list
[i
].dns_name
= talloc_strdup(list
, dns_name
);
4531 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
4532 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4535 list
[i
].trust_flags
= flags
;
4536 list
[i
].trust_attribs
= attribs
;
4537 list
[i
].trust_type
= type
;
4545 /*********************************************************************
4546 ********************************************************************/
4548 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
4550 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4551 TDB_DATA data
= { NULL
, 0 };
4557 /* See if we were asked to delete the cache entry */
4560 ret
= tdb_delete( wcache
->tdb
, key
);
4564 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4571 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4574 SAFE_FREE( data
.dptr
);
4575 SAFE_FREE( key
.dptr
);
4577 return ( ret
== 0 );
4580 /*********************************************************************
4581 ********************************************************************/
4583 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4585 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4586 TDB_DATA data
= { NULL
, 0 };
4594 data
= tdb_fetch( wcache
->tdb
, key
);
4596 SAFE_FREE( key
.dptr
);
4601 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4603 SAFE_FREE( data
.dptr
);
4611 /*********************************************************************
4612 ********************************************************************/
4614 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4616 struct winbindd_tdc_domain
*dom_list
= NULL
;
4617 size_t num_domains
= 0;
4620 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4621 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4622 domain
->name
, domain
->alt_name
,
4623 sid_string_dbg(&domain
->sid
),
4624 domain
->domain_flags
,
4625 domain
->domain_trust_attribs
,
4626 domain
->domain_type
));
4628 if ( !init_wcache() ) {
4632 /* fetch the list */
4634 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4636 /* add the new domain */
4638 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4642 /* pack the domain */
4644 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4652 TALLOC_FREE( dom_list
);
4657 static struct winbindd_tdc_domain
*wcache_tdc_dup_domain(
4658 TALLOC_CTX
*mem_ctx
, const struct winbindd_tdc_domain
*src
)
4660 struct winbindd_tdc_domain
*dst
;
4662 dst
= talloc(mem_ctx
, struct winbindd_tdc_domain
);
4666 dst
->domain_name
= talloc_strdup(dst
, src
->domain_name
);
4667 if (dst
->domain_name
== NULL
) {
4671 dst
->dns_name
= NULL
;
4672 if (src
->dns_name
!= NULL
) {
4673 dst
->dns_name
= talloc_strdup(dst
, src
->dns_name
);
4674 if (dst
->dns_name
== NULL
) {
4679 sid_copy(&dst
->sid
, &src
->sid
);
4680 dst
->trust_flags
= src
->trust_flags
;
4681 dst
->trust_type
= src
->trust_type
;
4682 dst
->trust_attribs
= src
->trust_attribs
;
4689 /*********************************************************************
4690 ********************************************************************/
4692 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4694 struct winbindd_tdc_domain
*dom_list
= NULL
;
4695 size_t num_domains
= 0;
4697 struct winbindd_tdc_domain
*d
= NULL
;
4699 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4701 if ( !init_wcache() ) {
4705 /* fetch the list */
4707 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4709 for ( i
=0; i
<num_domains
; i
++ ) {
4710 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4711 strequal(name
, dom_list
[i
].dns_name
) )
4713 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4716 d
= wcache_tdc_dup_domain(ctx
, &dom_list
[i
]);
4721 TALLOC_FREE( dom_list
);
4726 /*********************************************************************
4727 ********************************************************************/
4729 void wcache_tdc_clear( void )
4731 if ( !init_wcache() )
4734 wcache_tdc_store_list( NULL
, 0 );
4739 static bool wcache_ndr_key(TALLOC_CTX
*mem_ctx
, const char *domain_name
,
4740 uint32_t opnum
, const DATA_BLOB
*req
,
4746 key
= talloc_asprintf(mem_ctx
, "NDR/%s/%d/", domain_name
, (int)opnum
);
4750 keylen
= talloc_get_size(key
) - 1;
4752 key
= talloc_realloc(mem_ctx
, key
, char, keylen
+ req
->length
);
4756 memcpy(key
+ keylen
, req
->data
, req
->length
);
4758 pkey
->dptr
= (uint8_t *)key
;
4759 pkey
->dsize
= talloc_get_size(key
);
4763 static bool wcache_opnum_cacheable(uint32_t opnum
)
4766 case NDR_WBINT_PING
:
4767 case NDR_WBINT_QUERYSEQUENCENUMBER
:
4768 case NDR_WBINT_ALLOCATEUID
:
4769 case NDR_WBINT_ALLOCATEGID
:
4770 case NDR_WBINT_CHECKMACHINEACCOUNT
:
4771 case NDR_WBINT_CHANGEMACHINEACCOUNT
:
4772 case NDR_WBINT_PINGDC
:
4778 bool wcache_fetch_ndr(TALLOC_CTX
*mem_ctx
, struct winbindd_domain
*domain
,
4779 uint32_t opnum
, const DATA_BLOB
*req
, DATA_BLOB
*resp
)
4784 if (!wcache_opnum_cacheable(opnum
) ||
4785 is_my_own_sam_domain(domain
) ||
4786 is_builtin_domain(domain
)) {
4790 if (wcache
->tdb
== NULL
) {
4794 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4797 data
= tdb_fetch(wcache
->tdb
, key
);
4798 TALLOC_FREE(key
.dptr
);
4800 if (data
.dptr
== NULL
) {
4803 if (data
.dsize
< 12) {
4807 if (!is_domain_offline(domain
)) {
4808 uint32_t entry_seqnum
, dom_seqnum
, last_check
;
4809 uint64_t entry_timeout
;
4811 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
,
4815 entry_seqnum
= IVAL(data
.dptr
, 0);
4816 if (entry_seqnum
!= dom_seqnum
) {
4817 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4818 (int)entry_seqnum
));
4821 entry_timeout
= BVAL(data
.dptr
, 4);
4822 if (time(NULL
) > entry_timeout
) {
4823 DEBUG(10, ("Entry has timed out\n"));
4828 resp
->data
= (uint8_t *)talloc_memdup(mem_ctx
, data
.dptr
+ 12,
4830 if (resp
->data
== NULL
) {
4831 DEBUG(10, ("talloc failed\n"));
4834 resp
->length
= data
.dsize
- 12;
4838 SAFE_FREE(data
.dptr
);
4842 void wcache_store_ndr(struct winbindd_domain
*domain
, uint32_t opnum
,
4843 const DATA_BLOB
*req
, const DATA_BLOB
*resp
)
4846 uint32_t dom_seqnum
, last_check
;
4849 if (!wcache_opnum_cacheable(opnum
) ||
4850 is_my_own_sam_domain(domain
) ||
4851 is_builtin_domain(domain
)) {
4855 if (wcache
->tdb
== NULL
) {
4859 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
, &last_check
)) {
4860 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4865 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4869 timeout
= time(NULL
) + lp_winbind_cache_time();
4871 data
.dsize
= resp
->length
+ 12;
4872 data
.dptr
= talloc_array(key
.dptr
, uint8_t, data
.dsize
);
4873 if (data
.dptr
== NULL
) {
4877 SIVAL(data
.dptr
, 0, dom_seqnum
);
4878 SBVAL(data
.dptr
, 4, timeout
);
4879 memcpy(data
.dptr
+ 12, resp
->data
, resp
->length
);
4881 tdb_store(wcache
->tdb
, key
, data
, 0);
4884 TALLOC_FREE(key
.dptr
);