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"
39 #define DBGC_CLASS DBGC_WINBIND
41 #define WINBINDD_CACHE_VER1 1 /* initial db version */
42 #define WINBINDD_CACHE_VER2 2 /* second version with timeouts for NDR entries */
44 #define WINBINDD_CACHE_VERSION WINBINDD_CACHE_VER2
45 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
47 extern struct winbindd_methods reconnect_methods
;
49 extern struct winbindd_methods reconnect_ads_methods
;
51 extern struct winbindd_methods builtin_passdb_methods
;
52 extern struct winbindd_methods sam_passdb_methods
;
55 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
56 * Here are the list of entry types that are *not* stored
57 * as form struct cache_entry in the cache.
60 static const char *non_centry_keys
[] = {
63 WINBINDD_CACHE_VERSION_KEYSTR
,
67 /************************************************************************
68 Is this key a non-centry type ?
69 ************************************************************************/
71 static bool is_non_centry_key(TDB_DATA kbuf
)
75 if (kbuf
.dptr
== NULL
|| kbuf
.dsize
== 0) {
78 for (i
= 0; non_centry_keys
[i
] != NULL
; i
++) {
79 size_t namelen
= strlen(non_centry_keys
[i
]);
80 if (kbuf
.dsize
< namelen
) {
83 if (strncmp(non_centry_keys
[i
], (const char *)kbuf
.dptr
, namelen
) == 0) {
90 /* Global online/offline state - False when online. winbindd starts up online
91 and sets this to true if the first query fails and there's an entry in
92 the cache tdb telling us to stay offline. */
94 static bool global_winbindd_offline_state
;
96 struct winbind_cache
{
102 uint32_t sequence_number
;
108 void (*smb_panic_fn
)(const char *const why
) = smb_panic
;
110 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
112 static struct winbind_cache
*wcache
;
114 /* get the winbind_cache structure */
115 static struct winbind_cache
*get_cache(struct winbindd_domain
*domain
)
117 struct winbind_cache
*ret
= wcache
;
119 /* We have to know what type of domain we are dealing with first. */
121 if (domain
->internal
) {
122 domain
->backend
= &builtin_passdb_methods
;
125 if (dom_sid_equal(&domain
->sid
, &global_sid_Builtin
)) {
126 domain
->initialized
= true;
129 if (strequal(domain
->name
, get_global_sam_name()) &&
130 sid_check_is_our_sam(&domain
->sid
)) {
131 domain
->backend
= &sam_passdb_methods
;
134 if ( !domain
->initialized
) {
135 /* We do not need a connection to an RW DC for cache operation */
136 init_dc_connection(domain
, false);
140 OK. Listen up because I'm only going to say this once.
141 We have the following scenarios to consider
142 (a) trusted AD domains on a Samba DC,
143 (b) trusted AD domains and we are joined to a non-kerberos domain
144 (c) trusted AD domains and we are joined to a kerberos (AD) domain
146 For (a) we can always contact the trusted domain using krb5
147 since we have the domain trust account password
149 For (b) we can only use RPC since we have no way of
150 getting a krb5 ticket in our own domain
152 For (c) we can always use krb5 since we have a kerberos trust
157 if (!domain
->backend
) {
159 struct winbindd_domain
*our_domain
= domain
;
161 /* find our domain first so we can figure out if we
162 are joined to a kerberized domain */
164 if ( !domain
->primary
)
165 our_domain
= find_our_domain();
167 if ((our_domain
->active_directory
|| IS_DC
)
168 && domain
->active_directory
169 && !lp_winbind_rpc_only()) {
170 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain
->name
));
171 domain
->backend
= &reconnect_ads_methods
;
173 #endif /* HAVE_ADS */
174 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain
->name
));
175 domain
->backend
= &reconnect_methods
;
178 #endif /* HAVE_ADS */
184 ret
= SMB_XMALLOC_P(struct winbind_cache
);
188 wcache_flush_cache();
194 free a centry structure
196 static void centry_free(struct cache_entry
*centry
)
200 SAFE_FREE(centry
->data
);
204 static bool centry_check_bytes(struct cache_entry
*centry
, size_t nbytes
)
206 if (centry
->len
- centry
->ofs
< nbytes
) {
207 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
208 (unsigned int)nbytes
,
209 centry
->len
- centry
->ofs
));
216 pull a uint64_t from a cache entry
218 static uint64_t centry_uint64_t(struct cache_entry
*centry
)
222 if (!centry_check_bytes(centry
, 8)) {
223 smb_panic_fn("centry_uint64_t");
225 ret
= BVAL(centry
->data
, centry
->ofs
);
231 pull a uint32_t from a cache entry
233 static uint32_t centry_uint32(struct cache_entry
*centry
)
237 if (!centry_check_bytes(centry
, 4)) {
238 smb_panic_fn("centry_uint32");
240 ret
= IVAL(centry
->data
, centry
->ofs
);
246 pull a uint16_t from a cache entry
248 static uint16_t centry_uint16(struct cache_entry
*centry
)
251 if (!centry_check_bytes(centry
, 2)) {
252 smb_panic_fn("centry_uint16");
254 ret
= SVAL(centry
->data
, centry
->ofs
);
260 pull a uint8_t from a cache entry
262 static uint8_t centry_uint8(struct cache_entry
*centry
)
265 if (!centry_check_bytes(centry
, 1)) {
266 smb_panic_fn("centry_uint8");
268 ret
= CVAL(centry
->data
, centry
->ofs
);
274 pull a NTTIME from a cache entry
276 static NTTIME
centry_nttime(struct cache_entry
*centry
)
279 if (!centry_check_bytes(centry
, 8)) {
280 smb_panic_fn("centry_nttime");
282 ret
= IVAL(centry
->data
, centry
->ofs
);
284 ret
+= (uint64_t)IVAL(centry
->data
, centry
->ofs
) << 32;
290 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
292 static time_t centry_time(struct cache_entry
*centry
)
294 return (time_t)centry_nttime(centry
);
297 /* pull a string from a cache entry, using the supplied
300 static char *centry_string(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
305 len
= centry_uint8(centry
);
308 /* a deliberate NULL string */
312 if (!centry_check_bytes(centry
, (size_t)len
)) {
313 smb_panic_fn("centry_string");
316 ret
= talloc_array(mem_ctx
, char, len
+1);
318 smb_panic_fn("centry_string out of memory\n");
320 memcpy(ret
,centry
->data
+ centry
->ofs
, len
);
326 /* pull a hash16 from a cache entry, using the supplied
329 static char *centry_hash16(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
334 len
= centry_uint8(centry
);
337 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
342 if (!centry_check_bytes(centry
, 16)) {
346 ret
= talloc_array(mem_ctx
, char, 16);
348 smb_panic_fn("centry_hash out of memory\n");
350 memcpy(ret
,centry
->data
+ centry
->ofs
, 16);
355 /* pull a sid from a cache entry, using the supplied
358 static bool centry_sid(struct cache_entry
*centry
, struct dom_sid
*sid
)
363 sid_string
= centry_string(centry
, talloc_tos());
364 if (sid_string
== NULL
) {
367 ret
= string_to_sid(sid
, sid_string
);
368 TALLOC_FREE(sid_string
);
374 pull a NTSTATUS from a cache entry
376 static NTSTATUS
centry_ntstatus(struct cache_entry
*centry
)
380 status
= NT_STATUS(centry_uint32(centry
));
385 /* the server is considered down if it can't give us a sequence number */
386 static bool wcache_server_down(struct winbindd_domain
*domain
)
393 ret
= (domain
->sequence_number
== DOM_SEQUENCE_NONE
);
396 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
401 struct wcache_seqnum_state
{
403 uint32_t *last_seq_check
;
406 static int wcache_seqnum_parser(TDB_DATA key
, TDB_DATA data
,
409 struct wcache_seqnum_state
*state
= private_data
;
411 if (data
.dsize
!= 8) {
412 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
417 *state
->seqnum
= IVAL(data
.dptr
, 0);
418 *state
->last_seq_check
= IVAL(data
.dptr
, 4);
422 static bool wcache_fetch_seqnum(const char *domain_name
, uint32_t *seqnum
,
423 uint32_t *last_seq_check
)
425 struct wcache_seqnum_state state
= {
426 .seqnum
= seqnum
, .last_seq_check
= last_seq_check
428 size_t len
= strlen(domain_name
);
430 TDB_DATA key
= { .dptr
= (uint8_t *)keystr
, .dsize
= sizeof(keystr
) };
433 if (wcache
->tdb
== NULL
) {
434 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
438 snprintf(keystr
, sizeof(keystr
), "SEQNUM/%s", domain_name
);
440 ret
= tdb_parse_record(wcache
->tdb
, key
, wcache_seqnum_parser
,
445 static NTSTATUS
fetch_cache_seqnum( struct winbindd_domain
*domain
, time_t now
)
447 uint32_t last_check
, time_diff
;
449 if (!wcache_fetch_seqnum(domain
->name
, &domain
->sequence_number
,
451 return NT_STATUS_UNSUCCESSFUL
;
453 domain
->last_seq_check
= last_check
;
455 /* have we expired? */
457 time_diff
= now
- domain
->last_seq_check
;
458 if ( time_diff
> lp_winbind_cache_time() ) {
459 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
460 domain
->name
, domain
->sequence_number
,
461 (uint32_t)domain
->last_seq_check
));
462 return NT_STATUS_UNSUCCESSFUL
;
465 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
466 domain
->name
, domain
->sequence_number
,
467 (uint32_t)domain
->last_seq_check
));
472 bool wcache_store_seqnum(const char *domain_name
, uint32_t seqnum
,
473 time_t last_seq_check
)
475 size_t len
= strlen(domain_name
);
477 TDB_DATA key
= { .dptr
= (uint8_t *)keystr
, .dsize
= sizeof(keystr
) };
481 if (wcache
->tdb
== NULL
) {
482 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
486 snprintf(keystr
, sizeof(keystr
), "SEQNUM/%s", domain_name
);
488 SIVAL(buf
, 0, seqnum
);
489 SIVAL(buf
, 4, last_seq_check
);
491 ret
= tdb_store(wcache
->tdb
, key
, make_tdb_data(buf
, sizeof(buf
)),
494 DEBUG(10, ("tdb_store_bystring failed: %s\n",
495 tdb_errorstr(wcache
->tdb
)));
499 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
500 domain_name
, seqnum
, (unsigned)last_seq_check
));
505 static bool store_cache_seqnum( struct winbindd_domain
*domain
)
507 return wcache_store_seqnum(domain
->name
, domain
->sequence_number
,
508 domain
->last_seq_check
);
512 refresh the domain sequence number. If force is true
513 then always refresh it, no matter how recently we fetched it
516 static void refresh_sequence_number(struct winbindd_domain
*domain
, bool force
)
520 time_t t
= time(NULL
);
521 unsigned cache_time
= lp_winbind_cache_time();
523 if (is_domain_offline(domain
)) {
529 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
530 /* trying to reconnect is expensive, don't do it too often */
531 if (domain
->sequence_number
== DOM_SEQUENCE_NONE
) {
536 time_diff
= t
- domain
->last_seq_check
;
538 /* see if we have to refetch the domain sequence number */
539 if (!force
&& (time_diff
< cache_time
) &&
540 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
541 NT_STATUS_IS_OK(domain
->last_status
)) {
542 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain
->name
));
546 /* try to get the sequence number from the tdb cache first */
547 /* this will update the timestamp as well */
549 status
= fetch_cache_seqnum( domain
, t
);
550 if (NT_STATUS_IS_OK(status
) &&
551 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
552 NT_STATUS_IS_OK(domain
->last_status
)) {
556 /* important! make sure that we know if this is a native
557 mode domain or not. And that we can contact it. */
559 if ( winbindd_can_contact_domain( domain
) ) {
560 status
= domain
->backend
->sequence_number(domain
,
561 &domain
->sequence_number
);
563 /* just use the current time */
564 status
= NT_STATUS_OK
;
565 domain
->sequence_number
= time(NULL
);
569 /* the above call could have set our domain->backend to NULL when
570 * coming from offline to online mode, make sure to reinitialize the
571 * backend - Guenther */
574 if (!NT_STATUS_IS_OK(status
)) {
575 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status
)));
576 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
579 domain
->last_status
= status
;
580 domain
->last_seq_check
= time(NULL
);
582 /* save the new sequence number in the cache */
583 store_cache_seqnum( domain
);
586 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
587 domain
->name
, domain
->sequence_number
));
593 decide if a cache entry has expired
595 static bool centry_expired(struct winbindd_domain
*domain
, const char *keystr
, struct cache_entry
*centry
)
597 /* If we've been told to be offline - stay in that state... */
598 if (lp_winbind_offline_logon() && global_winbindd_offline_state
) {
599 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
600 keystr
, domain
->name
));
604 /* when the domain is offline return the cached entry.
605 * This deals with transient offline states... */
607 if (!domain
->online
) {
608 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
609 keystr
, domain
->name
));
613 /* if the server is OK and our cache entry came from when it was down then
614 the entry is invalid */
615 if ((domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
616 (centry
->sequence_number
== DOM_SEQUENCE_NONE
)) {
617 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
618 keystr
, domain
->name
));
622 /* if the server is down or the cache entry is not older than the
623 current sequence number or it did not timeout then it is OK */
624 if (wcache_server_down(domain
)
625 || ((centry
->sequence_number
== domain
->sequence_number
)
626 && (centry
->timeout
> time(NULL
)))) {
627 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
628 keystr
, domain
->name
));
632 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
633 keystr
, domain
->name
));
639 static struct cache_entry
*wcache_fetch_raw(char *kstr
)
642 struct cache_entry
*centry
;
645 key
= string_tdb_data(kstr
);
646 data
= tdb_fetch(wcache
->tdb
, key
);
652 centry
= SMB_XMALLOC_P(struct cache_entry
);
653 centry
->data
= (unsigned char *)data
.dptr
;
654 centry
->len
= data
.dsize
;
657 if (centry
->len
< 16) {
658 /* huh? corrupt cache? */
659 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s "
660 "(len < 16)?\n", kstr
));
665 centry
->status
= centry_ntstatus(centry
);
666 centry
->sequence_number
= centry_uint32(centry
);
667 centry
->timeout
= centry_uint64_t(centry
);
672 static bool is_my_own_sam_domain(struct winbindd_domain
*domain
)
674 if (strequal(domain
->name
, get_global_sam_name()) &&
675 sid_check_is_our_sam(&domain
->sid
)) {
682 static bool is_builtin_domain(struct winbindd_domain
*domain
)
684 if (strequal(domain
->name
, "BUILTIN") &&
685 sid_check_is_builtin(&domain
->sid
)) {
693 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
694 number and return status
696 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
697 struct winbindd_domain
*domain
,
698 const char *format
, ...) PRINTF_ATTRIBUTE(3,4);
699 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
700 struct winbindd_domain
*domain
,
701 const char *format
, ...)
705 struct cache_entry
*centry
;
707 if (!winbindd_use_cache() ||
708 is_my_own_sam_domain(domain
) ||
709 is_builtin_domain(domain
)) {
713 refresh_sequence_number(domain
, false);
715 va_start(ap
, format
);
716 smb_xvasprintf(&kstr
, format
, ap
);
719 centry
= wcache_fetch_raw(kstr
);
720 if (centry
== NULL
) {
725 if (centry_expired(domain
, kstr
, centry
)) {
727 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
728 kstr
, domain
->name
));
735 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
736 kstr
, domain
->name
));
742 static void wcache_delete(const char *format
, ...) PRINTF_ATTRIBUTE(1,2);
743 static void wcache_delete(const char *format
, ...)
749 va_start(ap
, format
);
750 smb_xvasprintf(&kstr
, format
, ap
);
753 key
= string_tdb_data(kstr
);
755 tdb_delete(wcache
->tdb
, key
);
760 make sure we have at least len bytes available in a centry
762 static void centry_expand(struct cache_entry
*centry
, uint32_t len
)
764 if (centry
->len
- centry
->ofs
>= len
)
767 centry
->data
= SMB_REALLOC_ARRAY(centry
->data
, unsigned char,
770 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry
->len
));
771 smb_panic_fn("out of memory in centry_expand");
776 push a uint64_t into a centry
778 static void centry_put_uint64_t(struct cache_entry
*centry
, uint64_t v
)
780 centry_expand(centry
, 8);
781 SBVAL(centry
->data
, centry
->ofs
, v
);
786 push a uint32_t into a centry
788 static void centry_put_uint32(struct cache_entry
*centry
, uint32_t v
)
790 centry_expand(centry
, 4);
791 SIVAL(centry
->data
, centry
->ofs
, v
);
796 push a uint16_t into a centry
798 static void centry_put_uint16(struct cache_entry
*centry
, uint16_t v
)
800 centry_expand(centry
, 2);
801 SSVAL(centry
->data
, centry
->ofs
, v
);
806 push a uint8_t into a centry
808 static void centry_put_uint8(struct cache_entry
*centry
, uint8_t v
)
810 centry_expand(centry
, 1);
811 SCVAL(centry
->data
, centry
->ofs
, v
);
816 push a string into a centry
818 static void centry_put_string(struct cache_entry
*centry
, const char *s
)
823 /* null strings are marked as len 0xFFFF */
824 centry_put_uint8(centry
, 0xFF);
829 /* can't handle more than 254 char strings. Truncating is probably best */
831 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len
));
834 centry_put_uint8(centry
, len
);
835 centry_expand(centry
, len
);
836 memcpy(centry
->data
+ centry
->ofs
, s
, len
);
841 push a 16 byte hash into a centry - treat as 16 byte string.
843 static void centry_put_hash16(struct cache_entry
*centry
, const uint8_t val
[16])
845 centry_put_uint8(centry
, 16);
846 centry_expand(centry
, 16);
847 memcpy(centry
->data
+ centry
->ofs
, val
, 16);
851 static void centry_put_sid(struct cache_entry
*centry
, const struct dom_sid
*sid
)
854 centry_put_string(centry
, sid_to_fstring(sid_string
, sid
));
859 put NTSTATUS into a centry
861 static void centry_put_ntstatus(struct cache_entry
*centry
, NTSTATUS status
)
863 uint32_t status_value
= NT_STATUS_V(status
);
864 centry_put_uint32(centry
, status_value
);
869 push a NTTIME into a centry
871 static void centry_put_nttime(struct cache_entry
*centry
, NTTIME nt
)
873 centry_expand(centry
, 8);
874 SIVAL(centry
->data
, centry
->ofs
, nt
& 0xFFFFFFFF);
876 SIVAL(centry
->data
, centry
->ofs
, nt
>> 32);
881 push a time_t into a centry - use a 64 bit size.
882 NTTIME here is being used as a convenient 64-bit size.
884 static void centry_put_time(struct cache_entry
*centry
, time_t t
)
886 NTTIME nt
= (NTTIME
)t
;
887 centry_put_nttime(centry
, nt
);
891 start a centry for output. When finished, call centry_end()
893 static struct cache_entry
*centry_start(struct winbindd_domain
*domain
,
896 struct cache_entry
*centry
;
901 centry
= SMB_XMALLOC_P(struct cache_entry
);
903 centry
->len
= 8192; /* reasonable default */
904 centry
->data
= SMB_XMALLOC_ARRAY(uint8_t, centry
->len
);
906 centry
->sequence_number
= domain
->sequence_number
;
907 centry
->timeout
= lp_winbind_cache_time() + time(NULL
);
908 centry_put_ntstatus(centry
, status
);
909 centry_put_uint32(centry
, centry
->sequence_number
);
910 centry_put_uint64_t(centry
, centry
->timeout
);
915 finish a centry and write it to the tdb
917 static void centry_end(struct cache_entry
*centry
, const char *format
, ...) PRINTF_ATTRIBUTE(2,3);
918 static void centry_end(struct cache_entry
*centry
, const char *format
, ...)
924 if (!winbindd_use_cache()) {
928 va_start(ap
, format
);
929 smb_xvasprintf(&kstr
, format
, ap
);
932 key
= string_tdb_data(kstr
);
933 data
.dptr
= centry
->data
;
934 data
.dsize
= centry
->ofs
;
936 tdb_store(wcache
->tdb
, key
, data
, TDB_REPLACE
);
940 static void wcache_save_name_to_sid(struct winbindd_domain
*domain
,
941 NTSTATUS status
, const char *domain_name
,
942 const char *name
, const struct dom_sid
*sid
,
943 enum lsa_SidType type
)
945 struct cache_entry
*centry
;
948 centry
= centry_start(domain
, status
);
952 if ((domain_name
== NULL
) || (domain_name
[0] == '\0')) {
953 struct winbindd_domain
*mydomain
=
954 find_domain_from_sid_noinit(sid
);
955 if (mydomain
!= NULL
) {
956 domain_name
= mydomain
->name
;
960 centry_put_uint32(centry
, type
);
961 centry_put_sid(centry
, sid
);
962 fstrcpy(uname
, name
);
963 (void)strupper_m(uname
);
964 centry_end(centry
, "NS/%s/%s", domain_name
, uname
);
965 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name
,
966 uname
, sid_string_dbg(sid
), nt_errstr(status
)));
970 static void wcache_save_sid_to_name(struct winbindd_domain
*domain
, NTSTATUS status
,
971 const struct dom_sid
*sid
, const char *domain_name
, const char *name
, enum lsa_SidType type
)
973 struct cache_entry
*centry
;
976 centry
= centry_start(domain
, status
);
980 if ((domain_name
== NULL
) || (domain_name
[0] == '\0')) {
981 struct winbindd_domain
*mydomain
=
982 find_domain_from_sid_noinit(sid
);
983 if (mydomain
!= NULL
) {
984 domain_name
= mydomain
->name
;
988 if (NT_STATUS_IS_OK(status
)) {
989 centry_put_uint32(centry
, type
);
990 centry_put_string(centry
, domain_name
);
991 centry_put_string(centry
, name
);
994 centry_end(centry
, "SN/%s", sid_to_fstring(sid_string
, sid
));
995 DEBUG(10,("wcache_save_sid_to_name: %s -> %s\\%s (%s)\n", sid_string
,
996 domain_name
, name
, nt_errstr(status
)));
1001 static void wcache_save_user(struct winbindd_domain
*domain
, NTSTATUS status
,
1002 struct wbint_userinfo
*info
)
1004 struct cache_entry
*centry
;
1007 if (is_null_sid(&info
->user_sid
)) {
1011 centry
= centry_start(domain
, status
);
1014 centry_put_string(centry
, info
->acct_name
);
1015 centry_put_string(centry
, info
->full_name
);
1016 centry_put_string(centry
, info
->homedir
);
1017 centry_put_string(centry
, info
->shell
);
1018 centry_put_uint32(centry
, info
->primary_gid
);
1019 centry_put_sid(centry
, &info
->user_sid
);
1020 centry_put_sid(centry
, &info
->group_sid
);
1021 centry_end(centry
, "U/%s", sid_to_fstring(sid_string
,
1023 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string
, info
->acct_name
));
1024 centry_free(centry
);
1027 static void wcache_save_lockout_policy(struct winbindd_domain
*domain
,
1029 struct samr_DomInfo12
*lockout_policy
)
1031 struct cache_entry
*centry
;
1033 centry
= centry_start(domain
, status
);
1037 centry_put_nttime(centry
, lockout_policy
->lockout_duration
);
1038 centry_put_nttime(centry
, lockout_policy
->lockout_window
);
1039 centry_put_uint16(centry
, lockout_policy
->lockout_threshold
);
1041 centry_end(centry
, "LOC_POL/%s", domain
->name
);
1043 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain
->name
));
1045 centry_free(centry
);
1050 static void wcache_save_password_policy(struct winbindd_domain
*domain
,
1052 struct samr_DomInfo1
*policy
)
1054 struct cache_entry
*centry
;
1056 centry
= centry_start(domain
, status
);
1060 centry_put_uint16(centry
, policy
->min_password_length
);
1061 centry_put_uint16(centry
, policy
->password_history_length
);
1062 centry_put_uint32(centry
, policy
->password_properties
);
1063 centry_put_nttime(centry
, policy
->max_password_age
);
1064 centry_put_nttime(centry
, policy
->min_password_age
);
1066 centry_end(centry
, "PWD_POL/%s", domain
->name
);
1068 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
1070 centry_free(centry
);
1073 /***************************************************************************
1074 ***************************************************************************/
1076 static void wcache_save_username_alias(struct winbindd_domain
*domain
,
1078 const char *name
, const char *alias
)
1080 struct cache_entry
*centry
;
1083 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1086 centry_put_string( centry
, alias
);
1088 fstrcpy(uname
, name
);
1089 (void)strupper_m(uname
);
1090 centry_end(centry
, "NSS/NA/%s", uname
);
1092 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name
, alias
));
1094 centry_free(centry
);
1097 static void wcache_save_alias_username(struct winbindd_domain
*domain
,
1099 const char *alias
, const char *name
)
1101 struct cache_entry
*centry
;
1104 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1107 centry_put_string( centry
, name
);
1109 fstrcpy(uname
, alias
);
1110 (void)strupper_m(uname
);
1111 centry_end(centry
, "NSS/AN/%s", uname
);
1113 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias
, name
));
1115 centry_free(centry
);
1118 /***************************************************************************
1119 ***************************************************************************/
1121 NTSTATUS
resolve_username_to_alias( TALLOC_CTX
*mem_ctx
,
1122 struct winbindd_domain
*domain
,
1123 const char *name
, char **alias
)
1125 struct winbind_cache
*cache
= get_cache(domain
);
1126 struct cache_entry
*centry
= NULL
;
1130 if ( domain
->internal
)
1131 return NT_STATUS_NOT_SUPPORTED
;
1136 upper_name
= talloc_strdup(mem_ctx
, name
);
1137 if (upper_name
== NULL
) {
1138 return NT_STATUS_NO_MEMORY
;
1140 if (!strupper_m(upper_name
)) {
1141 talloc_free(upper_name
);
1142 return NT_STATUS_INVALID_PARAMETER
;
1145 centry
= wcache_fetch(cache
, domain
, "NSS/NA/%s", upper_name
);
1147 talloc_free(upper_name
);
1152 status
= centry
->status
;
1154 if (!NT_STATUS_IS_OK(status
)) {
1155 centry_free(centry
);
1159 *alias
= centry_string( centry
, mem_ctx
);
1161 centry_free(centry
);
1163 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1164 name
, *alias
? *alias
: "(none)"));
1166 return (*alias
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1170 /* If its not in cache and we are offline, then fail */
1172 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1173 DEBUG(8,("resolve_username_to_alias: rejecting query "
1174 "in offline mode\n"));
1175 return NT_STATUS_NOT_FOUND
;
1178 status
= nss_map_to_alias( mem_ctx
, domain
->name
, name
, alias
);
1180 if ( NT_STATUS_IS_OK( status
) ) {
1181 wcache_save_username_alias(domain
, status
, name
, *alias
);
1184 if ( NT_STATUS_EQUAL( status
, NT_STATUS_NONE_MAPPED
) ) {
1185 wcache_save_username_alias(domain
, status
, name
, "(NULL)");
1188 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1189 nt_errstr(status
)));
1191 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1192 set_domain_offline( domain
);
1198 /***************************************************************************
1199 ***************************************************************************/
1201 NTSTATUS
resolve_alias_to_username( TALLOC_CTX
*mem_ctx
,
1202 struct winbindd_domain
*domain
,
1203 const char *alias
, char **name
)
1205 struct winbind_cache
*cache
= get_cache(domain
);
1206 struct cache_entry
*centry
= NULL
;
1210 if ( domain
->internal
)
1211 return NT_STATUS_NOT_SUPPORTED
;
1216 upper_name
= talloc_strdup(mem_ctx
, alias
);
1217 if (upper_name
== NULL
) {
1218 return NT_STATUS_NO_MEMORY
;
1220 if (!strupper_m(upper_name
)) {
1221 talloc_free(upper_name
);
1222 return NT_STATUS_INVALID_PARAMETER
;
1225 centry
= wcache_fetch(cache
, domain
, "NSS/AN/%s", upper_name
);
1227 talloc_free(upper_name
);
1232 status
= centry
->status
;
1234 if (!NT_STATUS_IS_OK(status
)) {
1235 centry_free(centry
);
1239 *name
= centry_string( centry
, mem_ctx
);
1241 centry_free(centry
);
1243 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1244 alias
, *name
? *name
: "(none)"));
1246 return (*name
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1250 /* If its not in cache and we are offline, then fail */
1252 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1253 DEBUG(8,("resolve_alias_to_username: rejecting query "
1254 "in offline mode\n"));
1255 return NT_STATUS_NOT_FOUND
;
1258 /* an alias cannot contain a domain prefix or '@' */
1260 if (strchr(alias
, '\\') || strchr(alias
, '@')) {
1261 DEBUG(10,("resolve_alias_to_username: skipping fully "
1262 "qualified name %s\n", alias
));
1263 return NT_STATUS_OBJECT_NAME_INVALID
;
1266 status
= nss_map_from_alias( mem_ctx
, domain
->name
, alias
, name
);
1268 if ( NT_STATUS_IS_OK( status
) ) {
1269 wcache_save_alias_username( domain
, status
, alias
, *name
);
1272 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1273 wcache_save_alias_username(domain
, status
, alias
, "(NULL)");
1276 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1277 nt_errstr(status
)));
1279 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1280 set_domain_offline( domain
);
1286 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
1288 struct winbind_cache
*cache
= get_cache(domain
);
1290 fstring key_str
, tmp
;
1294 return NT_STATUS_INTERNAL_DB_ERROR
;
1297 if (is_null_sid(sid
)) {
1298 return NT_STATUS_INVALID_SID
;
1301 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1302 return NT_STATUS_INVALID_SID
;
1305 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
1307 data
= tdb_fetch(cache
->tdb
, string_tdb_data(key_str
));
1309 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1312 SAFE_FREE(data
.dptr
);
1313 return NT_STATUS_OK
;
1316 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1317 as new salted ones. */
1319 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
1320 TALLOC_CTX
*mem_ctx
,
1321 const struct dom_sid
*sid
,
1322 const uint8_t **cached_nt_pass
,
1323 const uint8_t **cached_salt
)
1325 struct winbind_cache
*cache
= get_cache(domain
);
1326 struct cache_entry
*centry
= NULL
;
1332 return NT_STATUS_INTERNAL_DB_ERROR
;
1335 if (is_null_sid(sid
)) {
1336 return NT_STATUS_INVALID_SID
;
1339 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1340 return NT_STATUS_INVALID_SID
;
1343 /* Try and get a salted cred first. If we can't
1344 fall back to an unsalted cred. */
1346 centry
= wcache_fetch(cache
, domain
, "CRED/%s",
1347 sid_to_fstring(tmp
, sid
));
1349 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1350 sid_string_dbg(sid
)));
1351 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1355 * We don't use the time element at this moment,
1356 * but we have to consume it, so that we don't
1357 * neet to change the disk format of the cache.
1359 (void)centry_time(centry
);
1361 /* In the salted case this isn't actually the nt_hash itself,
1362 but the MD5 of the salt + nt_hash. Let the caller
1363 sort this out. It can tell as we only return the cached_salt
1364 if we are returning a salted cred. */
1366 *cached_nt_pass
= (const uint8_t *)centry_hash16(centry
, mem_ctx
);
1367 if (*cached_nt_pass
== NULL
) {
1370 sid_to_fstring(sidstr
, sid
);
1372 /* Bad (old) cred cache. Delete and pretend we
1374 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1376 wcache_delete("CRED/%s", sidstr
);
1377 centry_free(centry
);
1378 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1381 /* We only have 17 bytes more data in the salted cred case. */
1382 if (centry
->len
- centry
->ofs
== 17) {
1383 *cached_salt
= (const uint8_t *)centry_hash16(centry
, mem_ctx
);
1385 *cached_salt
= NULL
;
1388 dump_data_pw("cached_nt_pass", *cached_nt_pass
, NT_HASH_LEN
);
1390 dump_data_pw("cached_salt", *cached_salt
, NT_HASH_LEN
);
1393 status
= centry
->status
;
1395 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1396 sid_string_dbg(sid
), nt_errstr(status
) ));
1398 centry_free(centry
);
1402 /* Store creds for a SID - only writes out new salted ones. */
1404 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1405 const struct dom_sid
*sid
,
1406 const uint8_t nt_pass
[NT_HASH_LEN
])
1408 struct cache_entry
*centry
;
1411 uint8_t cred_salt
[NT_HASH_LEN
];
1412 uint8_t salted_hash
[NT_HASH_LEN
];
1414 if (is_null_sid(sid
)) {
1415 return NT_STATUS_INVALID_SID
;
1418 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1419 return NT_STATUS_INVALID_SID
;
1422 centry
= centry_start(domain
, NT_STATUS_OK
);
1424 return NT_STATUS_INTERNAL_DB_ERROR
;
1427 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1429 centry_put_time(centry
, time(NULL
));
1431 /* Create a salt and then salt the hash. */
1432 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1433 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1435 centry_put_hash16(centry
, salted_hash
);
1436 centry_put_hash16(centry
, cred_salt
);
1437 centry_end(centry
, "CRED/%s", sid_to_fstring(sid_string
, sid
));
1439 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1441 centry_free(centry
);
1443 return NT_STATUS_OK
;
1447 /* Query display info. This is the basic user list fn */
1448 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
1449 TALLOC_CTX
*mem_ctx
,
1450 uint32_t *num_entries
,
1451 struct wbint_userinfo
**info
)
1453 struct winbind_cache
*cache
= get_cache(domain
);
1454 struct cache_entry
*centry
= NULL
;
1456 unsigned int i
, retry
;
1457 bool old_status
= domain
->online
;
1462 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1467 *num_entries
= centry_uint32(centry
);
1469 if (*num_entries
== 0)
1472 (*info
) = talloc_array(mem_ctx
, struct wbint_userinfo
, *num_entries
);
1474 smb_panic_fn("query_user_list out of memory");
1476 for (i
=0; i
<(*num_entries
); i
++) {
1477 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
1478 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
1479 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
1480 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
1481 centry_sid(centry
, &(*info
)[i
].user_sid
);
1482 centry_sid(centry
, &(*info
)[i
].group_sid
);
1486 status
= centry
->status
;
1488 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1489 domain
->name
, nt_errstr(status
) ));
1491 centry_free(centry
);
1498 /* Return status value returned by seq number check */
1500 if (!NT_STATUS_IS_OK(domain
->last_status
))
1501 return domain
->last_status
;
1503 /* Put the query_user_list() in a retry loop. There appears to be
1504 * some bug either with Windows 2000 or Samba's handling of large
1505 * rpc replies. This manifests itself as sudden disconnection
1506 * at a random point in the enumeration of a large (60k) user list.
1507 * The retry loop simply tries the operation again. )-: It's not
1508 * pretty but an acceptable workaround until we work out what the
1509 * real problem is. */
1514 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1517 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
1518 if (!NT_STATUS_IS_OK(status
)) {
1519 DEBUG(3, ("query_user_list: returned 0x%08x, "
1520 "retrying\n", NT_STATUS_V(status
)));
1522 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1523 DEBUG(3, ("query_user_list: flushing "
1524 "connection cache\n"));
1525 invalidate_cm_connection(domain
);
1527 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1528 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1529 if (!domain
->internal
&& old_status
) {
1530 set_domain_offline(domain
);
1532 /* store partial response. */
1533 if (*num_entries
> 0) {
1535 * humm, what about the status used for cache?
1536 * Should it be NT_STATUS_OK?
1541 * domain is offline now, and there is no user entries,
1542 * try to fetch from cache again.
1544 if (cache
->tdb
&& !domain
->online
&& !domain
->internal
&& old_status
) {
1545 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1546 /* partial response... */
1550 goto do_fetch_cache
;
1557 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1561 refresh_sequence_number(domain
, false);
1562 if (!NT_STATUS_IS_OK(status
)) {
1565 centry
= centry_start(domain
, status
);
1568 centry_put_uint32(centry
, *num_entries
);
1569 for (i
=0; i
<(*num_entries
); i
++) {
1570 centry_put_string(centry
, (*info
)[i
].acct_name
);
1571 centry_put_string(centry
, (*info
)[i
].full_name
);
1572 centry_put_string(centry
, (*info
)[i
].homedir
);
1573 centry_put_string(centry
, (*info
)[i
].shell
);
1574 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1575 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1576 if (domain
->backend
&& domain
->backend
->consistent
) {
1577 /* when the backend is consistent we can pre-prime some mappings */
1578 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1580 (*info
)[i
].acct_name
,
1581 &(*info
)[i
].user_sid
,
1583 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1584 &(*info
)[i
].user_sid
,
1586 (*info
)[i
].acct_name
,
1588 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1591 centry_end(centry
, "UL/%s", domain
->name
);
1592 centry_free(centry
);
1598 /* list all domain groups */
1599 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
1600 TALLOC_CTX
*mem_ctx
,
1601 uint32_t *num_entries
,
1602 struct wb_acct_info
**info
)
1604 struct winbind_cache
*cache
= get_cache(domain
);
1605 struct cache_entry
*centry
= NULL
;
1610 old_status
= domain
->online
;
1614 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1619 *num_entries
= centry_uint32(centry
);
1621 if (*num_entries
== 0)
1624 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1626 smb_panic_fn("enum_dom_groups out of memory");
1628 for (i
=0; i
<(*num_entries
); i
++) {
1629 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1630 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1631 (*info
)[i
].rid
= centry_uint32(centry
);
1635 status
= centry
->status
;
1637 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1638 domain
->name
, nt_errstr(status
) ));
1640 centry_free(centry
);
1647 /* Return status value returned by seq number check */
1649 if (!NT_STATUS_IS_OK(domain
->last_status
))
1650 return domain
->last_status
;
1652 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1655 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1657 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1658 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1659 if (!domain
->internal
&& old_status
) {
1660 set_domain_offline(domain
);
1664 !domain
->internal
&&
1666 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1668 goto do_fetch_cache
;
1673 refresh_sequence_number(domain
, false);
1674 if (!NT_STATUS_IS_OK(status
)) {
1677 centry
= centry_start(domain
, status
);
1680 centry_put_uint32(centry
, *num_entries
);
1681 for (i
=0; i
<(*num_entries
); i
++) {
1682 centry_put_string(centry
, (*info
)[i
].acct_name
);
1683 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1684 centry_put_uint32(centry
, (*info
)[i
].rid
);
1686 centry_end(centry
, "GL/%s/domain", domain
->name
);
1687 centry_free(centry
);
1693 /* list all domain groups */
1694 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
1695 TALLOC_CTX
*mem_ctx
,
1696 uint32_t *num_entries
,
1697 struct wb_acct_info
**info
)
1699 struct winbind_cache
*cache
= get_cache(domain
);
1700 struct cache_entry
*centry
= NULL
;
1705 old_status
= domain
->online
;
1709 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1714 *num_entries
= centry_uint32(centry
);
1716 if (*num_entries
== 0)
1719 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1721 smb_panic_fn("enum_dom_groups out of memory");
1723 for (i
=0; i
<(*num_entries
); i
++) {
1724 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1725 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1726 (*info
)[i
].rid
= centry_uint32(centry
);
1731 /* If we are returning cached data and the domain controller
1732 is down then we don't know whether the data is up to date
1733 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1736 if (wcache_server_down(domain
)) {
1737 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1738 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1740 status
= centry
->status
;
1742 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1743 domain
->name
, nt_errstr(status
) ));
1745 centry_free(centry
);
1752 /* Return status value returned by seq number check */
1754 if (!NT_STATUS_IS_OK(domain
->last_status
))
1755 return domain
->last_status
;
1757 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1760 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1762 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1763 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1764 if (!domain
->internal
&& old_status
) {
1765 set_domain_offline(domain
);
1768 !domain
->internal
&&
1771 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1773 goto do_fetch_cache
;
1778 refresh_sequence_number(domain
, false);
1779 if (!NT_STATUS_IS_OK(status
)) {
1782 centry
= centry_start(domain
, status
);
1785 centry_put_uint32(centry
, *num_entries
);
1786 for (i
=0; i
<(*num_entries
); i
++) {
1787 centry_put_string(centry
, (*info
)[i
].acct_name
);
1788 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1789 centry_put_uint32(centry
, (*info
)[i
].rid
);
1791 centry_end(centry
, "GL/%s/local", domain
->name
);
1792 centry_free(centry
);
1798 NTSTATUS
wcache_name_to_sid(struct winbindd_domain
*domain
,
1799 const char *domain_name
,
1801 struct dom_sid
*sid
,
1802 enum lsa_SidType
*type
)
1804 struct winbind_cache
*cache
= get_cache(domain
);
1805 struct cache_entry
*centry
;
1809 if (cache
->tdb
== NULL
) {
1810 return NT_STATUS_NOT_FOUND
;
1813 uname
= talloc_strdup_upper(talloc_tos(), name
);
1814 if (uname
== NULL
) {
1815 return NT_STATUS_NO_MEMORY
;
1818 if ((domain_name
== NULL
) || (domain_name
[0] == '\0')) {
1819 domain_name
= domain
->name
;
1822 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1824 if (centry
== NULL
) {
1825 return NT_STATUS_NOT_FOUND
;
1828 status
= centry
->status
;
1829 if (NT_STATUS_IS_OK(status
)) {
1830 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1831 centry_sid(centry
, sid
);
1834 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1835 "%s\n", domain
->name
, nt_errstr(status
) ));
1837 centry_free(centry
);
1841 /* convert a single name to a sid in a domain */
1842 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
1843 TALLOC_CTX
*mem_ctx
,
1844 const char *domain_name
,
1847 struct dom_sid
*sid
,
1848 enum lsa_SidType
*type
)
1853 old_status
= domain
->online
;
1855 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1856 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1862 /* If the seq number check indicated that there is a problem
1863 * with this DC, then return that status... except for
1864 * access_denied. This is special because the dc may be in
1865 * "restrict anonymous = 1" mode, in which case it will deny
1866 * most unauthenticated operations, but *will* allow the LSA
1867 * name-to-sid that we try as a fallback. */
1869 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1870 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1871 return domain
->last_status
;
1873 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1876 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
,
1877 name
, flags
, sid
, type
);
1879 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1880 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1881 if (!domain
->internal
&& old_status
) {
1882 set_domain_offline(domain
);
1884 if (!domain
->internal
&&
1887 NTSTATUS cache_status
;
1888 cache_status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1889 return cache_status
;
1893 refresh_sequence_number(domain
, false);
1895 if (domain
->online
&&
1896 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1897 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1899 /* Only save the reverse mapping if this was not a UPN */
1900 if (!strchr(name
, '@')) {
1901 if (!strupper_m(discard_const_p(char, domain_name
))) {
1902 return NT_STATUS_INVALID_PARAMETER
;
1904 (void)strlower_m(discard_const_p(char, name
));
1905 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1912 static NTSTATUS
wcache_sid_to_name(struct winbindd_domain
*domain
,
1913 const struct dom_sid
*sid
,
1914 TALLOC_CTX
*mem_ctx
,
1917 enum lsa_SidType
*type
)
1919 struct winbind_cache
*cache
= get_cache(domain
);
1920 struct cache_entry
*centry
;
1924 if (cache
->tdb
== NULL
) {
1925 return NT_STATUS_NOT_FOUND
;
1928 sid_string
= sid_string_tos(sid
);
1929 if (sid_string
== NULL
) {
1930 return NT_STATUS_NO_MEMORY
;
1933 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_string
);
1934 TALLOC_FREE(sid_string
);
1935 if (centry
== NULL
) {
1936 return NT_STATUS_NOT_FOUND
;
1939 if (NT_STATUS_IS_OK(centry
->status
)) {
1940 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1941 *domain_name
= centry_string(centry
, mem_ctx
);
1942 *name
= centry_string(centry
, mem_ctx
);
1945 status
= centry
->status
;
1946 centry_free(centry
);
1948 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1949 "%s\n", domain
->name
, nt_errstr(status
) ));
1954 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1956 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1957 TALLOC_CTX
*mem_ctx
,
1958 const struct dom_sid
*sid
,
1961 enum lsa_SidType
*type
)
1966 old_status
= domain
->online
;
1967 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
1969 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1974 *domain_name
= NULL
;
1976 /* If the seq number check indicated that there is a problem
1977 * with this DC, then return that status... except for
1978 * access_denied. This is special because the dc may be in
1979 * "restrict anonymous = 1" mode, in which case it will deny
1980 * most unauthenticated operations, but *will* allow the LSA
1981 * sid-to-name that we try as a fallback. */
1983 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1984 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1985 return domain
->last_status
;
1987 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1990 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1992 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1993 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1994 if (!domain
->internal
&& old_status
) {
1995 set_domain_offline(domain
);
1997 if (!domain
->internal
&&
2000 NTSTATUS cache_status
;
2001 cache_status
= wcache_sid_to_name(domain
, sid
, mem_ctx
,
2002 domain_name
, name
, type
);
2003 return cache_status
;
2007 refresh_sequence_number(domain
, false);
2008 if (!NT_STATUS_IS_OK(status
)) {
2011 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
2013 /* We can't save the name to sid mapping here, as with sid history a
2014 * later name2sid would give the wrong sid. */
2019 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
2020 TALLOC_CTX
*mem_ctx
,
2021 const struct dom_sid
*domain_sid
,
2026 enum lsa_SidType
**types
)
2028 struct winbind_cache
*cache
= get_cache(domain
);
2030 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
2035 old_status
= domain
->online
;
2036 *domain_name
= NULL
;
2044 if (num_rids
== 0) {
2045 return NT_STATUS_OK
;
2048 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2049 *types
= talloc_array(mem_ctx
, enum lsa_SidType
, num_rids
);
2051 if ((*names
== NULL
) || (*types
== NULL
)) {
2052 result
= NT_STATUS_NO_MEMORY
;
2056 have_mapped
= have_unmapped
= false;
2058 for (i
=0; i
<num_rids
; i
++) {
2060 struct cache_entry
*centry
;
2063 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2064 result
= NT_STATUS_INTERNAL_ERROR
;
2068 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2069 sid_to_fstring(tmp
, &sid
));
2074 (*types
)[i
] = SID_NAME_UNKNOWN
;
2075 (*names
)[i
] = talloc_strdup(*names
, "");
2077 if (NT_STATUS_IS_OK(centry
->status
)) {
2080 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2082 dom
= centry_string(centry
, mem_ctx
);
2083 if (*domain_name
== NULL
) {
2089 (*names
)[i
] = centry_string(centry
, *names
);
2091 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)
2092 || NT_STATUS_EQUAL(centry
->status
, STATUS_SOME_UNMAPPED
)) {
2093 have_unmapped
= true;
2096 /* something's definitely wrong */
2097 result
= centry
->status
;
2098 centry_free(centry
);
2102 centry_free(centry
);
2106 return NT_STATUS_NONE_MAPPED
;
2108 if (!have_unmapped
) {
2109 return NT_STATUS_OK
;
2111 return STATUS_SOME_UNMAPPED
;
2115 TALLOC_FREE(*names
);
2116 TALLOC_FREE(*types
);
2118 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
2119 rids
, num_rids
, domain_name
,
2122 if (NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
2123 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2124 if (!domain
->internal
&& old_status
) {
2125 set_domain_offline(domain
);
2128 !domain
->internal
&&
2131 have_mapped
= have_unmapped
= false;
2133 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2134 if (*names
== NULL
) {
2135 result
= NT_STATUS_NO_MEMORY
;
2139 *types
= talloc_array(mem_ctx
, enum lsa_SidType
,
2141 if (*types
== NULL
) {
2142 result
= NT_STATUS_NO_MEMORY
;
2146 for (i
=0; i
<num_rids
; i
++) {
2148 struct cache_entry
*centry
;
2151 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2152 result
= NT_STATUS_INTERNAL_ERROR
;
2156 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2157 sid_to_fstring(tmp
, &sid
));
2159 (*types
)[i
] = SID_NAME_UNKNOWN
;
2160 (*names
)[i
] = talloc_strdup(*names
, "");
2164 (*types
)[i
] = SID_NAME_UNKNOWN
;
2165 (*names
)[i
] = talloc_strdup(*names
, "");
2167 if (NT_STATUS_IS_OK(centry
->status
)) {
2170 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2172 dom
= centry_string(centry
, mem_ctx
);
2173 if (*domain_name
== NULL
) {
2179 (*names
)[i
] = centry_string(centry
, *names
);
2181 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)) {
2182 have_unmapped
= true;
2185 /* something's definitely wrong */
2186 result
= centry
->status
;
2187 centry_free(centry
);
2191 centry_free(centry
);
2195 return NT_STATUS_NONE_MAPPED
;
2197 if (!have_unmapped
) {
2198 return NT_STATUS_OK
;
2200 return STATUS_SOME_UNMAPPED
;
2204 None of the queried rids has been found so save all negative entries
2206 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
2207 for (i
= 0; i
< num_rids
; i
++) {
2209 const char *name
= "";
2210 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
2211 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
2213 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2214 return NT_STATUS_INTERNAL_ERROR
;
2217 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2225 Some or all of the queried rids have been found.
2227 if (!NT_STATUS_IS_OK(result
) &&
2228 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
2232 refresh_sequence_number(domain
, false);
2234 for (i
=0; i
<num_rids
; i
++) {
2238 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2239 result
= NT_STATUS_INTERNAL_ERROR
;
2243 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
2244 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
2246 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2247 (*names
)[i
], (*types
)[i
]);
2253 TALLOC_FREE(*names
);
2254 TALLOC_FREE(*types
);
2258 NTSTATUS
wcache_query_user(struct winbindd_domain
*domain
,
2259 TALLOC_CTX
*mem_ctx
,
2260 const struct dom_sid
*user_sid
,
2261 struct wbint_userinfo
*info
)
2263 struct winbind_cache
*cache
= get_cache(domain
);
2264 struct cache_entry
*centry
= NULL
;
2268 if (cache
->tdb
== NULL
) {
2269 return NT_STATUS_NOT_FOUND
;
2272 sid_string
= sid_string_tos(user_sid
);
2273 if (sid_string
== NULL
) {
2274 return NT_STATUS_NO_MEMORY
;
2277 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string
);
2278 TALLOC_FREE(sid_string
);
2279 if (centry
== NULL
) {
2280 return NT_STATUS_NOT_FOUND
;
2284 * If we have an access denied cache entry and a cached info3
2285 * in the samlogon cache then do a query. This will force the
2286 * rpc back end to return the info3 data.
2289 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
) &&
2290 netsamlogon_cache_have(user_sid
)) {
2291 DEBUG(10, ("query_user: cached access denied and have cached "
2293 domain
->last_status
= NT_STATUS_OK
;
2294 centry_free(centry
);
2295 return NT_STATUS_NOT_FOUND
;
2298 /* if status is not ok then this is a negative hit
2299 and the rest of the data doesn't matter */
2300 status
= centry
->status
;
2301 if (NT_STATUS_IS_OK(status
)) {
2302 info
->acct_name
= centry_string(centry
, mem_ctx
);
2303 info
->full_name
= centry_string(centry
, mem_ctx
);
2304 info
->homedir
= centry_string(centry
, mem_ctx
);
2305 info
->shell
= centry_string(centry
, mem_ctx
);
2306 info
->primary_gid
= centry_uint32(centry
);
2307 centry_sid(centry
, &info
->user_sid
);
2308 centry_sid(centry
, &info
->group_sid
);
2311 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2312 "%s\n", domain
->name
, nt_errstr(status
) ));
2314 centry_free(centry
);
2320 * @brief Query a fullname from the username cache (for further gecos processing)
2322 * @param domain A pointer to the winbindd_domain struct.
2323 * @param mem_ctx The talloc context.
2324 * @param user_sid The user sid.
2325 * @param full_name A pointer to the full_name string.
2327 * @return NTSTATUS code
2329 NTSTATUS
wcache_query_user_fullname(struct winbindd_domain
*domain
,
2330 TALLOC_CTX
*mem_ctx
,
2331 const struct dom_sid
*user_sid
,
2332 const char **full_name
)
2335 struct wbint_userinfo info
;
2337 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, &info
);
2338 if (!NT_STATUS_IS_OK(status
)) {
2342 if (info
.full_name
!= NULL
) {
2343 *full_name
= talloc_strdup(mem_ctx
, info
.full_name
);
2344 if (*full_name
== NULL
) {
2345 return NT_STATUS_NO_MEMORY
;
2349 return NT_STATUS_OK
;
2352 /* Lookup user information from a rid */
2353 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
2354 TALLOC_CTX
*mem_ctx
,
2355 const struct dom_sid
*user_sid
,
2356 struct wbint_userinfo
*info
)
2361 old_status
= domain
->online
;
2362 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2363 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2369 /* Return status value returned by seq number check */
2371 if (!NT_STATUS_IS_OK(domain
->last_status
))
2372 return domain
->last_status
;
2374 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2377 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
2379 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2380 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2381 if (!domain
->internal
&& old_status
) {
2382 set_domain_offline(domain
);
2384 if (!domain
->internal
&&
2387 NTSTATUS cache_status
;
2388 cache_status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2389 return cache_status
;
2393 refresh_sequence_number(domain
, false);
2394 if (!NT_STATUS_IS_OK(status
)) {
2397 wcache_save_user(domain
, status
, info
);
2402 NTSTATUS
wcache_lookup_usergroups(struct winbindd_domain
*domain
,
2403 TALLOC_CTX
*mem_ctx
,
2404 const struct dom_sid
*user_sid
,
2405 uint32_t *pnum_sids
,
2406 struct dom_sid
**psids
)
2408 struct winbind_cache
*cache
= get_cache(domain
);
2409 struct cache_entry
*centry
= NULL
;
2411 uint32_t i
, num_sids
;
2412 struct dom_sid
*sids
;
2415 if (cache
->tdb
== NULL
) {
2416 return NT_STATUS_NOT_FOUND
;
2419 centry
= wcache_fetch(cache
, domain
, "UG/%s",
2420 sid_to_fstring(sid_string
, user_sid
));
2421 if (centry
== NULL
) {
2422 return NT_STATUS_NOT_FOUND
;
2425 /* If we have an access denied cache entry and a cached info3 in the
2426 samlogon cache then do a query. This will force the rpc back end
2427 to return the info3 data. */
2429 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)
2430 && netsamlogon_cache_have(user_sid
)) {
2431 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2433 domain
->last_status
= NT_STATUS_OK
;
2434 centry_free(centry
);
2435 return NT_STATUS_NOT_FOUND
;
2438 num_sids
= centry_uint32(centry
);
2439 sids
= talloc_array(mem_ctx
, struct dom_sid
, num_sids
);
2441 centry_free(centry
);
2442 return NT_STATUS_NO_MEMORY
;
2445 for (i
=0; i
<num_sids
; i
++) {
2446 centry_sid(centry
, &sids
[i
]);
2449 status
= centry
->status
;
2451 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2452 "status: %s\n", domain
->name
, nt_errstr(status
)));
2454 centry_free(centry
);
2456 *pnum_sids
= num_sids
;
2461 /* Lookup groups a user is a member of. */
2462 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
2463 TALLOC_CTX
*mem_ctx
,
2464 const struct dom_sid
*user_sid
,
2465 uint32_t *num_groups
, struct dom_sid
**user_gids
)
2467 struct cache_entry
*centry
= NULL
;
2473 old_status
= domain
->online
;
2474 status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2475 num_groups
, user_gids
);
2476 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2481 (*user_gids
) = NULL
;
2483 /* Return status value returned by seq number check */
2485 if (!NT_STATUS_IS_OK(domain
->last_status
))
2486 return domain
->last_status
;
2488 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2491 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
2493 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2494 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2495 if (!domain
->internal
&& old_status
) {
2496 set_domain_offline(domain
);
2498 if (!domain
->internal
&&
2501 NTSTATUS cache_status
;
2502 cache_status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2503 num_groups
, user_gids
);
2504 return cache_status
;
2507 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
2511 refresh_sequence_number(domain
, false);
2512 if (!NT_STATUS_IS_OK(status
)) {
2515 centry
= centry_start(domain
, status
);
2519 centry_put_uint32(centry
, *num_groups
);
2520 for (i
=0; i
<(*num_groups
); i
++) {
2521 centry_put_sid(centry
, &(*user_gids
)[i
]);
2524 centry_end(centry
, "UG/%s", sid_to_fstring(sid_string
, user_sid
));
2525 centry_free(centry
);
2531 static char *wcache_make_sidlist(TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2532 const struct dom_sid
*sids
)
2537 sidlist
= talloc_strdup(mem_ctx
, "");
2538 if (sidlist
== NULL
) {
2541 for (i
=0; i
<num_sids
; i
++) {
2543 sidlist
= talloc_asprintf_append_buffer(
2544 sidlist
, "/%s", sid_to_fstring(tmp
, &sids
[i
]));
2545 if (sidlist
== NULL
) {
2552 NTSTATUS
wcache_lookup_useraliases(struct winbindd_domain
*domain
,
2553 TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2554 const struct dom_sid
*sids
,
2555 uint32_t *pnum_aliases
, uint32_t **paliases
)
2557 struct winbind_cache
*cache
= get_cache(domain
);
2558 struct cache_entry
*centry
= NULL
;
2559 uint32_t num_aliases
;
2565 if (cache
->tdb
== NULL
) {
2566 return NT_STATUS_NOT_FOUND
;
2569 if (num_sids
== 0) {
2572 return NT_STATUS_OK
;
2575 /* We need to cache indexed by the whole list of SIDs, the aliases
2576 * resulting might come from any of the SIDs. */
2578 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2579 if (sidlist
== NULL
) {
2580 return NT_STATUS_NO_MEMORY
;
2583 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2584 TALLOC_FREE(sidlist
);
2585 if (centry
== NULL
) {
2586 return NT_STATUS_NOT_FOUND
;
2589 num_aliases
= centry_uint32(centry
);
2590 aliases
= talloc_array(mem_ctx
, uint32_t, num_aliases
);
2591 if (aliases
== NULL
) {
2592 centry_free(centry
);
2593 return NT_STATUS_NO_MEMORY
;
2596 for (i
=0; i
<num_aliases
; i
++) {
2597 aliases
[i
] = centry_uint32(centry
);
2600 status
= centry
->status
;
2602 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2603 "status %s\n", domain
->name
, nt_errstr(status
)));
2605 centry_free(centry
);
2607 *pnum_aliases
= num_aliases
;
2608 *paliases
= aliases
;
2613 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
2614 TALLOC_CTX
*mem_ctx
,
2615 uint32_t num_sids
, const struct dom_sid
*sids
,
2616 uint32_t *num_aliases
, uint32_t **alias_rids
)
2618 struct cache_entry
*centry
= NULL
;
2624 old_status
= domain
->online
;
2625 status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
2626 num_aliases
, alias_rids
);
2627 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2632 (*alias_rids
) = NULL
;
2634 if (!NT_STATUS_IS_OK(domain
->last_status
))
2635 return domain
->last_status
;
2637 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2638 "for domain %s\n", domain
->name
));
2640 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2641 if (sidlist
== NULL
) {
2642 return NT_STATUS_NO_MEMORY
;
2645 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2647 num_aliases
, alias_rids
);
2649 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2650 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2651 if (!domain
->internal
&& old_status
) {
2652 set_domain_offline(domain
);
2654 if (!domain
->internal
&&
2657 NTSTATUS cache_status
;
2658 cache_status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
,
2659 sids
, num_aliases
, alias_rids
);
2660 return cache_status
;
2664 refresh_sequence_number(domain
, false);
2665 if (!NT_STATUS_IS_OK(status
)) {
2668 centry
= centry_start(domain
, status
);
2671 centry_put_uint32(centry
, *num_aliases
);
2672 for (i
=0; i
<(*num_aliases
); i
++)
2673 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2674 centry_end(centry
, "UA%s", sidlist
);
2675 centry_free(centry
);
2681 NTSTATUS
wcache_lookup_groupmem(struct winbindd_domain
*domain
,
2682 TALLOC_CTX
*mem_ctx
,
2683 const struct dom_sid
*group_sid
,
2684 uint32_t *num_names
,
2685 struct dom_sid
**sid_mem
, char ***names
,
2686 uint32_t **name_types
)
2688 struct winbind_cache
*cache
= get_cache(domain
);
2689 struct cache_entry
*centry
= NULL
;
2694 if (cache
->tdb
== NULL
) {
2695 return NT_STATUS_NOT_FOUND
;
2698 sid_string
= sid_string_tos(group_sid
);
2699 if (sid_string
== NULL
) {
2700 return NT_STATUS_NO_MEMORY
;
2703 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_string
);
2704 TALLOC_FREE(sid_string
);
2705 if (centry
== NULL
) {
2706 return NT_STATUS_NOT_FOUND
;
2713 *num_names
= centry_uint32(centry
);
2714 if (*num_names
== 0) {
2715 centry_free(centry
);
2716 return NT_STATUS_OK
;
2719 *sid_mem
= talloc_array(mem_ctx
, struct dom_sid
, *num_names
);
2720 *names
= talloc_array(mem_ctx
, char *, *num_names
);
2721 *name_types
= talloc_array(mem_ctx
, uint32_t, *num_names
);
2723 if ((*sid_mem
== NULL
) || (*names
== NULL
) || (*name_types
== NULL
)) {
2724 TALLOC_FREE(*sid_mem
);
2725 TALLOC_FREE(*names
);
2726 TALLOC_FREE(*name_types
);
2727 centry_free(centry
);
2728 return NT_STATUS_NO_MEMORY
;
2731 for (i
=0; i
<(*num_names
); i
++) {
2732 centry_sid(centry
, &(*sid_mem
)[i
]);
2733 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2734 (*name_types
)[i
] = centry_uint32(centry
);
2737 status
= centry
->status
;
2739 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2740 "status: %s\n", domain
->name
, nt_errstr(status
)));
2742 centry_free(centry
);
2746 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
2747 TALLOC_CTX
*mem_ctx
,
2748 const struct dom_sid
*group_sid
,
2749 enum lsa_SidType type
,
2750 uint32_t *num_names
,
2751 struct dom_sid
**sid_mem
, char ***names
,
2752 uint32_t **name_types
)
2754 struct cache_entry
*centry
= NULL
;
2760 old_status
= domain
->online
;
2761 status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2762 sid_mem
, names
, name_types
);
2763 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2770 (*name_types
) = NULL
;
2772 /* Return status value returned by seq number check */
2774 if (!NT_STATUS_IS_OK(domain
->last_status
))
2775 return domain
->last_status
;
2777 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2780 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
,
2782 sid_mem
, names
, name_types
);
2784 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2785 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2786 if (!domain
->internal
&& old_status
) {
2787 set_domain_offline(domain
);
2789 if (!domain
->internal
&&
2792 NTSTATUS cache_status
;
2793 cache_status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
,
2794 num_names
, sid_mem
, names
,
2796 return cache_status
;
2800 refresh_sequence_number(domain
, false);
2801 if (!NT_STATUS_IS_OK(status
)) {
2804 centry
= centry_start(domain
, status
);
2807 centry_put_uint32(centry
, *num_names
);
2808 for (i
=0; i
<(*num_names
); i
++) {
2809 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2810 centry_put_string(centry
, (*names
)[i
]);
2811 centry_put_uint32(centry
, (*name_types
)[i
]);
2813 centry_end(centry
, "GM/%s", sid_to_fstring(sid_string
, group_sid
));
2814 centry_free(centry
);
2820 /* find the sequence number for a domain */
2821 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32_t *seq
)
2823 refresh_sequence_number(domain
, false);
2825 *seq
= domain
->sequence_number
;
2827 return NT_STATUS_OK
;
2830 /* enumerate trusted domains
2831 * (we need to have the list of trustdoms in the cache when we go offline) -
2833 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
2834 TALLOC_CTX
*mem_ctx
,
2835 struct netr_DomainTrustList
*trusts
)
2838 struct winbind_cache
*cache
;
2839 struct winbindd_tdc_domain
*dom_list
= NULL
;
2840 size_t num_domains
= 0;
2841 bool retval
= false;
2845 old_status
= domain
->online
;
2847 trusts
->array
= NULL
;
2849 cache
= get_cache(domain
);
2850 if (!cache
|| !cache
->tdb
) {
2854 if (domain
->online
) {
2858 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2859 if (!retval
|| !num_domains
|| !dom_list
) {
2860 TALLOC_FREE(dom_list
);
2865 trusts
->array
= talloc_zero_array(mem_ctx
, struct netr_DomainTrust
, num_domains
);
2866 if (!trusts
->array
) {
2867 TALLOC_FREE(dom_list
);
2868 return NT_STATUS_NO_MEMORY
;
2871 for (i
= 0; i
< num_domains
; i
++) {
2872 struct netr_DomainTrust
*trust
;
2873 struct dom_sid
*sid
;
2874 struct winbindd_domain
*dom
;
2876 dom
= find_domain_from_name_noinit(dom_list
[i
].domain_name
);
2877 if (dom
&& dom
->internal
) {
2881 trust
= &trusts
->array
[trusts
->count
];
2882 trust
->netbios_name
= talloc_strdup(trusts
->array
, dom_list
[i
].domain_name
);
2883 trust
->dns_name
= talloc_strdup(trusts
->array
, dom_list
[i
].dns_name
);
2884 sid
= talloc(trusts
->array
, struct dom_sid
);
2885 if (!trust
->netbios_name
|| !trust
->dns_name
||
2887 TALLOC_FREE(dom_list
);
2888 TALLOC_FREE(trusts
->array
);
2889 return NT_STATUS_NO_MEMORY
;
2892 trust
->trust_flags
= dom_list
[i
].trust_flags
;
2893 trust
->trust_attributes
= dom_list
[i
].trust_attribs
;
2894 trust
->trust_type
= dom_list
[i
].trust_type
;
2895 sid_copy(sid
, &dom_list
[i
].sid
);
2900 TALLOC_FREE(dom_list
);
2901 return NT_STATUS_OK
;
2904 /* Return status value returned by seq number check */
2906 if (!NT_STATUS_IS_OK(domain
->last_status
))
2907 return domain
->last_status
;
2909 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2912 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, trusts
);
2914 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2915 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2916 if (!domain
->internal
&& old_status
) {
2917 set_domain_offline(domain
);
2919 if (!domain
->internal
&&
2922 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2923 if (retval
&& num_domains
&& dom_list
) {
2924 TALLOC_FREE(trusts
->array
);
2926 goto do_fetch_cache
;
2930 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2931 * so that the generic centry handling still applies correctly -
2934 if (!NT_STATUS_IS_ERR(status
)) {
2935 status
= NT_STATUS_OK
;
2940 /* get lockout policy */
2941 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
2942 TALLOC_CTX
*mem_ctx
,
2943 struct samr_DomInfo12
*policy
)
2945 struct winbind_cache
*cache
= get_cache(domain
);
2946 struct cache_entry
*centry
= NULL
;
2950 old_status
= domain
->online
;
2954 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2960 policy
->lockout_duration
= centry_nttime(centry
);
2961 policy
->lockout_window
= centry_nttime(centry
);
2962 policy
->lockout_threshold
= centry_uint16(centry
);
2964 status
= centry
->status
;
2966 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2967 domain
->name
, nt_errstr(status
) ));
2969 centry_free(centry
);
2973 ZERO_STRUCTP(policy
);
2975 /* Return status value returned by seq number check */
2977 if (!NT_STATUS_IS_OK(domain
->last_status
))
2978 return domain
->last_status
;
2980 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2983 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2985 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2986 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2987 if (!domain
->internal
&& old_status
) {
2988 set_domain_offline(domain
);
2991 !domain
->internal
&&
2994 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2996 goto do_fetch_cache
;
3001 refresh_sequence_number(domain
, false);
3002 if (!NT_STATUS_IS_OK(status
)) {
3005 wcache_save_lockout_policy(domain
, status
, policy
);
3010 /* get password policy */
3011 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
3012 TALLOC_CTX
*mem_ctx
,
3013 struct samr_DomInfo1
*policy
)
3015 struct winbind_cache
*cache
= get_cache(domain
);
3016 struct cache_entry
*centry
= NULL
;
3020 old_status
= domain
->online
;
3024 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
3030 policy
->min_password_length
= centry_uint16(centry
);
3031 policy
->password_history_length
= centry_uint16(centry
);
3032 policy
->password_properties
= centry_uint32(centry
);
3033 policy
->max_password_age
= centry_nttime(centry
);
3034 policy
->min_password_age
= centry_nttime(centry
);
3036 status
= centry
->status
;
3038 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
3039 domain
->name
, nt_errstr(status
) ));
3041 centry_free(centry
);
3045 ZERO_STRUCTP(policy
);
3047 /* Return status value returned by seq number check */
3049 if (!NT_STATUS_IS_OK(domain
->last_status
))
3050 return domain
->last_status
;
3052 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
3055 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
3057 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
3058 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
3059 if (!domain
->internal
&& old_status
) {
3060 set_domain_offline(domain
);
3063 !domain
->internal
&&
3066 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
3068 goto do_fetch_cache
;
3073 refresh_sequence_number(domain
, false);
3074 if (!NT_STATUS_IS_OK(status
)) {
3077 wcache_save_password_policy(domain
, status
, policy
);
3083 /* Invalidate cached user and group lists coherently */
3085 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3088 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
3089 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
3090 tdb_delete(the_tdb
, kbuf
);
3095 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3097 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
3098 const struct dom_sid
*sid
)
3100 fstring key_str
, sid_string
;
3101 struct winbind_cache
*cache
;
3103 /* don't clear cached U/SID and UG/SID entries when we want to logon
3106 if (lp_winbind_offline_logon()) {
3113 cache
= get_cache(domain
);
3119 /* Clear U/SID cache entry */
3120 fstr_sprintf(key_str
, "U/%s", sid_to_fstring(sid_string
, sid
));
3121 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3122 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3124 /* Clear UG/SID cache entry */
3125 fstr_sprintf(key_str
, "UG/%s", sid_to_fstring(sid_string
, sid
));
3126 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3127 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3129 /* Samba/winbindd never needs this. */
3130 netsamlogon_clear_cached_user(sid
);
3133 bool wcache_invalidate_cache(void)
3135 struct winbindd_domain
*domain
;
3137 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3138 struct winbind_cache
*cache
= get_cache(domain
);
3140 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3141 "entries for %s\n", domain
->name
));
3144 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3153 bool wcache_invalidate_cache_noinit(void)
3155 struct winbindd_domain
*domain
;
3157 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3158 struct winbind_cache
*cache
;
3160 /* Skip uninitialized domains. */
3161 if (!domain
->initialized
&& !domain
->internal
) {
3165 cache
= get_cache(domain
);
3167 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3168 "entries for %s\n", domain
->name
));
3171 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3173 * Flushing cache has nothing to with domains.
3174 * return here if we successfully flushed once.
3175 * To avoid unnecessary traversing the cache.
3186 bool init_wcache(void)
3190 if (wcache
== NULL
) {
3191 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
3192 ZERO_STRUCTP(wcache
);
3195 if (wcache
->tdb
!= NULL
)
3198 db_path
= state_path("winbindd_cache.tdb");
3199 if (db_path
== NULL
) {
3203 /* when working offline we must not clear the cache on restart */
3204 wcache
->tdb
= tdb_open_log(db_path
,
3205 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3206 TDB_INCOMPATIBLE_HASH
|
3207 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3208 O_RDWR
|O_CREAT
, 0600);
3209 TALLOC_FREE(db_path
);
3210 if (wcache
->tdb
== NULL
) {
3211 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3218 /************************************************************************
3219 This is called by the parent to initialize the cache file.
3220 We don't need sophisticated locking here as we know we're the
3222 ************************************************************************/
3224 bool initialize_winbindd_cache(void)
3226 bool cache_bad
= true;
3229 if (!init_wcache()) {
3230 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3234 /* Check version number. */
3235 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
3236 vers
== WINBINDD_CACHE_VERSION
) {
3243 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3244 "and re-creating with version number %d\n",
3245 WINBINDD_CACHE_VERSION
));
3247 tdb_close(wcache
->tdb
);
3250 db_path
= state_path("winbindd_cache.tdb");
3251 if (db_path
== NULL
) {
3255 if (unlink(db_path
) == -1) {
3256 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3259 TALLOC_FREE(db_path
);
3262 TALLOC_FREE(db_path
);
3263 if (!init_wcache()) {
3264 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3265 "init_wcache failed.\n"));
3269 /* Write the version. */
3270 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
3271 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3272 tdb_errorstr(wcache
->tdb
) ));
3277 tdb_close(wcache
->tdb
);
3282 void close_winbindd_cache(void)
3288 tdb_close(wcache
->tdb
);
3293 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*sid
,
3294 char **domain_name
, char **name
,
3295 enum lsa_SidType
*type
)
3297 struct winbindd_domain
*domain
;
3300 domain
= find_lookup_domain_from_sid(sid
);
3301 if (domain
== NULL
) {
3304 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
3306 return NT_STATUS_IS_OK(status
);
3309 bool lookup_cached_name(const char *domain_name
,
3311 struct dom_sid
*sid
,
3312 enum lsa_SidType
*type
)
3314 struct winbindd_domain
*domain
;
3316 bool original_online_state
;
3318 domain
= find_lookup_domain_from_name(domain_name
);
3319 if (domain
== NULL
) {
3323 /* If we are doing a cached logon, temporarily set the domain
3324 offline so the cache won't expire the entry */
3326 original_online_state
= domain
->online
;
3327 domain
->online
= false;
3328 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
3329 domain
->online
= original_online_state
;
3331 return NT_STATUS_IS_OK(status
);
3334 void cache_name2sid(struct winbindd_domain
*domain
,
3335 const char *domain_name
, const char *name
,
3336 enum lsa_SidType type
, const struct dom_sid
*sid
)
3338 refresh_sequence_number(domain
, false);
3339 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
3344 * The original idea that this cache only contains centries has
3345 * been blurred - now other stuff gets put in here. Ensure we
3346 * ignore these things on cleanup.
3349 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
3350 TDB_DATA dbuf
, void *state
)
3352 struct cache_entry
*centry
;
3354 if (is_non_centry_key(kbuf
)) {
3358 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
3363 if (!NT_STATUS_IS_OK(centry
->status
)) {
3364 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
3365 tdb_delete(the_tdb
, kbuf
);
3368 centry_free(centry
);
3372 /* flush the cache */
3373 void wcache_flush_cache(void)
3380 tdb_close(wcache
->tdb
);
3383 if (!winbindd_use_cache()) {
3387 db_path
= state_path("winbindd_cache.tdb");
3388 if (db_path
== NULL
) {
3392 /* when working offline we must not clear the cache on restart */
3393 wcache
->tdb
= tdb_open_log(db_path
,
3394 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3395 TDB_INCOMPATIBLE_HASH
|
3396 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3397 O_RDWR
|O_CREAT
, 0600);
3398 TALLOC_FREE(db_path
);
3400 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3404 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
3406 DEBUG(10,("wcache_flush_cache success\n"));
3409 /* Count cached creds */
3411 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3414 int *cred_count
= (int*)state
;
3416 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3422 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
3424 struct winbind_cache
*cache
= get_cache(domain
);
3429 return NT_STATUS_INTERNAL_DB_ERROR
;
3432 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
3434 return NT_STATUS_OK
;
3438 struct cred_list
*prev
, *next
;
3443 static struct cred_list
*wcache_cred_list
;
3445 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3448 struct cred_list
*cred
;
3450 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3452 cred
= SMB_MALLOC_P(struct cred_list
);
3454 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3460 /* save a copy of the key */
3462 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
3463 DLIST_ADD(wcache_cred_list
, cred
);
3469 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
3471 struct winbind_cache
*cache
= get_cache(domain
);
3474 struct cred_list
*cred
, *oldest
= NULL
;
3477 return NT_STATUS_INTERNAL_DB_ERROR
;
3480 /* we possibly already have an entry */
3481 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
3483 fstring key_str
, tmp
;
3485 DEBUG(11,("we already have an entry, deleting that\n"));
3487 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
3489 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3491 return NT_STATUS_OK
;
3494 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
3496 return NT_STATUS_OK
;
3497 } else if ((ret
< 0) || (wcache_cred_list
== NULL
)) {
3498 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3501 ZERO_STRUCTP(oldest
);
3503 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
3508 data
= tdb_fetch(cache
->tdb
, string_tdb_data(cred
->name
));
3510 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3512 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3516 t
= IVAL(data
.dptr
, 0);
3517 SAFE_FREE(data
.dptr
);
3520 oldest
= SMB_MALLOC_P(struct cred_list
);
3521 if (oldest
== NULL
) {
3522 status
= NT_STATUS_NO_MEMORY
;
3526 fstrcpy(oldest
->name
, cred
->name
);
3527 oldest
->created
= t
;
3531 if (t
< oldest
->created
) {
3532 fstrcpy(oldest
->name
, cred
->name
);
3533 oldest
->created
= t
;
3537 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3538 status
= NT_STATUS_OK
;
3540 status
= NT_STATUS_UNSUCCESSFUL
;
3543 SAFE_FREE(wcache_cred_list
);
3549 /* Change the global online/offline state. */
3550 bool set_global_winbindd_state_offline(void)
3554 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3556 /* Only go offline if someone has created
3557 the key "WINBINDD_OFFLINE" in the cache tdb. */
3559 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3560 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3564 if (!lp_winbind_offline_logon()) {
3565 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3569 if (global_winbindd_offline_state
) {
3570 /* Already offline. */
3574 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
3576 if (!data
.dptr
|| data
.dsize
!= 4) {
3577 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3578 SAFE_FREE(data
.dptr
);
3581 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3582 global_winbindd_offline_state
= true;
3583 SAFE_FREE(data
.dptr
);
3588 void set_global_winbindd_state_online(void)
3590 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3592 if (!lp_winbind_offline_logon()) {
3593 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3597 if (!global_winbindd_offline_state
) {
3598 /* Already online. */
3601 global_winbindd_offline_state
= false;
3607 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3608 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3611 bool get_global_winbindd_state_offline(void)
3613 return global_winbindd_offline_state
;
3616 /***********************************************************************
3617 Validate functions for all possible cache tdb keys.
3618 ***********************************************************************/
3620 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3621 struct tdb_validation_status
*state
)
3623 struct cache_entry
*centry
;
3625 centry
= SMB_XMALLOC_P(struct cache_entry
);
3626 centry
->data
= (unsigned char *)smb_memdup(data
.dptr
, data
.dsize
);
3627 if (!centry
->data
) {
3631 centry
->len
= data
.dsize
;
3634 if (centry
->len
< 16) {
3635 /* huh? corrupt cache? */
3636 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3637 "(len < 16) ?\n", kstr
));
3638 centry_free(centry
);
3639 state
->bad_entry
= true;
3640 state
->success
= false;
3644 centry
->status
= NT_STATUS(centry_uint32(centry
));
3645 centry
->sequence_number
= centry_uint32(centry
);
3646 centry
->timeout
= centry_uint64_t(centry
);
3650 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3651 struct tdb_validation_status
*state
)
3653 if (dbuf
.dsize
!= 8) {
3654 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3655 keystr
, (unsigned int)dbuf
.dsize
));
3656 state
->bad_entry
= true;
3662 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3663 struct tdb_validation_status
*state
)
3665 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3670 (void)centry_uint32(centry
);
3671 if (NT_STATUS_IS_OK(centry
->status
)) {
3673 (void)centry_sid(centry
, &sid
);
3676 centry_free(centry
);
3678 if (!(state
->success
)) {
3681 DEBUG(10,("validate_ns: %s ok\n", keystr
));
3685 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3686 struct tdb_validation_status
*state
)
3688 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3693 if (NT_STATUS_IS_OK(centry
->status
)) {
3694 (void)centry_uint32(centry
);
3695 (void)centry_string(centry
, mem_ctx
);
3696 (void)centry_string(centry
, mem_ctx
);
3699 centry_free(centry
);
3701 if (!(state
->success
)) {
3704 DEBUG(10,("validate_sn: %s ok\n", keystr
));
3708 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3709 struct tdb_validation_status
*state
)
3711 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3718 (void)centry_string(centry
, mem_ctx
);
3719 (void)centry_string(centry
, mem_ctx
);
3720 (void)centry_string(centry
, mem_ctx
);
3721 (void)centry_string(centry
, mem_ctx
);
3722 (void)centry_uint32(centry
);
3723 (void)centry_sid(centry
, &sid
);
3724 (void)centry_sid(centry
, &sid
);
3726 centry_free(centry
);
3728 if (!(state
->success
)) {
3731 DEBUG(10,("validate_u: %s ok\n", keystr
));
3735 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3736 struct tdb_validation_status
*state
)
3738 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3744 (void)centry_nttime(centry
);
3745 (void)centry_nttime(centry
);
3746 (void)centry_uint16(centry
);
3748 centry_free(centry
);
3750 if (!(state
->success
)) {
3753 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3757 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3758 struct tdb_validation_status
*state
)
3760 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3766 (void)centry_uint16(centry
);
3767 (void)centry_uint16(centry
);
3768 (void)centry_uint32(centry
);
3769 (void)centry_nttime(centry
);
3770 (void)centry_nttime(centry
);
3772 centry_free(centry
);
3774 if (!(state
->success
)) {
3777 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3781 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3782 struct tdb_validation_status
*state
)
3784 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3790 (void)centry_time(centry
);
3791 (void)centry_hash16(centry
, mem_ctx
);
3793 /* We only have 17 bytes more data in the salted cred case. */
3794 if (centry
->len
- centry
->ofs
== 17) {
3795 (void)centry_hash16(centry
, mem_ctx
);
3798 centry_free(centry
);
3800 if (!(state
->success
)) {
3803 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3807 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3808 struct tdb_validation_status
*state
)
3810 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3811 int32_t num_entries
, i
;
3817 num_entries
= (int32_t)centry_uint32(centry
);
3819 for (i
=0; i
< num_entries
; i
++) {
3821 (void)centry_string(centry
, mem_ctx
);
3822 (void)centry_string(centry
, mem_ctx
);
3823 (void)centry_string(centry
, mem_ctx
);
3824 (void)centry_string(centry
, mem_ctx
);
3825 (void)centry_sid(centry
, &sid
);
3826 (void)centry_sid(centry
, &sid
);
3829 centry_free(centry
);
3831 if (!(state
->success
)) {
3834 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3838 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3839 struct tdb_validation_status
*state
)
3841 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3842 int32_t num_entries
, i
;
3848 num_entries
= centry_uint32(centry
);
3850 for (i
=0; i
< num_entries
; i
++) {
3851 (void)centry_string(centry
, mem_ctx
);
3852 (void)centry_string(centry
, mem_ctx
);
3853 (void)centry_uint32(centry
);
3856 centry_free(centry
);
3858 if (!(state
->success
)) {
3861 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3865 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3866 struct tdb_validation_status
*state
)
3868 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3869 int32_t num_groups
, i
;
3875 num_groups
= centry_uint32(centry
);
3877 for (i
=0; i
< num_groups
; i
++) {
3879 centry_sid(centry
, &sid
);
3882 centry_free(centry
);
3884 if (!(state
->success
)) {
3887 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3891 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3892 struct tdb_validation_status
*state
)
3894 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3895 int32_t num_aliases
, i
;
3901 num_aliases
= centry_uint32(centry
);
3903 for (i
=0; i
< num_aliases
; i
++) {
3904 (void)centry_uint32(centry
);
3907 centry_free(centry
);
3909 if (!(state
->success
)) {
3912 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3916 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3917 struct tdb_validation_status
*state
)
3919 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3920 int32_t num_names
, i
;
3926 num_names
= centry_uint32(centry
);
3928 for (i
=0; i
< num_names
; i
++) {
3930 centry_sid(centry
, &sid
);
3931 (void)centry_string(centry
, mem_ctx
);
3932 (void)centry_uint32(centry
);
3935 centry_free(centry
);
3937 if (!(state
->success
)) {
3940 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3944 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3945 struct tdb_validation_status
*state
)
3947 /* Can't say anything about this other than must be nonzero. */
3948 if (dbuf
.dsize
== 0) {
3949 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3951 state
->bad_entry
= true;
3952 state
->success
= false;
3956 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3960 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3961 struct tdb_validation_status
*state
)
3963 /* Can't say anything about this other than must be nonzero. */
3964 if (dbuf
.dsize
== 0) {
3965 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3967 state
->bad_entry
= true;
3968 state
->success
= false;
3972 DEBUG(10,("validate_de: %s ok\n", keystr
));
3976 static int validate_pwinfo(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3977 TDB_DATA dbuf
, struct tdb_validation_status
*state
)
3979 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3985 (void)centry_string(centry
, mem_ctx
);
3986 (void)centry_string(centry
, mem_ctx
);
3987 (void)centry_string(centry
, mem_ctx
);
3988 (void)centry_uint32(centry
);
3990 centry_free(centry
);
3992 if (!(state
->success
)) {
3995 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3999 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
4001 struct tdb_validation_status
*state
)
4003 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
4009 (void)centry_string( centry
, mem_ctx
);
4011 centry_free(centry
);
4013 if (!(state
->success
)) {
4016 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
4020 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
4022 struct tdb_validation_status
*state
)
4024 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
4030 (void)centry_string( centry
, mem_ctx
);
4032 centry_free(centry
);
4034 if (!(state
->success
)) {
4037 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
4041 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
4043 struct tdb_validation_status
*state
)
4045 if (dbuf
.dsize
== 0) {
4046 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
4047 "key %s (len ==0) ?\n", keystr
));
4048 state
->bad_entry
= true;
4049 state
->success
= false;
4053 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
4054 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
4058 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
4059 struct tdb_validation_status
*state
)
4061 if (dbuf
.dsize
!= 4) {
4062 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
4063 keystr
, (unsigned int)dbuf
.dsize
));
4064 state
->bad_entry
= true;
4065 state
->success
= false;
4068 DEBUG(10,("validate_offline: %s ok\n", keystr
));
4072 static int validate_ndr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
4073 struct tdb_validation_status
*state
)
4076 * Ignore validation for now. The proper way to do this is with a
4077 * checksum. Just pure parsing does not really catch much.
4082 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
4083 struct tdb_validation_status
*state
)
4085 if (dbuf
.dsize
!= 4) {
4086 DEBUG(0, ("validate_cache_version: Corrupt cache for "
4087 "key %s (len %u != 4) ?\n",
4088 keystr
, (unsigned int)dbuf
.dsize
));
4089 state
->bad_entry
= true;
4090 state
->success
= false;
4094 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
4098 /***********************************************************************
4099 A list of all possible cache tdb keys with associated validation
4101 ***********************************************************************/
4103 struct key_val_struct
{
4104 const char *keyname
;
4105 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
4107 {"SEQNUM/", validate_seqnum
},
4108 {"NS/", validate_ns
},
4109 {"SN/", validate_sn
},
4111 {"LOC_POL/", validate_loc_pol
},
4112 {"PWD_POL/", validate_pwd_pol
},
4113 {"CRED/", validate_cred
},
4114 {"UL/", validate_ul
},
4115 {"GL/", validate_gl
},
4116 {"UG/", validate_ug
},
4117 {"UA", validate_ua
},
4118 {"GM/", validate_gm
},
4119 {"DR/", validate_dr
},
4120 {"DE/", validate_de
},
4121 {"NSS/PWINFO/", validate_pwinfo
},
4122 {"TRUSTDOMCACHE/", validate_trustdomcache
},
4123 {"NSS/NA/", validate_nss_na
},
4124 {"NSS/AN/", validate_nss_an
},
4125 {"WINBINDD_OFFLINE", validate_offline
},
4126 {"NDR/", validate_ndr
},
4127 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
4131 /***********************************************************************
4132 Function to look at every entry in the tdb and validate it as far as
4134 ***********************************************************************/
4136 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
4139 unsigned int max_key_len
= 1024;
4140 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
4142 /* Paranoia check. */
4143 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0 ||
4144 strncmp("NDR/", (const char *)kbuf
.dptr
, 4) == 0) {
4145 max_key_len
= 1024 * 1024;
4147 if (kbuf
.dsize
> max_key_len
) {
4148 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4150 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
4154 for (i
= 0; key_val
[i
].keyname
; i
++) {
4155 size_t namelen
= strlen(key_val
[i
].keyname
);
4156 if (kbuf
.dsize
>= namelen
&& (
4157 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
4158 TALLOC_CTX
*mem_ctx
;
4162 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
4166 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
4167 keystr
[kbuf
.dsize
] = '\0';
4169 mem_ctx
= talloc_init("validate_ctx");
4175 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
4179 talloc_destroy(mem_ctx
);
4184 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4185 dump_data(0, (uint8_t *)kbuf
.dptr
, kbuf
.dsize
);
4186 DEBUG(0,("data :\n"));
4187 dump_data(0, (uint8_t *)dbuf
.dptr
, dbuf
.dsize
);
4188 v_state
->unknown_key
= true;
4189 v_state
->success
= false;
4190 return 1; /* terminate. */
4193 static void validate_panic(const char *const why
)
4195 DEBUG(0,("validating cache: would panic %s\n", why
));
4196 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4200 static int wbcache_update_centry_fn(TDB_CONTEXT
*tdb
,
4208 if (is_non_centry_key(key
)) {
4212 if (data
.dptr
== NULL
|| data
.dsize
== 0) {
4213 if (tdb_delete(tdb
, key
) < 0) {
4214 DEBUG(0, ("tdb_delete for [%s] failed!\n",
4220 /* add timeout to blob (uint64_t) */
4221 blob
.dsize
= data
.dsize
+ 8;
4223 blob
.dptr
= SMB_XMALLOC_ARRAY(uint8_t, blob
.dsize
);
4224 if (blob
.dptr
== NULL
) {
4227 memset(blob
.dptr
, 0, blob
.dsize
);
4229 /* copy status and seqnum */
4230 memcpy(blob
.dptr
, data
.dptr
, 8);
4233 ctimeout
= lp_winbind_cache_time() + time(NULL
);
4234 SBVAL(blob
.dptr
, 8, ctimeout
);
4237 memcpy(blob
.dptr
+ 16, data
.dptr
+ 8, data
.dsize
- 8);
4239 if (tdb_store(tdb
, key
, blob
, TDB_REPLACE
) < 0) {
4240 DEBUG(0, ("tdb_store to update [%s] failed!\n",
4242 SAFE_FREE(blob
.dptr
);
4246 SAFE_FREE(blob
.dptr
);
4250 static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT
*tdb
)
4254 DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
4256 rc
= tdb_traverse(tdb
, wbcache_update_centry_fn
, NULL
);
4264 /***********************************************************************
4265 Try and validate every entry in the winbindd cache. If we fail here,
4266 delete the cache tdb and return non-zero.
4267 ***********************************************************************/
4269 int winbindd_validate_cache(void)
4272 char *tdb_path
= NULL
;
4273 TDB_CONTEXT
*tdb
= NULL
;
4277 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4278 smb_panic_fn
= validate_panic
;
4280 tdb_path
= state_path("winbindd_cache.tdb");
4281 if (tdb_path
== NULL
) {
4285 tdb
= tdb_open_log(tdb_path
,
4286 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
4287 TDB_INCOMPATIBLE_HASH
|
4288 ( lp_winbind_offline_logon()
4290 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
4294 DEBUG(0, ("winbindd_validate_cache: "
4295 "error opening/initializing tdb\n"));
4299 /* Version check and upgrade code. */
4300 if (!tdb_fetch_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers_id
)) {
4301 DEBUG(10, ("Fresh database\n"));
4302 tdb_store_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
);
4303 vers_id
= WINBINDD_CACHE_VERSION
;
4306 if (vers_id
!= WINBINDD_CACHE_VERSION
) {
4307 if (vers_id
== WINBINDD_CACHE_VER1
) {
4308 ok
= wbcache_upgrade_v1_to_v2(tdb
);
4310 DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
4315 tdb_store_uint32(tdb
,
4316 WINBINDD_CACHE_VERSION_KEYSTR
,
4317 WINBINDD_CACHE_VERSION
);
4318 vers_id
= WINBINDD_CACHE_VER2
;
4324 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
4327 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4328 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
4333 TALLOC_FREE(tdb_path
);
4334 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4335 smb_panic_fn
= smb_panic
;
4339 /***********************************************************************
4340 Try and validate every entry in the winbindd cache.
4341 ***********************************************************************/
4343 int winbindd_validate_cache_nobackup(void)
4348 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4349 smb_panic_fn
= validate_panic
;
4351 tdb_path
= state_path("winbindd_cache.tdb");
4352 if (tdb_path
== NULL
) {
4353 goto err_panic_restore
;
4356 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
4357 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
4359 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
4363 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4367 TALLOC_FREE(tdb_path
);
4369 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4371 smb_panic_fn
= smb_panic
;
4375 bool winbindd_cache_validate_and_initialize(void)
4377 close_winbindd_cache();
4379 if (lp_winbind_offline_logon()) {
4380 if (winbindd_validate_cache() < 0) {
4381 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4382 "could be restored.\n"));
4386 return initialize_winbindd_cache();
4389 /*********************************************************************
4390 ********************************************************************/
4392 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
4393 struct winbindd_tdc_domain
**domains
,
4394 size_t *num_domains
)
4396 struct winbindd_tdc_domain
*list
= NULL
;
4399 bool set_only
= false;
4401 /* don't allow duplicates */
4406 for ( i
=0; i
< (*num_domains
); i
++ ) {
4407 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
4408 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4419 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, 1 );
4422 list
= talloc_realloc( *domains
, *domains
,
4423 struct winbindd_tdc_domain
,
4428 ZERO_STRUCT( list
[idx
] );
4434 list
[idx
].domain_name
= talloc_strdup(list
, new_dom
->name
);
4435 if (list
[idx
].domain_name
== NULL
) {
4438 if (new_dom
->alt_name
!= NULL
) {
4439 list
[idx
].dns_name
= talloc_strdup(list
, new_dom
->alt_name
);
4440 if (list
[idx
].dns_name
== NULL
) {
4445 if ( !is_null_sid( &new_dom
->sid
) ) {
4446 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
4448 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
4451 if ( new_dom
->domain_flags
!= 0x0 )
4452 list
[idx
].trust_flags
= new_dom
->domain_flags
;
4454 if ( new_dom
->domain_type
!= 0x0 )
4455 list
[idx
].trust_type
= new_dom
->domain_type
;
4457 if ( new_dom
->domain_trust_attribs
!= 0x0 )
4458 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
4462 *num_domains
= idx
+ 1;
4468 /*********************************************************************
4469 ********************************************************************/
4471 static TDB_DATA
make_tdc_key( const char *domain_name
)
4473 char *keystr
= NULL
;
4474 TDB_DATA key
= { NULL
, 0 };
4476 if ( !domain_name
) {
4477 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4481 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
4484 key
= string_term_tdb_data(keystr
);
4489 /*********************************************************************
4490 ********************************************************************/
4492 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
4494 unsigned char **buf
)
4496 unsigned char *buffer
= NULL
;
4501 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4509 /* Store the number of array items first */
4510 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
4513 /* now pack each domain trust record */
4514 for ( i
=0; i
<num_domains
; i
++ ) {
4519 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4520 domains
[i
].domain_name
,
4521 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
4524 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
4525 domains
[i
].domain_name
,
4526 domains
[i
].dns_name
? domains
[i
].dns_name
: "",
4527 sid_to_fstring(tmp
, &domains
[i
].sid
),
4528 domains
[i
].trust_flags
,
4529 domains
[i
].trust_attribs
,
4530 domains
[i
].trust_type
);
4533 if ( buflen
< len
) {
4535 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
4536 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4550 /*********************************************************************
4551 ********************************************************************/
4553 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
4554 struct winbindd_tdc_domain
**domains
)
4556 fstring domain_name
, dns_name
, sid_string
;
4557 uint32_t type
, attribs
, flags
;
4561 struct winbindd_tdc_domain
*list
= NULL
;
4563 /* get the number of domains */
4564 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
4566 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4570 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, num_domains
);
4572 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4576 for ( i
=0; i
<num_domains
; i
++ ) {
4579 this_len
= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
4587 if ( this_len
== -1 ) {
4588 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4589 TALLOC_FREE( list
);
4594 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4595 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4596 domain_name
, dns_name
, sid_string
,
4597 flags
, attribs
, type
));
4599 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
4600 list
[i
].dns_name
= NULL
;
4601 if (dns_name
[0] != '\0') {
4602 list
[i
].dns_name
= talloc_strdup(list
, dns_name
);
4604 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
4605 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4608 list
[i
].trust_flags
= flags
;
4609 list
[i
].trust_attribs
= attribs
;
4610 list
[i
].trust_type
= type
;
4618 /*********************************************************************
4619 ********************************************************************/
4621 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
4623 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4624 TDB_DATA data
= { NULL
, 0 };
4630 /* See if we were asked to delete the cache entry */
4633 ret
= tdb_delete( wcache
->tdb
, key
);
4637 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4644 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4647 SAFE_FREE( data
.dptr
);
4648 SAFE_FREE( key
.dptr
);
4650 return ( ret
== 0 );
4653 /*********************************************************************
4654 ********************************************************************/
4656 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4658 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4659 TDB_DATA data
= { NULL
, 0 };
4667 data
= tdb_fetch( wcache
->tdb
, key
);
4669 SAFE_FREE( key
.dptr
);
4674 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4676 SAFE_FREE( data
.dptr
);
4684 /*********************************************************************
4685 ********************************************************************/
4687 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4689 struct winbindd_tdc_domain
*dom_list
= NULL
;
4690 size_t num_domains
= 0;
4693 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4694 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4695 domain
->name
, domain
->alt_name
,
4696 sid_string_dbg(&domain
->sid
),
4697 domain
->domain_flags
,
4698 domain
->domain_trust_attribs
,
4699 domain
->domain_type
));
4701 if ( !init_wcache() ) {
4705 /* fetch the list */
4707 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4709 /* add the new domain */
4711 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4715 /* pack the domain */
4717 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4725 TALLOC_FREE( dom_list
);
4730 static struct winbindd_tdc_domain
*wcache_tdc_dup_domain(
4731 TALLOC_CTX
*mem_ctx
, const struct winbindd_tdc_domain
*src
)
4733 struct winbindd_tdc_domain
*dst
;
4735 dst
= talloc(mem_ctx
, struct winbindd_tdc_domain
);
4739 dst
->domain_name
= talloc_strdup(dst
, src
->domain_name
);
4740 if (dst
->domain_name
== NULL
) {
4744 dst
->dns_name
= NULL
;
4745 if (src
->dns_name
!= NULL
) {
4746 dst
->dns_name
= talloc_strdup(dst
, src
->dns_name
);
4747 if (dst
->dns_name
== NULL
) {
4752 sid_copy(&dst
->sid
, &src
->sid
);
4753 dst
->trust_flags
= src
->trust_flags
;
4754 dst
->trust_type
= src
->trust_type
;
4755 dst
->trust_attribs
= src
->trust_attribs
;
4762 /*********************************************************************
4763 ********************************************************************/
4765 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4767 struct winbindd_tdc_domain
*dom_list
= NULL
;
4768 size_t num_domains
= 0;
4770 struct winbindd_tdc_domain
*d
= NULL
;
4772 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4774 if ( !init_wcache() ) {
4778 /* fetch the list */
4780 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4782 for ( i
=0; i
<num_domains
; i
++ ) {
4783 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4784 strequal(name
, dom_list
[i
].dns_name
) )
4786 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4789 d
= wcache_tdc_dup_domain(ctx
, &dom_list
[i
]);
4794 TALLOC_FREE( dom_list
);
4799 /*********************************************************************
4800 ********************************************************************/
4802 struct winbindd_tdc_domain
*
4803 wcache_tdc_fetch_domainbysid(TALLOC_CTX
*ctx
,
4804 const struct dom_sid
*sid
)
4806 struct winbindd_tdc_domain
*dom_list
= NULL
;
4807 size_t num_domains
= 0;
4809 struct winbindd_tdc_domain
*d
= NULL
;
4811 DEBUG(10,("wcache_tdc_fetch_domainbysid: Searching for domain %s\n",
4812 sid_string_dbg(sid
)));
4814 if (!init_wcache()) {
4818 /* fetch the list */
4820 wcache_tdc_fetch_list(&dom_list
, &num_domains
);
4822 for (i
= 0; i
<num_domains
; i
++) {
4823 if (dom_sid_equal(sid
, &(dom_list
[i
].sid
))) {
4824 DEBUG(10, ("wcache_tdc_fetch_domainbysid: "
4825 "Found domain %s for SID %s\n",
4826 dom_list
[i
].domain_name
,
4827 sid_string_dbg(sid
)));
4829 d
= wcache_tdc_dup_domain(ctx
, &dom_list
[i
]);
4834 TALLOC_FREE(dom_list
);
4840 /*********************************************************************
4841 ********************************************************************/
4843 void wcache_tdc_clear( void )
4845 if ( !init_wcache() )
4848 wcache_tdc_store_list( NULL
, 0 );
4854 /*********************************************************************
4855 ********************************************************************/
4857 static void wcache_save_user_pwinfo(struct winbindd_domain
*domain
,
4859 const struct dom_sid
*user_sid
,
4860 const char *homedir
,
4865 struct cache_entry
*centry
;
4868 if ( (centry
= centry_start(domain
, status
)) == NULL
)
4871 centry_put_string( centry
, homedir
);
4872 centry_put_string( centry
, shell
);
4873 centry_put_string( centry
, gecos
);
4874 centry_put_uint32( centry
, gid
);
4876 centry_end(centry
, "NSS/PWINFO/%s", sid_to_fstring(tmp
, user_sid
) );
4878 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid
) ));
4880 centry_free(centry
);
4885 NTSTATUS
nss_get_info_cached( struct winbindd_domain
*domain
,
4886 const struct dom_sid
*user_sid
,
4888 const char **homedir
, const char **shell
,
4889 const char **gecos
, gid_t
*p_gid
)
4891 struct winbind_cache
*cache
= get_cache(domain
);
4892 struct cache_entry
*centry
= NULL
;
4899 centry
= wcache_fetch(cache
, domain
, "NSS/PWINFO/%s",
4900 sid_to_fstring(tmp
, user_sid
));
4905 *homedir
= centry_string( centry
, ctx
);
4906 *shell
= centry_string( centry
, ctx
);
4907 *gecos
= centry_string( centry
, ctx
);
4908 *p_gid
= centry_uint32( centry
);
4910 centry_free(centry
);
4912 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4913 sid_string_dbg(user_sid
)));
4915 return NT_STATUS_OK
;
4919 nt_status
= nss_get_info( domain
->name
, user_sid
, ctx
,
4920 homedir
, shell
, gecos
, p_gid
);
4922 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status
)));
4924 if ( NT_STATUS_IS_OK(nt_status
) ) {
4925 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir
));
4926 DEBUGADD(10, ("\tshell = '%s'\n", *shell
));
4927 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos
));
4928 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid
));
4930 wcache_save_user_pwinfo( domain
, nt_status
, user_sid
,
4931 *homedir
, *shell
, *gecos
, *p_gid
);
4934 if ( NT_STATUS_EQUAL( nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
4935 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4937 set_domain_offline( domain
);
4945 /* the cache backend methods are exposed via this structure */
4946 struct winbindd_methods cache_methods
= {
4964 static bool wcache_ndr_key(TALLOC_CTX
*mem_ctx
, const char *domain_name
,
4965 uint32_t opnum
, const DATA_BLOB
*req
,
4971 key
= talloc_asprintf(mem_ctx
, "NDR/%s/%d/", domain_name
, (int)opnum
);
4975 keylen
= talloc_get_size(key
) - 1;
4977 key
= talloc_realloc(mem_ctx
, key
, char, keylen
+ req
->length
);
4981 memcpy(key
+ keylen
, req
->data
, req
->length
);
4983 pkey
->dptr
= (uint8_t *)key
;
4984 pkey
->dsize
= talloc_get_size(key
);
4988 static bool wcache_opnum_cacheable(uint32_t opnum
)
4991 case NDR_WBINT_PING
:
4992 case NDR_WBINT_QUERYSEQUENCENUMBER
:
4993 case NDR_WBINT_ALLOCATEUID
:
4994 case NDR_WBINT_ALLOCATEGID
:
4995 case NDR_WBINT_CHECKMACHINEACCOUNT
:
4996 case NDR_WBINT_CHANGEMACHINEACCOUNT
:
4997 case NDR_WBINT_PINGDC
:
5003 bool wcache_fetch_ndr(TALLOC_CTX
*mem_ctx
, struct winbindd_domain
*domain
,
5004 uint32_t opnum
, const DATA_BLOB
*req
, DATA_BLOB
*resp
)
5009 if (!wcache_opnum_cacheable(opnum
) ||
5010 is_my_own_sam_domain(domain
) ||
5011 is_builtin_domain(domain
)) {
5015 if (wcache
->tdb
== NULL
) {
5019 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
5022 data
= tdb_fetch(wcache
->tdb
, key
);
5023 TALLOC_FREE(key
.dptr
);
5025 if (data
.dptr
== NULL
) {
5028 if (data
.dsize
< 12) {
5032 if (!is_domain_offline(domain
)) {
5033 uint32_t entry_seqnum
, dom_seqnum
, last_check
;
5034 uint64_t entry_timeout
;
5036 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
,
5040 entry_seqnum
= IVAL(data
.dptr
, 0);
5041 if (entry_seqnum
!= dom_seqnum
) {
5042 DEBUG(10, ("Entry has wrong sequence number: %d\n",
5043 (int)entry_seqnum
));
5046 entry_timeout
= BVAL(data
.dptr
, 4);
5047 if (time(NULL
) > entry_timeout
) {
5048 DEBUG(10, ("Entry has timed out\n"));
5053 resp
->data
= (uint8_t *)talloc_memdup(mem_ctx
, data
.dptr
+ 12,
5055 if (resp
->data
== NULL
) {
5056 DEBUG(10, ("talloc failed\n"));
5059 resp
->length
= data
.dsize
- 12;
5063 SAFE_FREE(data
.dptr
);
5067 void wcache_store_ndr(struct winbindd_domain
*domain
, uint32_t opnum
,
5068 const DATA_BLOB
*req
, const DATA_BLOB
*resp
)
5071 uint32_t dom_seqnum
, last_check
;
5074 if (!wcache_opnum_cacheable(opnum
) ||
5075 is_my_own_sam_domain(domain
) ||
5076 is_builtin_domain(domain
)) {
5080 if (wcache
->tdb
== NULL
) {
5084 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
, &last_check
)) {
5085 DEBUG(10, ("could not fetch seqnum for domain %s\n",
5090 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
5094 timeout
= time(NULL
) + lp_winbind_cache_time();
5096 data
.dsize
= resp
->length
+ 12;
5097 data
.dptr
= talloc_array(key
.dptr
, uint8_t, data
.dsize
);
5098 if (data
.dptr
== NULL
) {
5102 SIVAL(data
.dptr
, 0, dom_seqnum
);
5103 SBVAL(data
.dptr
, 4, timeout
);
5104 memcpy(data
.dptr
+ 12, resp
->data
, resp
->length
);
5106 tdb_store(wcache
->tdb
, key
, data
, 0);
5109 TALLOC_FREE(key
.dptr
);