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_wbint.h"
34 #include "../libcli/security/security.h"
35 #include "passdb/machine_sid.h"
38 #define DBGC_CLASS DBGC_WINBIND
40 #define WINBINDD_CACHE_VERSION 2
41 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
43 extern struct winbindd_methods reconnect_methods
;
45 extern struct winbindd_methods ads_methods
;
47 extern struct winbindd_methods builtin_passdb_methods
;
48 extern struct winbindd_methods sam_passdb_methods
;
51 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
52 * Here are the list of entry types that are *not* stored
53 * as form struct cache_entry in the cache.
56 static const char *non_centry_keys
[] = {
61 WINBINDD_CACHE_VERSION_KEYSTR
,
65 /************************************************************************
66 Is this key a non-centry type ?
67 ************************************************************************/
69 static bool is_non_centry_key(TDB_DATA kbuf
)
73 if (kbuf
.dptr
== NULL
|| kbuf
.dsize
== 0) {
76 for (i
= 0; non_centry_keys
[i
] != NULL
; i
++) {
77 size_t namelen
= strlen(non_centry_keys
[i
]);
78 if (kbuf
.dsize
< namelen
) {
81 if (strncmp(non_centry_keys
[i
], (const char *)kbuf
.dptr
, namelen
) == 0) {
88 /* Global online/offline state - False when online. winbindd starts up online
89 and sets this to true if the first query fails and there's an entry in
90 the cache tdb telling us to stay offline. */
92 static bool global_winbindd_offline_state
;
94 struct winbind_cache
{
100 uint32 sequence_number
;
106 void (*smb_panic_fn
)(const char *const why
) = smb_panic
;
108 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
110 static struct winbind_cache
*wcache
;
112 /* get the winbind_cache structure */
113 static struct winbind_cache
*get_cache(struct winbindd_domain
*domain
)
115 struct winbind_cache
*ret
= wcache
;
117 /* We have to know what type of domain we are dealing with first. */
119 if (domain
->internal
) {
120 domain
->backend
= &builtin_passdb_methods
;
121 domain
->initialized
= True
;
124 if (strequal(domain
->name
, get_global_sam_name()) &&
125 sid_check_is_domain(&domain
->sid
)) {
126 domain
->backend
= &sam_passdb_methods
;
127 domain
->initialized
= True
;
130 if ( !domain
->initialized
) {
131 init_dc_connection( domain
);
135 OK. listen up becasue I'm only going to say this once.
136 We have the following scenarios to consider
137 (a) trusted AD domains on a Samba DC,
138 (b) trusted AD domains and we are joined to a non-kerberos domain
139 (c) trusted AD domains and we are joined to a kerberos (AD) domain
141 For (a) we can always contact the trusted domain using krb5
142 since we have the domain trust account password
144 For (b) we can only use RPC since we have no way of
145 getting a krb5 ticket in our own domain
147 For (c) we can always use krb5 since we have a kerberos trust
152 if (!domain
->backend
) {
154 struct winbindd_domain
*our_domain
= domain
;
156 /* find our domain first so we can figure out if we
157 are joined to a kerberized domain */
159 if ( !domain
->primary
)
160 our_domain
= find_our_domain();
162 if ((our_domain
->active_directory
|| IS_DC
)
163 && domain
->active_directory
164 && !lp_winbind_rpc_only()) {
165 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain
->name
));
166 domain
->backend
= &ads_methods
;
168 #endif /* HAVE_ADS */
169 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain
->name
));
170 domain
->backend
= &reconnect_methods
;
173 #endif /* HAVE_ADS */
179 ret
= SMB_XMALLOC_P(struct winbind_cache
);
183 wcache_flush_cache();
189 free a centry structure
191 static void centry_free(struct cache_entry
*centry
)
195 SAFE_FREE(centry
->data
);
199 static bool centry_check_bytes(struct cache_entry
*centry
, size_t nbytes
)
201 if (centry
->len
- centry
->ofs
< nbytes
) {
202 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
203 (unsigned int)nbytes
,
204 centry
->len
- centry
->ofs
));
211 pull a uint64_t from a cache entry
213 static uint64_t centry_uint64_t(struct cache_entry
*centry
)
217 if (!centry_check_bytes(centry
, 8)) {
218 smb_panic_fn("centry_uint64_t");
220 ret
= BVAL(centry
->data
, centry
->ofs
);
226 pull a uint32 from a cache entry
228 static uint32
centry_uint32(struct cache_entry
*centry
)
232 if (!centry_check_bytes(centry
, 4)) {
233 smb_panic_fn("centry_uint32");
235 ret
= IVAL(centry
->data
, centry
->ofs
);
241 pull a uint16 from a cache entry
243 static uint16
centry_uint16(struct cache_entry
*centry
)
246 if (!centry_check_bytes(centry
, 2)) {
247 smb_panic_fn("centry_uint16");
249 ret
= SVAL(centry
->data
, centry
->ofs
);
255 pull a uint8 from a cache entry
257 static uint8
centry_uint8(struct cache_entry
*centry
)
260 if (!centry_check_bytes(centry
, 1)) {
261 smb_panic_fn("centry_uint8");
263 ret
= CVAL(centry
->data
, centry
->ofs
);
269 pull a NTTIME from a cache entry
271 static NTTIME
centry_nttime(struct cache_entry
*centry
)
274 if (!centry_check_bytes(centry
, 8)) {
275 smb_panic_fn("centry_nttime");
277 ret
= IVAL(centry
->data
, centry
->ofs
);
279 ret
+= (uint64
)IVAL(centry
->data
, centry
->ofs
) << 32;
285 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
287 static time_t centry_time(struct cache_entry
*centry
)
289 return (time_t)centry_nttime(centry
);
292 /* pull a string from a cache entry, using the supplied
295 static char *centry_string(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
300 len
= centry_uint8(centry
);
303 /* a deliberate NULL string */
307 if (!centry_check_bytes(centry
, (size_t)len
)) {
308 smb_panic_fn("centry_string");
311 ret
= TALLOC_ARRAY(mem_ctx
, char, len
+1);
313 smb_panic_fn("centry_string out of memory\n");
315 memcpy(ret
,centry
->data
+ centry
->ofs
, len
);
321 /* pull a hash16 from a cache entry, using the supplied
324 static char *centry_hash16(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
329 len
= centry_uint8(centry
);
332 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
337 if (!centry_check_bytes(centry
, 16)) {
341 ret
= TALLOC_ARRAY(mem_ctx
, char, 16);
343 smb_panic_fn("centry_hash out of memory\n");
345 memcpy(ret
,centry
->data
+ centry
->ofs
, 16);
350 /* pull a sid from a cache entry, using the supplied
353 static bool centry_sid(struct cache_entry
*centry
, struct dom_sid
*sid
)
358 sid_string
= centry_string(centry
, talloc_tos());
359 if (sid_string
== NULL
) {
362 ret
= string_to_sid(sid
, sid_string
);
363 TALLOC_FREE(sid_string
);
369 pull a NTSTATUS from a cache entry
371 static NTSTATUS
centry_ntstatus(struct cache_entry
*centry
)
375 status
= NT_STATUS(centry_uint32(centry
));
380 /* the server is considered down if it can't give us a sequence number */
381 static bool wcache_server_down(struct winbindd_domain
*domain
)
388 ret
= (domain
->sequence_number
== DOM_SEQUENCE_NONE
);
391 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
396 static bool wcache_fetch_seqnum(const char *domain_name
, uint32_t *seqnum
,
397 uint32_t *last_seq_check
)
402 if (wcache
->tdb
== NULL
) {
403 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
407 key
= talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name
);
409 DEBUG(10, ("talloc failed\n"));
413 data
= tdb_fetch_bystring(wcache
->tdb
, key
);
416 if (data
.dptr
== NULL
) {
417 DEBUG(10, ("wcache_fetch_seqnum: %s not found\n",
421 if (data
.dsize
!= 8) {
422 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
424 SAFE_FREE(data
.dptr
);
428 *seqnum
= IVAL(data
.dptr
, 0);
429 *last_seq_check
= IVAL(data
.dptr
, 4);
430 SAFE_FREE(data
.dptr
);
435 static NTSTATUS
fetch_cache_seqnum( struct winbindd_domain
*domain
, time_t now
)
437 uint32 last_check
, time_diff
;
439 if (!wcache_fetch_seqnum(domain
->name
, &domain
->sequence_number
,
441 return NT_STATUS_UNSUCCESSFUL
;
443 domain
->last_seq_check
= last_check
;
445 /* have we expired? */
447 time_diff
= now
- domain
->last_seq_check
;
448 if ( time_diff
> lp_winbind_cache_time() ) {
449 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
450 domain
->name
, domain
->sequence_number
,
451 (uint32
)domain
->last_seq_check
));
452 return NT_STATUS_UNSUCCESSFUL
;
455 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
456 domain
->name
, domain
->sequence_number
,
457 (uint32
)domain
->last_seq_check
));
462 bool wcache_store_seqnum(const char *domain_name
, uint32_t seqnum
,
463 time_t last_seq_check
)
469 if (wcache
->tdb
== NULL
) {
470 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
474 key_str
= talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name
);
475 if (key_str
== NULL
) {
476 DEBUG(10, ("talloc_asprintf failed\n"));
480 SIVAL(buf
, 0, seqnum
);
481 SIVAL(buf
, 4, last_seq_check
);
483 ret
= tdb_store_bystring(wcache
->tdb
, key_str
,
484 make_tdb_data(buf
, sizeof(buf
)), TDB_REPLACE
);
485 TALLOC_FREE(key_str
);
487 DEBUG(10, ("tdb_store_bystring failed: %s\n",
488 tdb_errorstr(wcache
->tdb
)));
489 TALLOC_FREE(key_str
);
493 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
494 domain_name
, seqnum
, (unsigned)last_seq_check
));
499 static bool store_cache_seqnum( struct winbindd_domain
*domain
)
501 return wcache_store_seqnum(domain
->name
, domain
->sequence_number
,
502 domain
->last_seq_check
);
506 refresh the domain sequence number. If force is true
507 then always refresh it, no matter how recently we fetched it
510 static void refresh_sequence_number(struct winbindd_domain
*domain
, bool force
)
514 time_t t
= time(NULL
);
515 unsigned cache_time
= lp_winbind_cache_time();
517 if (is_domain_offline(domain
)) {
523 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
524 /* trying to reconnect is expensive, don't do it too often */
525 if (domain
->sequence_number
== DOM_SEQUENCE_NONE
) {
530 time_diff
= t
- domain
->last_seq_check
;
532 /* see if we have to refetch the domain sequence number */
533 if (!force
&& (time_diff
< cache_time
) &&
534 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
535 NT_STATUS_IS_OK(domain
->last_status
)) {
536 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain
->name
));
540 /* try to get the sequence number from the tdb cache first */
541 /* this will update the timestamp as well */
543 status
= fetch_cache_seqnum( domain
, t
);
544 if (NT_STATUS_IS_OK(status
) &&
545 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
546 NT_STATUS_IS_OK(domain
->last_status
)) {
550 /* important! make sure that we know if this is a native
551 mode domain or not. And that we can contact it. */
553 if ( winbindd_can_contact_domain( domain
) ) {
554 status
= domain
->backend
->sequence_number(domain
,
555 &domain
->sequence_number
);
557 /* just use the current time */
558 status
= NT_STATUS_OK
;
559 domain
->sequence_number
= time(NULL
);
563 /* the above call could have set our domain->backend to NULL when
564 * coming from offline to online mode, make sure to reinitialize the
565 * backend - Guenther */
568 if (!NT_STATUS_IS_OK(status
)) {
569 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status
)));
570 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
573 domain
->last_status
= status
;
574 domain
->last_seq_check
= time(NULL
);
576 /* save the new sequence number in the cache */
577 store_cache_seqnum( domain
);
580 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
581 domain
->name
, domain
->sequence_number
));
587 decide if a cache entry has expired
589 static bool centry_expired(struct winbindd_domain
*domain
, const char *keystr
, struct cache_entry
*centry
)
591 /* If we've been told to be offline - stay in that state... */
592 if (lp_winbind_offline_logon() && global_winbindd_offline_state
) {
593 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
594 keystr
, domain
->name
));
598 /* when the domain is offline return the cached entry.
599 * This deals with transient offline states... */
601 if (!domain
->online
) {
602 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
603 keystr
, domain
->name
));
607 /* if the server is OK and our cache entry came from when it was down then
608 the entry is invalid */
609 if ((domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
610 (centry
->sequence_number
== DOM_SEQUENCE_NONE
)) {
611 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
612 keystr
, domain
->name
));
616 /* if the server is down or the cache entry is not older than the
617 current sequence number or it did not timeout then it is OK */
618 if (wcache_server_down(domain
)
619 || ((centry
->sequence_number
== domain
->sequence_number
)
620 && (centry
->timeout
> time(NULL
)))) {
621 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
622 keystr
, domain
->name
));
626 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
627 keystr
, domain
->name
));
633 static struct cache_entry
*wcache_fetch_raw(char *kstr
)
636 struct cache_entry
*centry
;
639 key
= string_tdb_data(kstr
);
640 data
= tdb_fetch(wcache
->tdb
, key
);
646 centry
= SMB_XMALLOC_P(struct cache_entry
);
647 centry
->data
= (unsigned char *)data
.dptr
;
648 centry
->len
= data
.dsize
;
651 if (centry
->len
< 16) {
652 /* huh? corrupt cache? */
653 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s "
654 "(len < 16)?\n", kstr
));
659 centry
->status
= centry_ntstatus(centry
);
660 centry
->sequence_number
= centry_uint32(centry
);
661 centry
->timeout
= centry_uint64_t(centry
);
666 static bool is_my_own_sam_domain(struct winbindd_domain
*domain
)
668 if (strequal(domain
->name
, get_global_sam_name()) &&
669 sid_check_is_domain(&domain
->sid
)) {
676 static bool is_builtin_domain(struct winbindd_domain
*domain
)
678 if (strequal(domain
->name
, "BUILTIN") &&
679 sid_check_is_builtin(&domain
->sid
)) {
687 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
688 number and return status
690 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
691 struct winbindd_domain
*domain
,
692 const char *format
, ...) PRINTF_ATTRIBUTE(3,4);
693 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
694 struct winbindd_domain
*domain
,
695 const char *format
, ...)
699 struct cache_entry
*centry
;
701 if (!winbindd_use_cache() ||
702 is_my_own_sam_domain(domain
) ||
703 is_builtin_domain(domain
)) {
707 refresh_sequence_number(domain
, false);
709 va_start(ap
, format
);
710 smb_xvasprintf(&kstr
, format
, ap
);
713 centry
= wcache_fetch_raw(kstr
);
714 if (centry
== NULL
) {
719 if (centry_expired(domain
, kstr
, centry
)) {
721 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
722 kstr
, domain
->name
));
729 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
730 kstr
, domain
->name
));
736 static void wcache_delete(const char *format
, ...) PRINTF_ATTRIBUTE(1,2);
737 static void wcache_delete(const char *format
, ...)
743 va_start(ap
, format
);
744 smb_xvasprintf(&kstr
, format
, ap
);
747 key
= string_tdb_data(kstr
);
749 tdb_delete(wcache
->tdb
, key
);
754 make sure we have at least len bytes available in a centry
756 static void centry_expand(struct cache_entry
*centry
, uint32 len
)
758 if (centry
->len
- centry
->ofs
>= len
)
761 centry
->data
= SMB_REALLOC_ARRAY(centry
->data
, unsigned char,
764 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry
->len
));
765 smb_panic_fn("out of memory in centry_expand");
770 push a uint64_t into a centry
772 static void centry_put_uint64_t(struct cache_entry
*centry
, uint64_t v
)
774 centry_expand(centry
, 8);
775 SBVAL(centry
->data
, centry
->ofs
, v
);
780 push a uint32 into a centry
782 static void centry_put_uint32(struct cache_entry
*centry
, uint32 v
)
784 centry_expand(centry
, 4);
785 SIVAL(centry
->data
, centry
->ofs
, v
);
790 push a uint16 into a centry
792 static void centry_put_uint16(struct cache_entry
*centry
, uint16 v
)
794 centry_expand(centry
, 2);
795 SSVAL(centry
->data
, centry
->ofs
, v
);
800 push a uint8 into a centry
802 static void centry_put_uint8(struct cache_entry
*centry
, uint8 v
)
804 centry_expand(centry
, 1);
805 SCVAL(centry
->data
, centry
->ofs
, v
);
810 push a string into a centry
812 static void centry_put_string(struct cache_entry
*centry
, const char *s
)
817 /* null strings are marked as len 0xFFFF */
818 centry_put_uint8(centry
, 0xFF);
823 /* can't handle more than 254 char strings. Truncating is probably best */
825 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len
));
828 centry_put_uint8(centry
, len
);
829 centry_expand(centry
, len
);
830 memcpy(centry
->data
+ centry
->ofs
, s
, len
);
835 push a 16 byte hash into a centry - treat as 16 byte string.
837 static void centry_put_hash16(struct cache_entry
*centry
, const uint8 val
[16])
839 centry_put_uint8(centry
, 16);
840 centry_expand(centry
, 16);
841 memcpy(centry
->data
+ centry
->ofs
, val
, 16);
845 static void centry_put_sid(struct cache_entry
*centry
, const struct dom_sid
*sid
)
848 centry_put_string(centry
, sid_to_fstring(sid_string
, sid
));
853 put NTSTATUS into a centry
855 static void centry_put_ntstatus(struct cache_entry
*centry
, NTSTATUS status
)
857 uint32 status_value
= NT_STATUS_V(status
);
858 centry_put_uint32(centry
, status_value
);
863 push a NTTIME into a centry
865 static void centry_put_nttime(struct cache_entry
*centry
, NTTIME nt
)
867 centry_expand(centry
, 8);
868 SIVAL(centry
->data
, centry
->ofs
, nt
& 0xFFFFFFFF);
870 SIVAL(centry
->data
, centry
->ofs
, nt
>> 32);
875 push a time_t into a centry - use a 64 bit size.
876 NTTIME here is being used as a convenient 64-bit size.
878 static void centry_put_time(struct cache_entry
*centry
, time_t t
)
880 NTTIME nt
= (NTTIME
)t
;
881 centry_put_nttime(centry
, nt
);
885 start a centry for output. When finished, call centry_end()
887 struct cache_entry
*centry_start(struct winbindd_domain
*domain
, NTSTATUS status
)
889 struct cache_entry
*centry
;
894 centry
= SMB_XMALLOC_P(struct cache_entry
);
896 centry
->len
= 8192; /* reasonable default */
897 centry
->data
= SMB_XMALLOC_ARRAY(uint8
, centry
->len
);
899 centry
->sequence_number
= domain
->sequence_number
;
900 centry
->timeout
= lp_winbind_cache_time() + time(NULL
);
901 centry_put_ntstatus(centry
, status
);
902 centry_put_uint32(centry
, centry
->sequence_number
);
903 centry_put_uint64_t(centry
, centry
->timeout
);
908 finish a centry and write it to the tdb
910 static void centry_end(struct cache_entry
*centry
, const char *format
, ...) PRINTF_ATTRIBUTE(2,3);
911 static void centry_end(struct cache_entry
*centry
, const char *format
, ...)
917 if (!winbindd_use_cache()) {
921 va_start(ap
, format
);
922 smb_xvasprintf(&kstr
, format
, ap
);
925 key
= string_tdb_data(kstr
);
926 data
.dptr
= centry
->data
;
927 data
.dsize
= centry
->ofs
;
929 tdb_store(wcache
->tdb
, key
, data
, TDB_REPLACE
);
933 static void wcache_save_name_to_sid(struct winbindd_domain
*domain
,
934 NTSTATUS status
, const char *domain_name
,
935 const char *name
, const struct dom_sid
*sid
,
936 enum lsa_SidType type
)
938 struct cache_entry
*centry
;
941 centry
= centry_start(domain
, status
);
944 centry_put_uint32(centry
, type
);
945 centry_put_sid(centry
, sid
);
946 fstrcpy(uname
, name
);
948 centry_end(centry
, "NS/%s/%s", domain_name
, uname
);
949 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name
,
950 uname
, sid_string_dbg(sid
), nt_errstr(status
)));
954 static void wcache_save_sid_to_name(struct winbindd_domain
*domain
, NTSTATUS status
,
955 const struct dom_sid
*sid
, const char *domain_name
, const char *name
, enum lsa_SidType type
)
957 struct cache_entry
*centry
;
960 centry
= centry_start(domain
, status
);
964 if (NT_STATUS_IS_OK(status
)) {
965 centry_put_uint32(centry
, type
);
966 centry_put_string(centry
, domain_name
);
967 centry_put_string(centry
, name
);
970 centry_end(centry
, "SN/%s", sid_to_fstring(sid_string
, sid
));
971 DEBUG(10,("wcache_save_sid_to_name: %s -> %s (%s)\n", sid_string
,
972 name
, nt_errstr(status
)));
977 static void wcache_save_user(struct winbindd_domain
*domain
, NTSTATUS status
,
978 struct wbint_userinfo
*info
)
980 struct cache_entry
*centry
;
983 if (is_null_sid(&info
->user_sid
)) {
987 centry
= centry_start(domain
, status
);
990 centry_put_string(centry
, info
->acct_name
);
991 centry_put_string(centry
, info
->full_name
);
992 centry_put_string(centry
, info
->homedir
);
993 centry_put_string(centry
, info
->shell
);
994 centry_put_uint32(centry
, info
->primary_gid
);
995 centry_put_sid(centry
, &info
->user_sid
);
996 centry_put_sid(centry
, &info
->group_sid
);
997 centry_end(centry
, "U/%s", sid_to_fstring(sid_string
,
999 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string
, info
->acct_name
));
1000 centry_free(centry
);
1003 static void wcache_save_lockout_policy(struct winbindd_domain
*domain
,
1005 struct samr_DomInfo12
*lockout_policy
)
1007 struct cache_entry
*centry
;
1009 centry
= centry_start(domain
, status
);
1013 centry_put_nttime(centry
, lockout_policy
->lockout_duration
);
1014 centry_put_nttime(centry
, lockout_policy
->lockout_window
);
1015 centry_put_uint16(centry
, lockout_policy
->lockout_threshold
);
1017 centry_end(centry
, "LOC_POL/%s", domain
->name
);
1019 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain
->name
));
1021 centry_free(centry
);
1026 static void wcache_save_password_policy(struct winbindd_domain
*domain
,
1028 struct samr_DomInfo1
*policy
)
1030 struct cache_entry
*centry
;
1032 centry
= centry_start(domain
, status
);
1036 centry_put_uint16(centry
, policy
->min_password_length
);
1037 centry_put_uint16(centry
, policy
->password_history_length
);
1038 centry_put_uint32(centry
, policy
->password_properties
);
1039 centry_put_nttime(centry
, policy
->max_password_age
);
1040 centry_put_nttime(centry
, policy
->min_password_age
);
1042 centry_end(centry
, "PWD_POL/%s", domain
->name
);
1044 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
1046 centry_free(centry
);
1049 /***************************************************************************
1050 ***************************************************************************/
1052 static void wcache_save_username_alias(struct winbindd_domain
*domain
,
1054 const char *name
, const char *alias
)
1056 struct cache_entry
*centry
;
1059 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1062 centry_put_string( centry
, alias
);
1064 fstrcpy(uname
, name
);
1066 centry_end(centry
, "NSS/NA/%s", uname
);
1068 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name
, alias
));
1070 centry_free(centry
);
1073 static void wcache_save_alias_username(struct winbindd_domain
*domain
,
1075 const char *alias
, const char *name
)
1077 struct cache_entry
*centry
;
1080 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1083 centry_put_string( centry
, name
);
1085 fstrcpy(uname
, alias
);
1087 centry_end(centry
, "NSS/AN/%s", uname
);
1089 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias
, name
));
1091 centry_free(centry
);
1094 /***************************************************************************
1095 ***************************************************************************/
1097 NTSTATUS
resolve_username_to_alias( TALLOC_CTX
*mem_ctx
,
1098 struct winbindd_domain
*domain
,
1099 const char *name
, char **alias
)
1101 struct winbind_cache
*cache
= get_cache(domain
);
1102 struct cache_entry
*centry
= NULL
;
1106 if ( domain
->internal
)
1107 return NT_STATUS_NOT_SUPPORTED
;
1112 if ( (upper_name
= SMB_STRDUP(name
)) == NULL
)
1113 return NT_STATUS_NO_MEMORY
;
1114 strupper_m(upper_name
);
1116 centry
= wcache_fetch(cache
, domain
, "NSS/NA/%s", upper_name
);
1118 SAFE_FREE( upper_name
);
1123 status
= centry
->status
;
1125 if (!NT_STATUS_IS_OK(status
)) {
1126 centry_free(centry
);
1130 *alias
= centry_string( centry
, mem_ctx
);
1132 centry_free(centry
);
1134 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1135 name
, *alias
? *alias
: "(none)"));
1137 return (*alias
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1141 /* If its not in cache and we are offline, then fail */
1143 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1144 DEBUG(8,("resolve_username_to_alias: rejecting query "
1145 "in offline mode\n"));
1146 return NT_STATUS_NOT_FOUND
;
1149 status
= nss_map_to_alias( mem_ctx
, domain
->name
, name
, alias
);
1151 if ( NT_STATUS_IS_OK( status
) ) {
1152 wcache_save_username_alias(domain
, status
, name
, *alias
);
1155 if ( NT_STATUS_EQUAL( status
, NT_STATUS_NONE_MAPPED
) ) {
1156 wcache_save_username_alias(domain
, status
, name
, "(NULL)");
1159 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1160 nt_errstr(status
)));
1162 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1163 set_domain_offline( domain
);
1169 /***************************************************************************
1170 ***************************************************************************/
1172 NTSTATUS
resolve_alias_to_username( TALLOC_CTX
*mem_ctx
,
1173 struct winbindd_domain
*domain
,
1174 const char *alias
, char **name
)
1176 struct winbind_cache
*cache
= get_cache(domain
);
1177 struct cache_entry
*centry
= NULL
;
1181 if ( domain
->internal
)
1182 return NT_STATUS_NOT_SUPPORTED
;
1187 if ( (upper_name
= SMB_STRDUP(alias
)) == NULL
)
1188 return NT_STATUS_NO_MEMORY
;
1189 strupper_m(upper_name
);
1191 centry
= wcache_fetch(cache
, domain
, "NSS/AN/%s", upper_name
);
1193 SAFE_FREE( upper_name
);
1198 status
= centry
->status
;
1200 if (!NT_STATUS_IS_OK(status
)) {
1201 centry_free(centry
);
1205 *name
= centry_string( centry
, mem_ctx
);
1207 centry_free(centry
);
1209 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1210 alias
, *name
? *name
: "(none)"));
1212 return (*name
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1216 /* If its not in cache and we are offline, then fail */
1218 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1219 DEBUG(8,("resolve_alias_to_username: rejecting query "
1220 "in offline mode\n"));
1221 return NT_STATUS_NOT_FOUND
;
1224 /* an alias cannot contain a domain prefix or '@' */
1226 if (strchr(alias
, '\\') || strchr(alias
, '@')) {
1227 DEBUG(10,("resolve_alias_to_username: skipping fully "
1228 "qualified name %s\n", alias
));
1229 return NT_STATUS_OBJECT_NAME_INVALID
;
1232 status
= nss_map_from_alias( mem_ctx
, domain
->name
, alias
, name
);
1234 if ( NT_STATUS_IS_OK( status
) ) {
1235 wcache_save_alias_username( domain
, status
, alias
, *name
);
1238 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1239 wcache_save_alias_username(domain
, status
, alias
, "(NULL)");
1242 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1243 nt_errstr(status
)));
1245 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1246 set_domain_offline( domain
);
1252 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
1254 struct winbind_cache
*cache
= get_cache(domain
);
1256 fstring key_str
, tmp
;
1260 return NT_STATUS_INTERNAL_DB_ERROR
;
1263 if (is_null_sid(sid
)) {
1264 return NT_STATUS_INVALID_SID
;
1267 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1268 return NT_STATUS_INVALID_SID
;
1271 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
1273 data
= tdb_fetch(cache
->tdb
, string_tdb_data(key_str
));
1275 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1278 SAFE_FREE(data
.dptr
);
1279 return NT_STATUS_OK
;
1282 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1283 as new salted ones. */
1285 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
1286 TALLOC_CTX
*mem_ctx
,
1287 const struct dom_sid
*sid
,
1288 const uint8
**cached_nt_pass
,
1289 const uint8
**cached_salt
)
1291 struct winbind_cache
*cache
= get_cache(domain
);
1292 struct cache_entry
*centry
= NULL
;
1299 return NT_STATUS_INTERNAL_DB_ERROR
;
1302 if (is_null_sid(sid
)) {
1303 return NT_STATUS_INVALID_SID
;
1306 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1307 return NT_STATUS_INVALID_SID
;
1310 /* Try and get a salted cred first. If we can't
1311 fall back to an unsalted cred. */
1313 centry
= wcache_fetch(cache
, domain
, "CRED/%s",
1314 sid_to_fstring(tmp
, sid
));
1316 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1317 sid_string_dbg(sid
)));
1318 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1321 t
= centry_time(centry
);
1323 /* In the salted case this isn't actually the nt_hash itself,
1324 but the MD5 of the salt + nt_hash. Let the caller
1325 sort this out. It can tell as we only return the cached_salt
1326 if we are returning a salted cred. */
1328 *cached_nt_pass
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1329 if (*cached_nt_pass
== NULL
) {
1332 sid_to_fstring(sidstr
, sid
);
1334 /* Bad (old) cred cache. Delete and pretend we
1336 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1338 wcache_delete("CRED/%s", sidstr
);
1339 centry_free(centry
);
1340 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1343 /* We only have 17 bytes more data in the salted cred case. */
1344 if (centry
->len
- centry
->ofs
== 17) {
1345 *cached_salt
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1347 *cached_salt
= NULL
;
1350 dump_data_pw("cached_nt_pass", *cached_nt_pass
, NT_HASH_LEN
);
1352 dump_data_pw("cached_salt", *cached_salt
, NT_HASH_LEN
);
1355 status
= centry
->status
;
1357 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1358 sid_string_dbg(sid
), nt_errstr(status
) ));
1360 centry_free(centry
);
1364 /* Store creds for a SID - only writes out new salted ones. */
1366 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1367 const struct dom_sid
*sid
,
1368 const uint8 nt_pass
[NT_HASH_LEN
])
1370 struct cache_entry
*centry
;
1373 uint8 cred_salt
[NT_HASH_LEN
];
1374 uint8 salted_hash
[NT_HASH_LEN
];
1376 if (is_null_sid(sid
)) {
1377 return NT_STATUS_INVALID_SID
;
1380 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1381 return NT_STATUS_INVALID_SID
;
1384 centry
= centry_start(domain
, NT_STATUS_OK
);
1386 return NT_STATUS_INTERNAL_DB_ERROR
;
1389 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1391 centry_put_time(centry
, time(NULL
));
1393 /* Create a salt and then salt the hash. */
1394 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1395 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1397 centry_put_hash16(centry
, salted_hash
);
1398 centry_put_hash16(centry
, cred_salt
);
1399 centry_end(centry
, "CRED/%s", sid_to_fstring(sid_string
, sid
));
1401 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1403 centry_free(centry
);
1405 return NT_STATUS_OK
;
1409 /* Query display info. This is the basic user list fn */
1410 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
1411 TALLOC_CTX
*mem_ctx
,
1412 uint32
*num_entries
,
1413 struct wbint_userinfo
**info
)
1415 struct winbind_cache
*cache
= get_cache(domain
);
1416 struct cache_entry
*centry
= NULL
;
1418 unsigned int i
, retry
;
1419 bool old_status
= domain
->online
;
1424 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1429 *num_entries
= centry_uint32(centry
);
1431 if (*num_entries
== 0)
1434 (*info
) = TALLOC_ARRAY(mem_ctx
, struct wbint_userinfo
, *num_entries
);
1436 smb_panic_fn("query_user_list out of memory");
1438 for (i
=0; i
<(*num_entries
); i
++) {
1439 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
1440 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
1441 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
1442 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
1443 centry_sid(centry
, &(*info
)[i
].user_sid
);
1444 centry_sid(centry
, &(*info
)[i
].group_sid
);
1448 status
= centry
->status
;
1450 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1451 domain
->name
, nt_errstr(status
) ));
1453 centry_free(centry
);
1460 /* Return status value returned by seq number check */
1462 if (!NT_STATUS_IS_OK(domain
->last_status
))
1463 return domain
->last_status
;
1465 /* Put the query_user_list() in a retry loop. There appears to be
1466 * some bug either with Windows 2000 or Samba's handling of large
1467 * rpc replies. This manifests itself as sudden disconnection
1468 * at a random point in the enumeration of a large (60k) user list.
1469 * The retry loop simply tries the operation again. )-: It's not
1470 * pretty but an acceptable workaround until we work out what the
1471 * real problem is. */
1476 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1479 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
1480 if (!NT_STATUS_IS_OK(status
)) {
1481 DEBUG(3, ("query_user_list: returned 0x%08x, "
1482 "retrying\n", NT_STATUS_V(status
)));
1484 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1485 DEBUG(3, ("query_user_list: flushing "
1486 "connection cache\n"));
1487 invalidate_cm_connection(&domain
->conn
);
1489 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1490 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1491 if (!domain
->internal
&& old_status
) {
1492 set_domain_offline(domain
);
1494 /* store partial response. */
1495 if (*num_entries
> 0) {
1497 * humm, what about the status used for cache?
1498 * Should it be NT_STATUS_OK?
1503 * domain is offline now, and there is no user entries,
1504 * try to fetch from cache again.
1506 if (cache
->tdb
&& !domain
->online
&& !domain
->internal
&& old_status
) {
1507 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1508 /* partial response... */
1512 goto do_fetch_cache
;
1519 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1523 refresh_sequence_number(domain
, false);
1524 if (!NT_STATUS_IS_OK(status
)) {
1527 centry
= centry_start(domain
, status
);
1530 centry_put_uint32(centry
, *num_entries
);
1531 for (i
=0; i
<(*num_entries
); i
++) {
1532 centry_put_string(centry
, (*info
)[i
].acct_name
);
1533 centry_put_string(centry
, (*info
)[i
].full_name
);
1534 centry_put_string(centry
, (*info
)[i
].homedir
);
1535 centry_put_string(centry
, (*info
)[i
].shell
);
1536 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1537 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1538 if (domain
->backend
&& domain
->backend
->consistent
) {
1539 /* when the backend is consistent we can pre-prime some mappings */
1540 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1542 (*info
)[i
].acct_name
,
1543 &(*info
)[i
].user_sid
,
1545 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1546 &(*info
)[i
].user_sid
,
1548 (*info
)[i
].acct_name
,
1550 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1553 centry_end(centry
, "UL/%s", domain
->name
);
1554 centry_free(centry
);
1560 /* list all domain groups */
1561 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
1562 TALLOC_CTX
*mem_ctx
,
1563 uint32
*num_entries
,
1564 struct wb_acct_info
**info
)
1566 struct winbind_cache
*cache
= get_cache(domain
);
1567 struct cache_entry
*centry
= NULL
;
1572 old_status
= domain
->online
;
1576 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1581 *num_entries
= centry_uint32(centry
);
1583 if (*num_entries
== 0)
1586 (*info
) = TALLOC_ARRAY(mem_ctx
, struct wb_acct_info
, *num_entries
);
1588 smb_panic_fn("enum_dom_groups out of memory");
1590 for (i
=0; i
<(*num_entries
); i
++) {
1591 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1592 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1593 (*info
)[i
].rid
= centry_uint32(centry
);
1597 status
= centry
->status
;
1599 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1600 domain
->name
, nt_errstr(status
) ));
1602 centry_free(centry
);
1609 /* Return status value returned by seq number check */
1611 if (!NT_STATUS_IS_OK(domain
->last_status
))
1612 return domain
->last_status
;
1614 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1617 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1619 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1620 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1621 if (!domain
->internal
&& old_status
) {
1622 set_domain_offline(domain
);
1626 !domain
->internal
&&
1628 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1630 goto do_fetch_cache
;
1635 refresh_sequence_number(domain
, false);
1636 if (!NT_STATUS_IS_OK(status
)) {
1639 centry
= centry_start(domain
, status
);
1642 centry_put_uint32(centry
, *num_entries
);
1643 for (i
=0; i
<(*num_entries
); i
++) {
1644 centry_put_string(centry
, (*info
)[i
].acct_name
);
1645 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1646 centry_put_uint32(centry
, (*info
)[i
].rid
);
1648 centry_end(centry
, "GL/%s/domain", domain
->name
);
1649 centry_free(centry
);
1655 /* list all domain groups */
1656 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
1657 TALLOC_CTX
*mem_ctx
,
1658 uint32
*num_entries
,
1659 struct wb_acct_info
**info
)
1661 struct winbind_cache
*cache
= get_cache(domain
);
1662 struct cache_entry
*centry
= NULL
;
1667 old_status
= domain
->online
;
1671 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1676 *num_entries
= centry_uint32(centry
);
1678 if (*num_entries
== 0)
1681 (*info
) = TALLOC_ARRAY(mem_ctx
, struct wb_acct_info
, *num_entries
);
1683 smb_panic_fn("enum_dom_groups out of memory");
1685 for (i
=0; i
<(*num_entries
); i
++) {
1686 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1687 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1688 (*info
)[i
].rid
= centry_uint32(centry
);
1693 /* If we are returning cached data and the domain controller
1694 is down then we don't know whether the data is up to date
1695 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1698 if (wcache_server_down(domain
)) {
1699 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1700 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1702 status
= centry
->status
;
1704 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1705 domain
->name
, nt_errstr(status
) ));
1707 centry_free(centry
);
1714 /* Return status value returned by seq number check */
1716 if (!NT_STATUS_IS_OK(domain
->last_status
))
1717 return domain
->last_status
;
1719 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1722 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1724 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1725 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1726 if (!domain
->internal
&& old_status
) {
1727 set_domain_offline(domain
);
1730 !domain
->internal
&&
1733 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1735 goto do_fetch_cache
;
1740 refresh_sequence_number(domain
, false);
1741 if (!NT_STATUS_IS_OK(status
)) {
1744 centry
= centry_start(domain
, status
);
1747 centry_put_uint32(centry
, *num_entries
);
1748 for (i
=0; i
<(*num_entries
); i
++) {
1749 centry_put_string(centry
, (*info
)[i
].acct_name
);
1750 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1751 centry_put_uint32(centry
, (*info
)[i
].rid
);
1753 centry_end(centry
, "GL/%s/local", domain
->name
);
1754 centry_free(centry
);
1760 NTSTATUS
wcache_name_to_sid(struct winbindd_domain
*domain
,
1761 const char *domain_name
,
1763 struct dom_sid
*sid
,
1764 enum lsa_SidType
*type
)
1766 struct winbind_cache
*cache
= get_cache(domain
);
1767 struct cache_entry
*centry
;
1771 if (cache
->tdb
== NULL
) {
1772 return NT_STATUS_NOT_FOUND
;
1775 uname
= talloc_strdup_upper(talloc_tos(), name
);
1776 if (uname
== NULL
) {
1777 return NT_STATUS_NO_MEMORY
;
1780 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1782 if (centry
== NULL
) {
1783 return NT_STATUS_NOT_FOUND
;
1786 status
= centry
->status
;
1787 if (NT_STATUS_IS_OK(status
)) {
1788 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1789 centry_sid(centry
, sid
);
1792 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1793 "%s\n", domain
->name
, nt_errstr(status
) ));
1795 centry_free(centry
);
1799 /* convert a single name to a sid in a domain */
1800 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
1801 TALLOC_CTX
*mem_ctx
,
1802 const char *domain_name
,
1805 struct dom_sid
*sid
,
1806 enum lsa_SidType
*type
)
1811 old_status
= domain
->online
;
1813 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1814 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1820 /* If the seq number check indicated that there is a problem
1821 * with this DC, then return that status... except for
1822 * access_denied. This is special because the dc may be in
1823 * "restrict anonymous = 1" mode, in which case it will deny
1824 * most unauthenticated operations, but *will* allow the LSA
1825 * name-to-sid that we try as a fallback. */
1827 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1828 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1829 return domain
->last_status
;
1831 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1834 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
,
1835 name
, flags
, sid
, type
);
1837 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1838 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1839 if (!domain
->internal
&& old_status
) {
1840 set_domain_offline(domain
);
1842 if (!domain
->internal
&&
1845 NTSTATUS cache_status
;
1846 cache_status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1847 return cache_status
;
1851 refresh_sequence_number(domain
, false);
1853 if (domain
->online
&&
1854 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1855 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1857 /* Only save the reverse mapping if this was not a UPN */
1858 if (!strchr(name
, '@')) {
1859 strupper_m(CONST_DISCARD(char *,domain_name
));
1860 strlower_m(CONST_DISCARD(char *,name
));
1861 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1868 NTSTATUS
wcache_sid_to_name(struct winbindd_domain
*domain
,
1869 const struct dom_sid
*sid
,
1870 TALLOC_CTX
*mem_ctx
,
1873 enum lsa_SidType
*type
)
1875 struct winbind_cache
*cache
= get_cache(domain
);
1876 struct cache_entry
*centry
;
1880 if (cache
->tdb
== NULL
) {
1881 return NT_STATUS_NOT_FOUND
;
1884 sid_string
= sid_string_tos(sid
);
1885 if (sid_string
== NULL
) {
1886 return NT_STATUS_NO_MEMORY
;
1889 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_string
);
1890 TALLOC_FREE(sid_string
);
1891 if (centry
== NULL
) {
1892 return NT_STATUS_NOT_FOUND
;
1895 if (NT_STATUS_IS_OK(centry
->status
)) {
1896 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1897 *domain_name
= centry_string(centry
, mem_ctx
);
1898 *name
= centry_string(centry
, mem_ctx
);
1901 status
= centry
->status
;
1902 centry_free(centry
);
1904 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1905 "%s\n", domain
->name
, nt_errstr(status
) ));
1910 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1912 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1913 TALLOC_CTX
*mem_ctx
,
1914 const struct dom_sid
*sid
,
1917 enum lsa_SidType
*type
)
1922 old_status
= domain
->online
;
1923 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
1925 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1930 *domain_name
= NULL
;
1932 /* If the seq number check indicated that there is a problem
1933 * with this DC, then return that status... except for
1934 * access_denied. This is special because the dc may be in
1935 * "restrict anonymous = 1" mode, in which case it will deny
1936 * most unauthenticated operations, but *will* allow the LSA
1937 * sid-to-name that we try as a fallback. */
1939 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1940 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1941 return domain
->last_status
;
1943 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1946 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1948 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1949 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1950 if (!domain
->internal
&& old_status
) {
1951 set_domain_offline(domain
);
1953 if (!domain
->internal
&&
1956 NTSTATUS cache_status
;
1957 cache_status
= wcache_sid_to_name(domain
, sid
, mem_ctx
,
1958 domain_name
, name
, type
);
1959 return cache_status
;
1963 refresh_sequence_number(domain
, false);
1964 if (!NT_STATUS_IS_OK(status
)) {
1967 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
1969 /* We can't save the name to sid mapping here, as with sid history a
1970 * later name2sid would give the wrong sid. */
1975 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
1976 TALLOC_CTX
*mem_ctx
,
1977 const struct dom_sid
*domain_sid
,
1982 enum lsa_SidType
**types
)
1984 struct winbind_cache
*cache
= get_cache(domain
);
1986 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1991 old_status
= domain
->online
;
1992 *domain_name
= NULL
;
2000 if (num_rids
== 0) {
2001 return NT_STATUS_OK
;
2004 *names
= TALLOC_ARRAY(mem_ctx
, char *, num_rids
);
2005 *types
= TALLOC_ARRAY(mem_ctx
, enum lsa_SidType
, num_rids
);
2007 if ((*names
== NULL
) || (*types
== NULL
)) {
2008 result
= NT_STATUS_NO_MEMORY
;
2012 have_mapped
= have_unmapped
= false;
2014 for (i
=0; i
<num_rids
; i
++) {
2016 struct cache_entry
*centry
;
2019 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2020 result
= NT_STATUS_INTERNAL_ERROR
;
2024 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2025 sid_to_fstring(tmp
, &sid
));
2030 (*types
)[i
] = SID_NAME_UNKNOWN
;
2031 (*names
)[i
] = talloc_strdup(*names
, "");
2033 if (NT_STATUS_IS_OK(centry
->status
)) {
2036 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2038 dom
= centry_string(centry
, mem_ctx
);
2039 if (*domain_name
== NULL
) {
2045 (*names
)[i
] = centry_string(centry
, *names
);
2047 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)
2048 || NT_STATUS_EQUAL(centry
->status
, STATUS_SOME_UNMAPPED
)) {
2049 have_unmapped
= true;
2052 /* something's definitely wrong */
2053 result
= centry
->status
;
2057 centry_free(centry
);
2061 return NT_STATUS_NONE_MAPPED
;
2063 if (!have_unmapped
) {
2064 return NT_STATUS_OK
;
2066 return STATUS_SOME_UNMAPPED
;
2070 TALLOC_FREE(*names
);
2071 TALLOC_FREE(*types
);
2073 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
2074 rids
, num_rids
, domain_name
,
2077 if (NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
2078 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2079 if (!domain
->internal
&& old_status
) {
2080 set_domain_offline(domain
);
2083 !domain
->internal
&&
2086 have_mapped
= have_unmapped
= false;
2088 for (i
=0; i
<num_rids
; i
++) {
2090 struct cache_entry
*centry
;
2093 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2094 result
= NT_STATUS_INTERNAL_ERROR
;
2098 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2099 sid_to_fstring(tmp
, &sid
));
2101 (*types
)[i
] = SID_NAME_UNKNOWN
;
2102 (*names
)[i
] = talloc_strdup(*names
, "");
2106 (*types
)[i
] = SID_NAME_UNKNOWN
;
2107 (*names
)[i
] = talloc_strdup(*names
, "");
2109 if (NT_STATUS_IS_OK(centry
->status
)) {
2112 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2114 dom
= centry_string(centry
, mem_ctx
);
2115 if (*domain_name
== NULL
) {
2121 (*names
)[i
] = centry_string(centry
, *names
);
2123 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)) {
2124 have_unmapped
= true;
2127 /* something's definitely wrong */
2128 result
= centry
->status
;
2132 centry_free(centry
);
2136 return NT_STATUS_NONE_MAPPED
;
2138 if (!have_unmapped
) {
2139 return NT_STATUS_OK
;
2141 return STATUS_SOME_UNMAPPED
;
2145 None of the queried rids has been found so save all negative entries
2147 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
2148 for (i
= 0; i
< num_rids
; i
++) {
2150 const char *name
= "";
2151 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
2152 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
2154 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2155 return NT_STATUS_INTERNAL_ERROR
;
2158 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2166 Some or all of the queried rids have been found.
2168 if (!NT_STATUS_IS_OK(result
) &&
2169 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
2173 refresh_sequence_number(domain
, false);
2175 for (i
=0; i
<num_rids
; i
++) {
2179 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2180 result
= NT_STATUS_INTERNAL_ERROR
;
2184 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
2185 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
2187 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2188 (*names
)[i
], (*types
)[i
]);
2194 TALLOC_FREE(*names
);
2195 TALLOC_FREE(*types
);
2199 NTSTATUS
wcache_query_user(struct winbindd_domain
*domain
,
2200 TALLOC_CTX
*mem_ctx
,
2201 const struct dom_sid
*user_sid
,
2202 struct wbint_userinfo
*info
)
2204 struct winbind_cache
*cache
= get_cache(domain
);
2205 struct cache_entry
*centry
= NULL
;
2209 if (cache
->tdb
== NULL
) {
2210 return NT_STATUS_NOT_FOUND
;
2213 sid_string
= sid_string_tos(user_sid
);
2214 if (sid_string
== NULL
) {
2215 return NT_STATUS_NO_MEMORY
;
2218 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string
);
2219 TALLOC_FREE(sid_string
);
2220 if (centry
== NULL
) {
2221 return NT_STATUS_NOT_FOUND
;
2225 * If we have an access denied cache entry and a cached info3
2226 * in the samlogon cache then do a query. This will force the
2227 * rpc back end to return the info3 data.
2230 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
) &&
2231 netsamlogon_cache_have(user_sid
)) {
2232 DEBUG(10, ("query_user: cached access denied and have cached "
2234 domain
->last_status
= NT_STATUS_OK
;
2235 centry_free(centry
);
2236 return NT_STATUS_NOT_FOUND
;
2239 /* if status is not ok then this is a negative hit
2240 and the rest of the data doesn't matter */
2241 status
= centry
->status
;
2242 if (NT_STATUS_IS_OK(status
)) {
2243 info
->acct_name
= centry_string(centry
, mem_ctx
);
2244 info
->full_name
= centry_string(centry
, mem_ctx
);
2245 info
->homedir
= centry_string(centry
, mem_ctx
);
2246 info
->shell
= centry_string(centry
, mem_ctx
);
2247 info
->primary_gid
= centry_uint32(centry
);
2248 centry_sid(centry
, &info
->user_sid
);
2249 centry_sid(centry
, &info
->group_sid
);
2252 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2253 "%s\n", domain
->name
, nt_errstr(status
) ));
2255 centry_free(centry
);
2259 /* Lookup user information from a rid */
2260 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
2261 TALLOC_CTX
*mem_ctx
,
2262 const struct dom_sid
*user_sid
,
2263 struct wbint_userinfo
*info
)
2268 old_status
= domain
->online
;
2269 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2270 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2276 /* Return status value returned by seq number check */
2278 if (!NT_STATUS_IS_OK(domain
->last_status
))
2279 return domain
->last_status
;
2281 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2284 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
2286 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2287 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2288 if (!domain
->internal
&& old_status
) {
2289 set_domain_offline(domain
);
2291 if (!domain
->internal
&&
2294 NTSTATUS cache_status
;
2295 cache_status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2296 return cache_status
;
2300 refresh_sequence_number(domain
, false);
2301 if (!NT_STATUS_IS_OK(status
)) {
2304 wcache_save_user(domain
, status
, info
);
2309 NTSTATUS
wcache_lookup_usergroups(struct winbindd_domain
*domain
,
2310 TALLOC_CTX
*mem_ctx
,
2311 const struct dom_sid
*user_sid
,
2312 uint32_t *pnum_sids
,
2313 struct dom_sid
**psids
)
2315 struct winbind_cache
*cache
= get_cache(domain
);
2316 struct cache_entry
*centry
= NULL
;
2318 uint32_t i
, num_sids
;
2319 struct dom_sid
*sids
;
2322 if (cache
->tdb
== NULL
) {
2323 return NT_STATUS_NOT_FOUND
;
2326 centry
= wcache_fetch(cache
, domain
, "UG/%s",
2327 sid_to_fstring(sid_string
, user_sid
));
2328 if (centry
== NULL
) {
2329 return NT_STATUS_NOT_FOUND
;
2332 /* If we have an access denied cache entry and a cached info3 in the
2333 samlogon cache then do a query. This will force the rpc back end
2334 to return the info3 data. */
2336 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)
2337 && netsamlogon_cache_have(user_sid
)) {
2338 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2340 domain
->last_status
= NT_STATUS_OK
;
2341 centry_free(centry
);
2342 return NT_STATUS_NOT_FOUND
;
2345 num_sids
= centry_uint32(centry
);
2346 sids
= talloc_array(mem_ctx
, struct dom_sid
, num_sids
);
2348 centry_free(centry
);
2349 return NT_STATUS_NO_MEMORY
;
2352 for (i
=0; i
<num_sids
; i
++) {
2353 centry_sid(centry
, &sids
[i
]);
2356 status
= centry
->status
;
2358 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2359 "status: %s\n", domain
->name
, nt_errstr(status
)));
2361 centry_free(centry
);
2363 *pnum_sids
= num_sids
;
2368 /* Lookup groups a user is a member of. */
2369 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
2370 TALLOC_CTX
*mem_ctx
,
2371 const struct dom_sid
*user_sid
,
2372 uint32
*num_groups
, struct dom_sid
**user_gids
)
2374 struct cache_entry
*centry
= NULL
;
2380 old_status
= domain
->online
;
2381 status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2382 num_groups
, user_gids
);
2383 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2388 (*user_gids
) = NULL
;
2390 /* Return status value returned by seq number check */
2392 if (!NT_STATUS_IS_OK(domain
->last_status
))
2393 return domain
->last_status
;
2395 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2398 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
2400 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2401 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2402 if (!domain
->internal
&& old_status
) {
2403 set_domain_offline(domain
);
2405 if (!domain
->internal
&&
2408 NTSTATUS cache_status
;
2409 cache_status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2410 num_groups
, user_gids
);
2411 return cache_status
;
2414 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
2418 refresh_sequence_number(domain
, false);
2419 if (!NT_STATUS_IS_OK(status
)) {
2422 centry
= centry_start(domain
, status
);
2426 centry_put_uint32(centry
, *num_groups
);
2427 for (i
=0; i
<(*num_groups
); i
++) {
2428 centry_put_sid(centry
, &(*user_gids
)[i
]);
2431 centry_end(centry
, "UG/%s", sid_to_fstring(sid_string
, user_sid
));
2432 centry_free(centry
);
2438 static char *wcache_make_sidlist(TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2439 const struct dom_sid
*sids
)
2444 sidlist
= talloc_strdup(mem_ctx
, "");
2445 if (sidlist
== NULL
) {
2448 for (i
=0; i
<num_sids
; i
++) {
2450 sidlist
= talloc_asprintf_append_buffer(
2451 sidlist
, "/%s", sid_to_fstring(tmp
, &sids
[i
]));
2452 if (sidlist
== NULL
) {
2459 NTSTATUS
wcache_lookup_useraliases(struct winbindd_domain
*domain
,
2460 TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2461 const struct dom_sid
*sids
,
2462 uint32_t *pnum_aliases
, uint32_t **paliases
)
2464 struct winbind_cache
*cache
= get_cache(domain
);
2465 struct cache_entry
*centry
= NULL
;
2466 uint32_t num_aliases
;
2472 if (cache
->tdb
== NULL
) {
2473 return NT_STATUS_NOT_FOUND
;
2476 if (num_sids
== 0) {
2479 return NT_STATUS_OK
;
2482 /* We need to cache indexed by the whole list of SIDs, the aliases
2483 * resulting might come from any of the SIDs. */
2485 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2486 if (sidlist
== NULL
) {
2487 return NT_STATUS_NO_MEMORY
;
2490 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2491 TALLOC_FREE(sidlist
);
2492 if (centry
== NULL
) {
2493 return NT_STATUS_NOT_FOUND
;
2496 num_aliases
= centry_uint32(centry
);
2497 aliases
= talloc_array(mem_ctx
, uint32_t, num_aliases
);
2498 if (aliases
== NULL
) {
2499 centry_free(centry
);
2500 return NT_STATUS_NO_MEMORY
;
2503 for (i
=0; i
<num_aliases
; i
++) {
2504 aliases
[i
] = centry_uint32(centry
);
2507 status
= centry
->status
;
2509 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2510 "status %s\n", domain
->name
, nt_errstr(status
)));
2512 centry_free(centry
);
2514 *pnum_aliases
= num_aliases
;
2515 *paliases
= aliases
;
2520 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
2521 TALLOC_CTX
*mem_ctx
,
2522 uint32 num_sids
, const struct dom_sid
*sids
,
2523 uint32
*num_aliases
, uint32
**alias_rids
)
2525 struct cache_entry
*centry
= NULL
;
2531 old_status
= domain
->online
;
2532 status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
2533 num_aliases
, alias_rids
);
2534 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2539 (*alias_rids
) = NULL
;
2541 if (!NT_STATUS_IS_OK(domain
->last_status
))
2542 return domain
->last_status
;
2544 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2545 "for domain %s\n", domain
->name
));
2547 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2548 if (sidlist
== NULL
) {
2549 return NT_STATUS_NO_MEMORY
;
2552 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2554 num_aliases
, alias_rids
);
2556 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2557 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2558 if (!domain
->internal
&& old_status
) {
2559 set_domain_offline(domain
);
2561 if (!domain
->internal
&&
2564 NTSTATUS cache_status
;
2565 cache_status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
,
2566 sids
, num_aliases
, alias_rids
);
2567 return cache_status
;
2571 refresh_sequence_number(domain
, false);
2572 if (!NT_STATUS_IS_OK(status
)) {
2575 centry
= centry_start(domain
, status
);
2578 centry_put_uint32(centry
, *num_aliases
);
2579 for (i
=0; i
<(*num_aliases
); i
++)
2580 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2581 centry_end(centry
, "UA%s", sidlist
);
2582 centry_free(centry
);
2588 NTSTATUS
wcache_lookup_groupmem(struct winbindd_domain
*domain
,
2589 TALLOC_CTX
*mem_ctx
,
2590 const struct dom_sid
*group_sid
,
2591 uint32_t *num_names
,
2592 struct dom_sid
**sid_mem
, char ***names
,
2593 uint32_t **name_types
)
2595 struct winbind_cache
*cache
= get_cache(domain
);
2596 struct cache_entry
*centry
= NULL
;
2601 if (cache
->tdb
== NULL
) {
2602 return NT_STATUS_NOT_FOUND
;
2605 sid_string
= sid_string_tos(group_sid
);
2606 if (sid_string
== NULL
) {
2607 return NT_STATUS_NO_MEMORY
;
2610 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_string
);
2611 TALLOC_FREE(sid_string
);
2612 if (centry
== NULL
) {
2613 return NT_STATUS_NOT_FOUND
;
2620 *num_names
= centry_uint32(centry
);
2621 if (*num_names
== 0) {
2622 centry_free(centry
);
2623 return NT_STATUS_OK
;
2626 *sid_mem
= talloc_array(mem_ctx
, struct dom_sid
, *num_names
);
2627 *names
= talloc_array(mem_ctx
, char *, *num_names
);
2628 *name_types
= talloc_array(mem_ctx
, uint32
, *num_names
);
2630 if ((*sid_mem
== NULL
) || (*names
== NULL
) || (*name_types
== NULL
)) {
2631 TALLOC_FREE(*sid_mem
);
2632 TALLOC_FREE(*names
);
2633 TALLOC_FREE(*name_types
);
2634 centry_free(centry
);
2635 return NT_STATUS_NO_MEMORY
;
2638 for (i
=0; i
<(*num_names
); i
++) {
2639 centry_sid(centry
, &(*sid_mem
)[i
]);
2640 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2641 (*name_types
)[i
] = centry_uint32(centry
);
2644 status
= centry
->status
;
2646 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2647 "status: %s\n", domain
->name
, nt_errstr(status
)));
2649 centry_free(centry
);
2653 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
2654 TALLOC_CTX
*mem_ctx
,
2655 const struct dom_sid
*group_sid
,
2656 enum lsa_SidType type
,
2658 struct dom_sid
**sid_mem
, char ***names
,
2659 uint32
**name_types
)
2661 struct cache_entry
*centry
= NULL
;
2667 old_status
= domain
->online
;
2668 status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2669 sid_mem
, names
, name_types
);
2670 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2677 (*name_types
) = NULL
;
2679 /* Return status value returned by seq number check */
2681 if (!NT_STATUS_IS_OK(domain
->last_status
))
2682 return domain
->last_status
;
2684 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2687 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
,
2689 sid_mem
, names
, name_types
);
2691 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2692 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2693 if (!domain
->internal
&& old_status
) {
2694 set_domain_offline(domain
);
2696 if (!domain
->internal
&&
2699 NTSTATUS cache_status
;
2700 cache_status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
,
2701 num_names
, sid_mem
, names
,
2703 return cache_status
;
2707 refresh_sequence_number(domain
, false);
2708 if (!NT_STATUS_IS_OK(status
)) {
2711 centry
= centry_start(domain
, status
);
2714 centry_put_uint32(centry
, *num_names
);
2715 for (i
=0; i
<(*num_names
); i
++) {
2716 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2717 centry_put_string(centry
, (*names
)[i
]);
2718 centry_put_uint32(centry
, (*name_types
)[i
]);
2720 centry_end(centry
, "GM/%s", sid_to_fstring(sid_string
, group_sid
));
2721 centry_free(centry
);
2727 /* find the sequence number for a domain */
2728 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
2730 refresh_sequence_number(domain
, false);
2732 *seq
= domain
->sequence_number
;
2734 return NT_STATUS_OK
;
2737 /* enumerate trusted domains
2738 * (we need to have the list of trustdoms in the cache when we go offline) -
2740 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
2741 TALLOC_CTX
*mem_ctx
,
2742 struct netr_DomainTrustList
*trusts
)
2745 struct winbind_cache
*cache
;
2746 struct winbindd_tdc_domain
*dom_list
= NULL
;
2747 size_t num_domains
= 0;
2748 bool retval
= false;
2752 old_status
= domain
->online
;
2754 trusts
->array
= NULL
;
2756 cache
= get_cache(domain
);
2757 if (!cache
|| !cache
->tdb
) {
2761 if (domain
->online
) {
2765 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2766 if (!retval
|| !num_domains
|| !dom_list
) {
2767 TALLOC_FREE(dom_list
);
2772 trusts
->array
= TALLOC_ZERO_ARRAY(mem_ctx
, struct netr_DomainTrust
, num_domains
);
2773 if (!trusts
->array
) {
2774 TALLOC_FREE(dom_list
);
2775 return NT_STATUS_NO_MEMORY
;
2778 for (i
= 0; i
< num_domains
; i
++) {
2779 struct netr_DomainTrust
*trust
;
2780 struct dom_sid
*sid
;
2781 struct winbindd_domain
*dom
;
2783 dom
= find_domain_from_name_noinit(dom_list
[i
].domain_name
);
2784 if (dom
&& dom
->internal
) {
2788 trust
= &trusts
->array
[trusts
->count
];
2789 trust
->netbios_name
= talloc_strdup(trusts
->array
, dom_list
[i
].domain_name
);
2790 trust
->dns_name
= talloc_strdup(trusts
->array
, dom_list
[i
].dns_name
);
2791 sid
= talloc(trusts
->array
, struct dom_sid
);
2792 if (!trust
->netbios_name
|| !trust
->dns_name
||
2794 TALLOC_FREE(dom_list
);
2795 TALLOC_FREE(trusts
->array
);
2796 return NT_STATUS_NO_MEMORY
;
2799 trust
->trust_flags
= dom_list
[i
].trust_flags
;
2800 trust
->trust_attributes
= dom_list
[i
].trust_attribs
;
2801 trust
->trust_type
= dom_list
[i
].trust_type
;
2802 sid_copy(sid
, &dom_list
[i
].sid
);
2807 TALLOC_FREE(dom_list
);
2808 return NT_STATUS_OK
;
2811 /* Return status value returned by seq number check */
2813 if (!NT_STATUS_IS_OK(domain
->last_status
))
2814 return domain
->last_status
;
2816 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2819 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, trusts
);
2821 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2822 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2823 if (!domain
->internal
&& old_status
) {
2824 set_domain_offline(domain
);
2826 if (!domain
->internal
&&
2829 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2830 if (retval
&& num_domains
&& dom_list
) {
2831 TALLOC_FREE(trusts
->array
);
2833 goto do_fetch_cache
;
2837 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2838 * so that the generic centry handling still applies correctly -
2841 if (!NT_STATUS_IS_ERR(status
)) {
2842 status
= NT_STATUS_OK
;
2847 /* get lockout policy */
2848 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
2849 TALLOC_CTX
*mem_ctx
,
2850 struct samr_DomInfo12
*policy
)
2852 struct winbind_cache
*cache
= get_cache(domain
);
2853 struct cache_entry
*centry
= NULL
;
2857 old_status
= domain
->online
;
2861 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2867 policy
->lockout_duration
= centry_nttime(centry
);
2868 policy
->lockout_window
= centry_nttime(centry
);
2869 policy
->lockout_threshold
= centry_uint16(centry
);
2871 status
= centry
->status
;
2873 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2874 domain
->name
, nt_errstr(status
) ));
2876 centry_free(centry
);
2880 ZERO_STRUCTP(policy
);
2882 /* Return status value returned by seq number check */
2884 if (!NT_STATUS_IS_OK(domain
->last_status
))
2885 return domain
->last_status
;
2887 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2890 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2892 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2893 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2894 if (!domain
->internal
&& old_status
) {
2895 set_domain_offline(domain
);
2898 !domain
->internal
&&
2901 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2903 goto do_fetch_cache
;
2908 refresh_sequence_number(domain
, false);
2909 if (!NT_STATUS_IS_OK(status
)) {
2912 wcache_save_lockout_policy(domain
, status
, policy
);
2917 /* get password policy */
2918 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
2919 TALLOC_CTX
*mem_ctx
,
2920 struct samr_DomInfo1
*policy
)
2922 struct winbind_cache
*cache
= get_cache(domain
);
2923 struct cache_entry
*centry
= NULL
;
2927 old_status
= domain
->online
;
2931 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2937 policy
->min_password_length
= centry_uint16(centry
);
2938 policy
->password_history_length
= centry_uint16(centry
);
2939 policy
->password_properties
= centry_uint32(centry
);
2940 policy
->max_password_age
= centry_nttime(centry
);
2941 policy
->min_password_age
= centry_nttime(centry
);
2943 status
= centry
->status
;
2945 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2946 domain
->name
, nt_errstr(status
) ));
2948 centry_free(centry
);
2952 ZERO_STRUCTP(policy
);
2954 /* Return status value returned by seq number check */
2956 if (!NT_STATUS_IS_OK(domain
->last_status
))
2957 return domain
->last_status
;
2959 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2962 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
2964 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2965 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2966 if (!domain
->internal
&& old_status
) {
2967 set_domain_offline(domain
);
2970 !domain
->internal
&&
2973 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2975 goto do_fetch_cache
;
2980 refresh_sequence_number(domain
, false);
2981 if (!NT_STATUS_IS_OK(status
)) {
2984 wcache_save_password_policy(domain
, status
, policy
);
2990 /* Invalidate cached user and group lists coherently */
2992 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2995 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
2996 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
2997 tdb_delete(the_tdb
, kbuf
);
3002 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3004 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
3005 const struct dom_sid
*sid
)
3007 fstring key_str
, sid_string
;
3008 struct winbind_cache
*cache
;
3010 /* dont clear cached U/SID and UG/SID entries when we want to logon
3013 if (lp_winbind_offline_logon()) {
3020 cache
= get_cache(domain
);
3026 /* Clear U/SID cache entry */
3027 fstr_sprintf(key_str
, "U/%s", sid_to_fstring(sid_string
, sid
));
3028 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3029 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3031 /* Clear UG/SID cache entry */
3032 fstr_sprintf(key_str
, "UG/%s", sid_to_fstring(sid_string
, sid
));
3033 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3034 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3036 /* Samba/winbindd never needs this. */
3037 netsamlogon_clear_cached_user(sid
);
3040 bool wcache_invalidate_cache(void)
3042 struct winbindd_domain
*domain
;
3044 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3045 struct winbind_cache
*cache
= get_cache(domain
);
3047 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3048 "entries for %s\n", domain
->name
));
3051 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3060 bool wcache_invalidate_cache_noinit(void)
3062 struct winbindd_domain
*domain
;
3064 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3065 struct winbind_cache
*cache
;
3067 /* Skip uninitialized domains. */
3068 if (!domain
->initialized
&& !domain
->internal
) {
3072 cache
= get_cache(domain
);
3074 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3075 "entries for %s\n", domain
->name
));
3078 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3080 * Flushing cache has nothing to with domains.
3081 * return here if we successfully flushed once.
3082 * To avoid unnecessary traversing the cache.
3093 bool init_wcache(void)
3095 if (wcache
== NULL
) {
3096 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
3097 ZERO_STRUCTP(wcache
);
3100 if (wcache
->tdb
!= NULL
)
3103 /* when working offline we must not clear the cache on restart */
3104 wcache
->tdb
= tdb_open_log(cache_path("winbindd_cache.tdb"),
3105 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3106 TDB_INCOMPATIBLE_HASH
|
3107 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3108 O_RDWR
|O_CREAT
, 0600);
3110 if (wcache
->tdb
== NULL
) {
3111 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3118 /************************************************************************
3119 This is called by the parent to initialize the cache file.
3120 We don't need sophisticated locking here as we know we're the
3122 ************************************************************************/
3124 bool initialize_winbindd_cache(void)
3126 bool cache_bad
= true;
3129 if (!init_wcache()) {
3130 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3134 /* Check version number. */
3135 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
3136 vers
== WINBINDD_CACHE_VERSION
) {
3141 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3142 "and re-creating with version number %d\n",
3143 WINBINDD_CACHE_VERSION
));
3145 tdb_close(wcache
->tdb
);
3148 if (unlink(cache_path("winbindd_cache.tdb")) == -1) {
3149 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3150 cache_path("winbindd_cache.tdb"),
3154 if (!init_wcache()) {
3155 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3156 "init_wcache failed.\n"));
3160 /* Write the version. */
3161 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
3162 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3163 tdb_errorstr(wcache
->tdb
) ));
3168 tdb_close(wcache
->tdb
);
3173 void close_winbindd_cache(void)
3179 tdb_close(wcache
->tdb
);
3184 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*sid
,
3185 char **domain_name
, char **name
,
3186 enum lsa_SidType
*type
)
3188 struct winbindd_domain
*domain
;
3191 domain
= find_lookup_domain_from_sid(sid
);
3192 if (domain
== NULL
) {
3195 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
3197 return NT_STATUS_IS_OK(status
);
3200 bool lookup_cached_name(const char *domain_name
,
3202 struct dom_sid
*sid
,
3203 enum lsa_SidType
*type
)
3205 struct winbindd_domain
*domain
;
3207 bool original_online_state
;
3209 domain
= find_lookup_domain_from_name(domain_name
);
3210 if (domain
== NULL
) {
3214 /* If we are doing a cached logon, temporarily set the domain
3215 offline so the cache won't expire the entry */
3217 original_online_state
= domain
->online
;
3218 domain
->online
= false;
3219 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
3220 domain
->online
= original_online_state
;
3222 return NT_STATUS_IS_OK(status
);
3225 void cache_name2sid(struct winbindd_domain
*domain
,
3226 const char *domain_name
, const char *name
,
3227 enum lsa_SidType type
, const struct dom_sid
*sid
)
3229 refresh_sequence_number(domain
, false);
3230 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
3235 * The original idea that this cache only contains centries has
3236 * been blurred - now other stuff gets put in here. Ensure we
3237 * ignore these things on cleanup.
3240 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
3241 TDB_DATA dbuf
, void *state
)
3243 struct cache_entry
*centry
;
3245 if (is_non_centry_key(kbuf
)) {
3249 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
3254 if (!NT_STATUS_IS_OK(centry
->status
)) {
3255 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
3256 tdb_delete(the_tdb
, kbuf
);
3259 centry_free(centry
);
3263 /* flush the cache */
3264 void wcache_flush_cache(void)
3269 tdb_close(wcache
->tdb
);
3272 if (!winbindd_use_cache()) {
3276 /* when working offline we must not clear the cache on restart */
3277 wcache
->tdb
= tdb_open_log(cache_path("winbindd_cache.tdb"),
3278 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3279 TDB_INCOMPATIBLE_HASH
|
3280 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3281 O_RDWR
|O_CREAT
, 0600);
3284 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3288 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
3290 DEBUG(10,("wcache_flush_cache success\n"));
3293 /* Count cached creds */
3295 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3298 int *cred_count
= (int*)state
;
3300 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3306 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
3308 struct winbind_cache
*cache
= get_cache(domain
);
3313 return NT_STATUS_INTERNAL_DB_ERROR
;
3316 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
3318 return NT_STATUS_OK
;
3322 struct cred_list
*prev
, *next
;
3327 static struct cred_list
*wcache_cred_list
;
3329 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3332 struct cred_list
*cred
;
3334 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3336 cred
= SMB_MALLOC_P(struct cred_list
);
3338 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3344 /* save a copy of the key */
3346 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
3347 DLIST_ADD(wcache_cred_list
, cred
);
3353 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
3355 struct winbind_cache
*cache
= get_cache(domain
);
3358 struct cred_list
*cred
, *oldest
= NULL
;
3361 return NT_STATUS_INTERNAL_DB_ERROR
;
3364 /* we possibly already have an entry */
3365 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
3367 fstring key_str
, tmp
;
3369 DEBUG(11,("we already have an entry, deleting that\n"));
3371 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
3373 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3375 return NT_STATUS_OK
;
3378 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
3380 return NT_STATUS_OK
;
3381 } else if ((ret
== -1) || (wcache_cred_list
== NULL
)) {
3382 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3385 ZERO_STRUCTP(oldest
);
3387 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
3392 data
= tdb_fetch(cache
->tdb
, string_tdb_data(cred
->name
));
3394 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3396 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3400 t
= IVAL(data
.dptr
, 0);
3401 SAFE_FREE(data
.dptr
);
3404 oldest
= SMB_MALLOC_P(struct cred_list
);
3405 if (oldest
== NULL
) {
3406 status
= NT_STATUS_NO_MEMORY
;
3410 fstrcpy(oldest
->name
, cred
->name
);
3411 oldest
->created
= t
;
3415 if (t
< oldest
->created
) {
3416 fstrcpy(oldest
->name
, cred
->name
);
3417 oldest
->created
= t
;
3421 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3422 status
= NT_STATUS_OK
;
3424 status
= NT_STATUS_UNSUCCESSFUL
;
3427 SAFE_FREE(wcache_cred_list
);
3433 /* Change the global online/offline state. */
3434 bool set_global_winbindd_state_offline(void)
3438 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3440 /* Only go offline if someone has created
3441 the key "WINBINDD_OFFLINE" in the cache tdb. */
3443 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3444 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3448 if (!lp_winbind_offline_logon()) {
3449 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3453 if (global_winbindd_offline_state
) {
3454 /* Already offline. */
3458 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
3460 if (!data
.dptr
|| data
.dsize
!= 4) {
3461 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3462 SAFE_FREE(data
.dptr
);
3465 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3466 global_winbindd_offline_state
= true;
3467 SAFE_FREE(data
.dptr
);
3472 void set_global_winbindd_state_online(void)
3474 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3476 if (!lp_winbind_offline_logon()) {
3477 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3481 if (!global_winbindd_offline_state
) {
3482 /* Already online. */
3485 global_winbindd_offline_state
= false;
3491 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3492 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3495 bool get_global_winbindd_state_offline(void)
3497 return global_winbindd_offline_state
;
3500 /***********************************************************************
3501 Validate functions for all possible cache tdb keys.
3502 ***********************************************************************/
3504 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3505 struct tdb_validation_status
*state
)
3507 struct cache_entry
*centry
;
3509 centry
= SMB_XMALLOC_P(struct cache_entry
);
3510 centry
->data
= (unsigned char *)memdup(data
.dptr
, data
.dsize
);
3511 if (!centry
->data
) {
3515 centry
->len
= data
.dsize
;
3518 if (centry
->len
< 16) {
3519 /* huh? corrupt cache? */
3520 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3521 "(len < 16) ?\n", kstr
));
3522 centry_free(centry
);
3523 state
->bad_entry
= true;
3524 state
->success
= false;
3528 centry
->status
= NT_STATUS(centry_uint32(centry
));
3529 centry
->sequence_number
= centry_uint32(centry
);
3530 centry
->timeout
= centry_uint64_t(centry
);
3534 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3535 struct tdb_validation_status
*state
)
3537 if (dbuf
.dsize
!= 8) {
3538 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3539 keystr
, (unsigned int)dbuf
.dsize
));
3540 state
->bad_entry
= true;
3546 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3547 struct tdb_validation_status
*state
)
3549 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3554 (void)centry_uint32(centry
);
3555 if (NT_STATUS_IS_OK(centry
->status
)) {
3557 (void)centry_sid(centry
, &sid
);
3560 centry_free(centry
);
3562 if (!(state
->success
)) {
3565 DEBUG(10,("validate_ns: %s ok\n", keystr
));
3569 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3570 struct tdb_validation_status
*state
)
3572 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3577 if (NT_STATUS_IS_OK(centry
->status
)) {
3578 (void)centry_uint32(centry
);
3579 (void)centry_string(centry
, mem_ctx
);
3580 (void)centry_string(centry
, mem_ctx
);
3583 centry_free(centry
);
3585 if (!(state
->success
)) {
3588 DEBUG(10,("validate_sn: %s ok\n", keystr
));
3592 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3593 struct tdb_validation_status
*state
)
3595 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3602 (void)centry_string(centry
, mem_ctx
);
3603 (void)centry_string(centry
, mem_ctx
);
3604 (void)centry_string(centry
, mem_ctx
);
3605 (void)centry_string(centry
, mem_ctx
);
3606 (void)centry_uint32(centry
);
3607 (void)centry_sid(centry
, &sid
);
3608 (void)centry_sid(centry
, &sid
);
3610 centry_free(centry
);
3612 if (!(state
->success
)) {
3615 DEBUG(10,("validate_u: %s ok\n", keystr
));
3619 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3620 struct tdb_validation_status
*state
)
3622 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3628 (void)centry_nttime(centry
);
3629 (void)centry_nttime(centry
);
3630 (void)centry_uint16(centry
);
3632 centry_free(centry
);
3634 if (!(state
->success
)) {
3637 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3641 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3642 struct tdb_validation_status
*state
)
3644 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3650 (void)centry_uint16(centry
);
3651 (void)centry_uint16(centry
);
3652 (void)centry_uint32(centry
);
3653 (void)centry_nttime(centry
);
3654 (void)centry_nttime(centry
);
3656 centry_free(centry
);
3658 if (!(state
->success
)) {
3661 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3665 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3666 struct tdb_validation_status
*state
)
3668 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3674 (void)centry_time(centry
);
3675 (void)centry_hash16(centry
, mem_ctx
);
3677 /* We only have 17 bytes more data in the salted cred case. */
3678 if (centry
->len
- centry
->ofs
== 17) {
3679 (void)centry_hash16(centry
, mem_ctx
);
3682 centry_free(centry
);
3684 if (!(state
->success
)) {
3687 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3691 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3692 struct tdb_validation_status
*state
)
3694 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3695 int32 num_entries
, i
;
3701 num_entries
= (int32
)centry_uint32(centry
);
3703 for (i
=0; i
< num_entries
; i
++) {
3705 (void)centry_string(centry
, mem_ctx
);
3706 (void)centry_string(centry
, mem_ctx
);
3707 (void)centry_string(centry
, mem_ctx
);
3708 (void)centry_string(centry
, mem_ctx
);
3709 (void)centry_sid(centry
, &sid
);
3710 (void)centry_sid(centry
, &sid
);
3713 centry_free(centry
);
3715 if (!(state
->success
)) {
3718 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3722 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3723 struct tdb_validation_status
*state
)
3725 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3726 int32 num_entries
, i
;
3732 num_entries
= centry_uint32(centry
);
3734 for (i
=0; i
< num_entries
; i
++) {
3735 (void)centry_string(centry
, mem_ctx
);
3736 (void)centry_string(centry
, mem_ctx
);
3737 (void)centry_uint32(centry
);
3740 centry_free(centry
);
3742 if (!(state
->success
)) {
3745 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3749 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3750 struct tdb_validation_status
*state
)
3752 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3753 int32 num_groups
, i
;
3759 num_groups
= centry_uint32(centry
);
3761 for (i
=0; i
< num_groups
; i
++) {
3763 centry_sid(centry
, &sid
);
3766 centry_free(centry
);
3768 if (!(state
->success
)) {
3771 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3775 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3776 struct tdb_validation_status
*state
)
3778 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3779 int32 num_aliases
, i
;
3785 num_aliases
= centry_uint32(centry
);
3787 for (i
=0; i
< num_aliases
; i
++) {
3788 (void)centry_uint32(centry
);
3791 centry_free(centry
);
3793 if (!(state
->success
)) {
3796 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3800 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3801 struct tdb_validation_status
*state
)
3803 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3810 num_names
= centry_uint32(centry
);
3812 for (i
=0; i
< num_names
; i
++) {
3814 centry_sid(centry
, &sid
);
3815 (void)centry_string(centry
, mem_ctx
);
3816 (void)centry_uint32(centry
);
3819 centry_free(centry
);
3821 if (!(state
->success
)) {
3824 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3828 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3829 struct tdb_validation_status
*state
)
3831 /* Can't say anything about this other than must be nonzero. */
3832 if (dbuf
.dsize
== 0) {
3833 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3835 state
->bad_entry
= true;
3836 state
->success
= false;
3840 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3844 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3845 struct tdb_validation_status
*state
)
3847 /* Can't say anything about this other than must be nonzero. */
3848 if (dbuf
.dsize
== 0) {
3849 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3851 state
->bad_entry
= true;
3852 state
->success
= false;
3856 DEBUG(10,("validate_de: %s ok\n", keystr
));
3860 static int validate_pwinfo(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3861 TDB_DATA dbuf
, struct tdb_validation_status
*state
)
3863 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3869 (void)centry_string(centry
, mem_ctx
);
3870 (void)centry_string(centry
, mem_ctx
);
3871 (void)centry_string(centry
, mem_ctx
);
3872 (void)centry_uint32(centry
);
3874 centry_free(centry
);
3876 if (!(state
->success
)) {
3879 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3883 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3885 struct tdb_validation_status
*state
)
3887 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3893 (void)centry_string( centry
, mem_ctx
);
3895 centry_free(centry
);
3897 if (!(state
->success
)) {
3900 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3904 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3906 struct tdb_validation_status
*state
)
3908 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3914 (void)centry_string( centry
, mem_ctx
);
3916 centry_free(centry
);
3918 if (!(state
->success
)) {
3921 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3925 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3927 struct tdb_validation_status
*state
)
3929 if (dbuf
.dsize
== 0) {
3930 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3931 "key %s (len ==0) ?\n", keystr
));
3932 state
->bad_entry
= true;
3933 state
->success
= false;
3937 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3938 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3942 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3943 struct tdb_validation_status
*state
)
3945 if (dbuf
.dsize
!= 4) {
3946 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3947 keystr
, (unsigned int)dbuf
.dsize
));
3948 state
->bad_entry
= true;
3949 state
->success
= false;
3952 DEBUG(10,("validate_offline: %s ok\n", keystr
));
3956 static int validate_ndr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3957 struct tdb_validation_status
*state
)
3960 * Ignore validation for now. The proper way to do this is with a
3961 * checksum. Just pure parsing does not really catch much.
3966 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3967 struct tdb_validation_status
*state
)
3969 if (dbuf
.dsize
!= 4) {
3970 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3971 "key %s (len %u != 4) ?\n",
3972 keystr
, (unsigned int)dbuf
.dsize
));
3973 state
->bad_entry
= true;
3974 state
->success
= false;
3978 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
3982 /***********************************************************************
3983 A list of all possible cache tdb keys with associated validation
3985 ***********************************************************************/
3987 struct key_val_struct
{
3988 const char *keyname
;
3989 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
3991 {"SEQNUM/", validate_seqnum
},
3992 {"NS/", validate_ns
},
3993 {"SN/", validate_sn
},
3995 {"LOC_POL/", validate_loc_pol
},
3996 {"PWD_POL/", validate_pwd_pol
},
3997 {"CRED/", validate_cred
},
3998 {"UL/", validate_ul
},
3999 {"GL/", validate_gl
},
4000 {"UG/", validate_ug
},
4001 {"UA", validate_ua
},
4002 {"GM/", validate_gm
},
4003 {"DR/", validate_dr
},
4004 {"DE/", validate_de
},
4005 {"NSS/PWINFO/", validate_pwinfo
},
4006 {"TRUSTDOMCACHE/", validate_trustdomcache
},
4007 {"NSS/NA/", validate_nss_na
},
4008 {"NSS/AN/", validate_nss_an
},
4009 {"WINBINDD_OFFLINE", validate_offline
},
4010 {"NDR/", validate_ndr
},
4011 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
4015 /***********************************************************************
4016 Function to look at every entry in the tdb and validate it as far as
4018 ***********************************************************************/
4020 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
4023 unsigned int max_key_len
= 1024;
4024 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
4026 /* Paranoia check. */
4027 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0) {
4028 max_key_len
= 1024 * 1024;
4030 if (kbuf
.dsize
> max_key_len
) {
4031 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4033 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
4037 for (i
= 0; key_val
[i
].keyname
; i
++) {
4038 size_t namelen
= strlen(key_val
[i
].keyname
);
4039 if (kbuf
.dsize
>= namelen
&& (
4040 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
4041 TALLOC_CTX
*mem_ctx
;
4045 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
4049 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
4050 keystr
[kbuf
.dsize
] = '\0';
4052 mem_ctx
= talloc_init("validate_ctx");
4058 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
4062 talloc_destroy(mem_ctx
);
4067 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4068 dump_data(0, (uint8
*)kbuf
.dptr
, kbuf
.dsize
);
4069 DEBUG(0,("data :\n"));
4070 dump_data(0, (uint8
*)dbuf
.dptr
, dbuf
.dsize
);
4071 v_state
->unknown_key
= true;
4072 v_state
->success
= false;
4073 return 1; /* terminate. */
4076 static void validate_panic(const char *const why
)
4078 DEBUG(0,("validating cache: would panic %s\n", why
));
4079 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4083 /***********************************************************************
4084 Try and validate every entry in the winbindd cache. If we fail here,
4085 delete the cache tdb and return non-zero.
4086 ***********************************************************************/
4088 int winbindd_validate_cache(void)
4091 const char *tdb_path
= cache_path("winbindd_cache.tdb");
4092 TDB_CONTEXT
*tdb
= NULL
;
4094 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4095 smb_panic_fn
= validate_panic
;
4098 tdb
= tdb_open_log(tdb_path
,
4099 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
4100 TDB_INCOMPATIBLE_HASH
|
4101 ( lp_winbind_offline_logon()
4103 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
4107 DEBUG(0, ("winbindd_validate_cache: "
4108 "error opening/initializing tdb\n"));
4113 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
4116 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4117 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
4122 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4123 smb_panic_fn
= smb_panic
;
4127 /***********************************************************************
4128 Try and validate every entry in the winbindd cache.
4129 ***********************************************************************/
4131 int winbindd_validate_cache_nobackup(void)
4134 const char *tdb_path
= cache_path("winbindd_cache.tdb");
4136 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4137 smb_panic_fn
= validate_panic
;
4140 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
4141 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
4143 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
4147 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4151 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4153 smb_panic_fn
= smb_panic
;
4157 bool winbindd_cache_validate_and_initialize(void)
4159 close_winbindd_cache();
4161 if (lp_winbind_offline_logon()) {
4162 if (winbindd_validate_cache() < 0) {
4163 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4164 "could be restored.\n"));
4168 return initialize_winbindd_cache();
4171 /*********************************************************************
4172 ********************************************************************/
4174 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
4175 struct winbindd_tdc_domain
**domains
,
4176 size_t *num_domains
)
4178 struct winbindd_tdc_domain
*list
= NULL
;
4181 bool set_only
= false;
4183 /* don't allow duplicates */
4188 for ( i
=0; i
< (*num_domains
); i
++ ) {
4189 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
4190 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4201 list
= TALLOC_ARRAY( NULL
, struct winbindd_tdc_domain
, 1 );
4204 list
= TALLOC_REALLOC_ARRAY( *domains
, *domains
,
4205 struct winbindd_tdc_domain
,
4210 ZERO_STRUCT( list
[idx
] );
4216 list
[idx
].domain_name
= talloc_strdup( list
, new_dom
->name
);
4217 list
[idx
].dns_name
= talloc_strdup( list
, new_dom
->alt_name
);
4219 if ( !is_null_sid( &new_dom
->sid
) ) {
4220 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
4222 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
4225 if ( new_dom
->domain_flags
!= 0x0 )
4226 list
[idx
].trust_flags
= new_dom
->domain_flags
;
4228 if ( new_dom
->domain_type
!= 0x0 )
4229 list
[idx
].trust_type
= new_dom
->domain_type
;
4231 if ( new_dom
->domain_trust_attribs
!= 0x0 )
4232 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
4236 *num_domains
= idx
+ 1;
4242 /*********************************************************************
4243 ********************************************************************/
4245 static TDB_DATA
make_tdc_key( const char *domain_name
)
4247 char *keystr
= NULL
;
4248 TDB_DATA key
= { NULL
, 0 };
4250 if ( !domain_name
) {
4251 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4255 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
4258 key
= string_term_tdb_data(keystr
);
4263 /*********************************************************************
4264 ********************************************************************/
4266 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
4268 unsigned char **buf
)
4270 unsigned char *buffer
= NULL
;
4275 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4283 /* Store the number of array items first */
4284 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
4287 /* now pack each domain trust record */
4288 for ( i
=0; i
<num_domains
; i
++ ) {
4293 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4294 domains
[i
].domain_name
,
4295 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
4298 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
4299 domains
[i
].domain_name
,
4300 domains
[i
].dns_name
,
4301 sid_to_fstring(tmp
, &domains
[i
].sid
),
4302 domains
[i
].trust_flags
,
4303 domains
[i
].trust_attribs
,
4304 domains
[i
].trust_type
);
4307 if ( buflen
< len
) {
4309 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
4310 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4324 /*********************************************************************
4325 ********************************************************************/
4327 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
4328 struct winbindd_tdc_domain
**domains
)
4330 fstring domain_name
, dns_name
, sid_string
;
4331 uint32 type
, attribs
, flags
;
4335 struct winbindd_tdc_domain
*list
= NULL
;
4337 /* get the number of domains */
4338 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
4340 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4344 list
= TALLOC_ARRAY( NULL
, struct winbindd_tdc_domain
, num_domains
);
4346 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4350 for ( i
=0; i
<num_domains
; i
++ ) {
4351 len
+= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
4360 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4361 TALLOC_FREE( list
);
4365 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4366 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4367 domain_name
, dns_name
, sid_string
,
4368 flags
, attribs
, type
));
4370 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
4371 list
[i
].dns_name
= talloc_strdup( list
, dns_name
);
4372 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
4373 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4376 list
[i
].trust_flags
= flags
;
4377 list
[i
].trust_attribs
= attribs
;
4378 list
[i
].trust_type
= type
;
4386 /*********************************************************************
4387 ********************************************************************/
4389 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
4391 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4392 TDB_DATA data
= { NULL
, 0 };
4398 /* See if we were asked to delete the cache entry */
4401 ret
= tdb_delete( wcache
->tdb
, key
);
4405 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4412 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4415 SAFE_FREE( data
.dptr
);
4416 SAFE_FREE( key
.dptr
);
4418 return ( ret
!= -1 );
4421 /*********************************************************************
4422 ********************************************************************/
4424 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4426 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4427 TDB_DATA data
= { NULL
, 0 };
4435 data
= tdb_fetch( wcache
->tdb
, key
);
4437 SAFE_FREE( key
.dptr
);
4442 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4444 SAFE_FREE( data
.dptr
);
4452 /*********************************************************************
4453 ********************************************************************/
4455 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4457 struct winbindd_tdc_domain
*dom_list
= NULL
;
4458 size_t num_domains
= 0;
4461 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4462 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4463 domain
->name
, domain
->alt_name
,
4464 sid_string_dbg(&domain
->sid
),
4465 domain
->domain_flags
,
4466 domain
->domain_trust_attribs
,
4467 domain
->domain_type
));
4469 if ( !init_wcache() ) {
4473 /* fetch the list */
4475 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4477 /* add the new domain */
4479 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4483 /* pack the domain */
4485 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4493 TALLOC_FREE( dom_list
);
4498 /*********************************************************************
4499 ********************************************************************/
4501 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4503 struct winbindd_tdc_domain
*dom_list
= NULL
;
4504 size_t num_domains
= 0;
4506 struct winbindd_tdc_domain
*d
= NULL
;
4508 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4510 if ( !init_wcache() ) {
4514 /* fetch the list */
4516 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4518 for ( i
=0; i
<num_domains
; i
++ ) {
4519 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4520 strequal(name
, dom_list
[i
].dns_name
) )
4522 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4525 d
= TALLOC_P( ctx
, struct winbindd_tdc_domain
);
4529 d
->domain_name
= talloc_strdup( d
, dom_list
[i
].domain_name
);
4530 d
->dns_name
= talloc_strdup( d
, dom_list
[i
].dns_name
);
4531 sid_copy( &d
->sid
, &dom_list
[i
].sid
);
4532 d
->trust_flags
= dom_list
[i
].trust_flags
;
4533 d
->trust_type
= dom_list
[i
].trust_type
;
4534 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
4540 TALLOC_FREE( dom_list
);
4545 /*********************************************************************
4546 ********************************************************************/
4548 struct winbindd_tdc_domain
*
4549 wcache_tdc_fetch_domainbysid(TALLOC_CTX
*ctx
,
4550 const struct dom_sid
*sid
)
4552 struct winbindd_tdc_domain
*dom_list
= NULL
;
4553 size_t num_domains
= 0;
4555 struct winbindd_tdc_domain
*d
= NULL
;
4557 DEBUG(10,("wcache_tdc_fetch_domainbysid: Searching for domain %s\n",
4558 sid_string_dbg(sid
)));
4560 if (!init_wcache()) {
4564 /* fetch the list */
4566 wcache_tdc_fetch_list(&dom_list
, &num_domains
);
4568 for (i
= 0; i
<num_domains
; i
++) {
4569 if (sid_equal(sid
, &(dom_list
[i
].sid
))) {
4570 DEBUG(10, ("wcache_tdc_fetch_domainbysid: "
4571 "Found domain %s for SID %s\n",
4572 dom_list
[i
].domain_name
,
4573 sid_string_dbg(sid
)));
4575 d
= TALLOC_P(ctx
, struct winbindd_tdc_domain
);
4579 d
->domain_name
= talloc_strdup(d
,
4580 dom_list
[i
].domain_name
);
4582 d
->dns_name
= talloc_strdup(d
, dom_list
[i
].dns_name
);
4583 sid_copy(&d
->sid
, &dom_list
[i
].sid
);
4584 d
->trust_flags
= dom_list
[i
].trust_flags
;
4585 d
->trust_type
= dom_list
[i
].trust_type
;
4586 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
4592 TALLOC_FREE(dom_list
);
4598 /*********************************************************************
4599 ********************************************************************/
4601 void wcache_tdc_clear( void )
4603 if ( !init_wcache() )
4606 wcache_tdc_store_list( NULL
, 0 );
4612 /*********************************************************************
4613 ********************************************************************/
4615 static void wcache_save_user_pwinfo(struct winbindd_domain
*domain
,
4617 const struct dom_sid
*user_sid
,
4618 const char *homedir
,
4623 struct cache_entry
*centry
;
4626 if ( (centry
= centry_start(domain
, status
)) == NULL
)
4629 centry_put_string( centry
, homedir
);
4630 centry_put_string( centry
, shell
);
4631 centry_put_string( centry
, gecos
);
4632 centry_put_uint32( centry
, gid
);
4634 centry_end(centry
, "NSS/PWINFO/%s", sid_to_fstring(tmp
, user_sid
) );
4636 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid
) ));
4638 centry_free(centry
);
4643 NTSTATUS
nss_get_info_cached( struct winbindd_domain
*domain
,
4644 const struct dom_sid
*user_sid
,
4646 const char **homedir
, const char **shell
,
4647 const char **gecos
, gid_t
*p_gid
)
4649 struct winbind_cache
*cache
= get_cache(domain
);
4650 struct cache_entry
*centry
= NULL
;
4657 centry
= wcache_fetch(cache
, domain
, "NSS/PWINFO/%s",
4658 sid_to_fstring(tmp
, user_sid
));
4663 *homedir
= centry_string( centry
, ctx
);
4664 *shell
= centry_string( centry
, ctx
);
4665 *gecos
= centry_string( centry
, ctx
);
4666 *p_gid
= centry_uint32( centry
);
4668 centry_free(centry
);
4670 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4671 sid_string_dbg(user_sid
)));
4673 return NT_STATUS_OK
;
4677 nt_status
= nss_get_info( domain
->name
, user_sid
, ctx
,
4678 homedir
, shell
, gecos
, p_gid
);
4680 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status
)));
4682 if ( NT_STATUS_IS_OK(nt_status
) ) {
4683 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir
));
4684 DEBUGADD(10, ("\tshell = '%s'\n", *shell
));
4685 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos
));
4686 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid
));
4688 wcache_save_user_pwinfo( domain
, nt_status
, user_sid
,
4689 *homedir
, *shell
, *gecos
, *p_gid
);
4692 if ( NT_STATUS_EQUAL( nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
4693 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4695 set_domain_offline( domain
);
4703 /* the cache backend methods are exposed via this structure */
4704 struct winbindd_methods cache_methods
= {
4722 static bool wcache_ndr_key(TALLOC_CTX
*mem_ctx
, char *domain_name
,
4723 uint32_t opnum
, const DATA_BLOB
*req
,
4729 key
= talloc_asprintf(mem_ctx
, "NDR/%s/%d/", domain_name
, (int)opnum
);
4733 keylen
= talloc_get_size(key
) - 1;
4735 key
= talloc_realloc(mem_ctx
, key
, char, keylen
+ req
->length
);
4739 memcpy(key
+ keylen
, req
->data
, req
->length
);
4741 pkey
->dptr
= (uint8_t *)key
;
4742 pkey
->dsize
= talloc_get_size(key
);
4746 static bool wcache_opnum_cacheable(uint32_t opnum
)
4749 case NDR_WBINT_PING
:
4750 case NDR_WBINT_QUERYSEQUENCENUMBER
:
4751 case NDR_WBINT_ALLOCATEUID
:
4752 case NDR_WBINT_ALLOCATEGID
:
4753 case NDR_WBINT_CHECKMACHINEACCOUNT
:
4754 case NDR_WBINT_CHANGEMACHINEACCOUNT
:
4755 case NDR_WBINT_PINGDC
:
4761 bool wcache_fetch_ndr(TALLOC_CTX
*mem_ctx
, struct winbindd_domain
*domain
,
4762 uint32_t opnum
, const DATA_BLOB
*req
, DATA_BLOB
*resp
)
4767 if (!wcache_opnum_cacheable(opnum
) ||
4768 is_my_own_sam_domain(domain
) ||
4769 is_builtin_domain(domain
)) {
4773 if (wcache
->tdb
== NULL
) {
4777 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4780 data
= tdb_fetch(wcache
->tdb
, key
);
4781 TALLOC_FREE(key
.dptr
);
4783 if (data
.dptr
== NULL
) {
4786 if (data
.dsize
< 12) {
4790 if (!is_domain_offline(domain
)) {
4791 uint32_t entry_seqnum
, dom_seqnum
, last_check
;
4792 uint64_t entry_timeout
;
4794 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
,
4798 entry_seqnum
= IVAL(data
.dptr
, 0);
4799 if (entry_seqnum
!= dom_seqnum
) {
4800 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4801 (int)entry_seqnum
));
4804 entry_timeout
= BVAL(data
.dptr
, 4);
4805 if (entry_timeout
> time(NULL
)) {
4806 DEBUG(10, ("Entry has timed out\n"));
4811 resp
->data
= (uint8_t *)talloc_memdup(mem_ctx
, data
.dptr
+ 12,
4813 if (resp
->data
== NULL
) {
4814 DEBUG(10, ("talloc failed\n"));
4817 resp
->length
= data
.dsize
- 12;
4821 SAFE_FREE(data
.dptr
);
4825 void wcache_store_ndr(struct winbindd_domain
*domain
, uint32_t opnum
,
4826 const DATA_BLOB
*req
, const DATA_BLOB
*resp
)
4829 uint32_t dom_seqnum
, last_check
;
4832 if (!wcache_opnum_cacheable(opnum
) ||
4833 is_my_own_sam_domain(domain
) ||
4834 is_builtin_domain(domain
)) {
4838 if (wcache
->tdb
== NULL
) {
4842 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
, &last_check
)) {
4843 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4848 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4852 timeout
= time(NULL
) + lp_winbind_cache_time();
4854 data
.dsize
= resp
->length
+ 12;
4855 data
.dptr
= talloc_array(key
.dptr
, uint8_t, data
.dsize
);
4856 if (data
.dptr
== NULL
) {
4860 SIVAL(data
.dptr
, 0, dom_seqnum
);
4861 SBVAL(data
.dptr
, 4, timeout
);
4862 memcpy(data
.dptr
+ 12, resp
->data
, resp
->length
);
4864 tdb_store(wcache
->tdb
, key
, data
, 0);
4867 TALLOC_FREE(key
.dptr
);