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"
39 #define DBGC_CLASS DBGC_WINBIND
41 #define WINBINDD_CACHE_VERSION 2
42 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
44 extern struct winbindd_methods reconnect_methods
;
46 extern struct winbindd_methods ads_methods
;
48 extern struct winbindd_methods builtin_passdb_methods
;
49 extern struct winbindd_methods sam_passdb_methods
;
52 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
53 * Here are the list of entry types that are *not* stored
54 * as form struct cache_entry in the cache.
57 static const char *non_centry_keys
[] = {
60 WINBINDD_CACHE_VERSION_KEYSTR
,
64 /************************************************************************
65 Is this key a non-centry type ?
66 ************************************************************************/
68 static bool is_non_centry_key(TDB_DATA kbuf
)
72 if (kbuf
.dptr
== NULL
|| kbuf
.dsize
== 0) {
75 for (i
= 0; non_centry_keys
[i
] != NULL
; i
++) {
76 size_t namelen
= strlen(non_centry_keys
[i
]);
77 if (kbuf
.dsize
< namelen
) {
80 if (strncmp(non_centry_keys
[i
], (const char *)kbuf
.dptr
, namelen
) == 0) {
87 /* Global online/offline state - False when online. winbindd starts up online
88 and sets this to true if the first query fails and there's an entry in
89 the cache tdb telling us to stay offline. */
91 static bool global_winbindd_offline_state
;
93 struct winbind_cache
{
99 uint32 sequence_number
;
105 void (*smb_panic_fn
)(const char *const why
) = smb_panic
;
107 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
109 static struct winbind_cache
*wcache
;
111 /* get the winbind_cache structure */
112 static struct winbind_cache
*get_cache(struct winbindd_domain
*domain
)
114 struct winbind_cache
*ret
= wcache
;
116 /* We have to know what type of domain we are dealing with first. */
118 if (domain
->internal
) {
119 domain
->backend
= &builtin_passdb_methods
;
120 domain
->initialized
= True
;
123 if (strequal(domain
->name
, get_global_sam_name()) &&
124 sid_check_is_domain(&domain
->sid
)) {
125 domain
->backend
= &sam_passdb_methods
;
126 domain
->initialized
= True
;
129 if ( !domain
->initialized
) {
130 init_dc_connection( domain
);
134 OK. listen up becasue I'm only going to say this once.
135 We have the following scenarios to consider
136 (a) trusted AD domains on a Samba DC,
137 (b) trusted AD domains and we are joined to a non-kerberos domain
138 (c) trusted AD domains and we are joined to a kerberos (AD) domain
140 For (a) we can always contact the trusted domain using krb5
141 since we have the domain trust account password
143 For (b) we can only use RPC since we have no way of
144 getting a krb5 ticket in our own domain
146 For (c) we can always use krb5 since we have a kerberos trust
151 if (!domain
->backend
) {
153 struct winbindd_domain
*our_domain
= domain
;
155 /* find our domain first so we can figure out if we
156 are joined to a kerberized domain */
158 if ( !domain
->primary
)
159 our_domain
= find_our_domain();
161 if ((our_domain
->active_directory
|| IS_DC
)
162 && domain
->active_directory
163 && !lp_winbind_rpc_only()) {
164 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain
->name
));
165 domain
->backend
= &ads_methods
;
167 #endif /* HAVE_ADS */
168 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain
->name
));
169 domain
->backend
= &reconnect_methods
;
172 #endif /* HAVE_ADS */
178 ret
= SMB_XMALLOC_P(struct winbind_cache
);
182 wcache_flush_cache();
188 free a centry structure
190 static void centry_free(struct cache_entry
*centry
)
194 SAFE_FREE(centry
->data
);
198 static bool centry_check_bytes(struct cache_entry
*centry
, size_t nbytes
)
200 if (centry
->len
- centry
->ofs
< nbytes
) {
201 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
202 (unsigned int)nbytes
,
203 centry
->len
- centry
->ofs
));
210 pull a uint64_t from a cache entry
212 static uint64_t centry_uint64_t(struct cache_entry
*centry
)
216 if (!centry_check_bytes(centry
, 8)) {
217 smb_panic_fn("centry_uint64_t");
219 ret
= BVAL(centry
->data
, centry
->ofs
);
225 pull a uint32 from a cache entry
227 static uint32
centry_uint32(struct cache_entry
*centry
)
231 if (!centry_check_bytes(centry
, 4)) {
232 smb_panic_fn("centry_uint32");
234 ret
= IVAL(centry
->data
, centry
->ofs
);
240 pull a uint16 from a cache entry
242 static uint16
centry_uint16(struct cache_entry
*centry
)
245 if (!centry_check_bytes(centry
, 2)) {
246 smb_panic_fn("centry_uint16");
248 ret
= SVAL(centry
->data
, centry
->ofs
);
254 pull a uint8 from a cache entry
256 static uint8
centry_uint8(struct cache_entry
*centry
)
259 if (!centry_check_bytes(centry
, 1)) {
260 smb_panic_fn("centry_uint8");
262 ret
= CVAL(centry
->data
, centry
->ofs
);
268 pull a NTTIME from a cache entry
270 static NTTIME
centry_nttime(struct cache_entry
*centry
)
273 if (!centry_check_bytes(centry
, 8)) {
274 smb_panic_fn("centry_nttime");
276 ret
= IVAL(centry
->data
, centry
->ofs
);
278 ret
+= (uint64
)IVAL(centry
->data
, centry
->ofs
) << 32;
284 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
286 static time_t centry_time(struct cache_entry
*centry
)
288 return (time_t)centry_nttime(centry
);
291 /* pull a string from a cache entry, using the supplied
294 static char *centry_string(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
299 len
= centry_uint8(centry
);
302 /* a deliberate NULL string */
306 if (!centry_check_bytes(centry
, (size_t)len
)) {
307 smb_panic_fn("centry_string");
310 ret
= talloc_array(mem_ctx
, char, len
+1);
312 smb_panic_fn("centry_string out of memory\n");
314 memcpy(ret
,centry
->data
+ centry
->ofs
, len
);
320 /* pull a hash16 from a cache entry, using the supplied
323 static char *centry_hash16(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
328 len
= centry_uint8(centry
);
331 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
336 if (!centry_check_bytes(centry
, 16)) {
340 ret
= talloc_array(mem_ctx
, char, 16);
342 smb_panic_fn("centry_hash out of memory\n");
344 memcpy(ret
,centry
->data
+ centry
->ofs
, 16);
349 /* pull a sid from a cache entry, using the supplied
352 static bool centry_sid(struct cache_entry
*centry
, struct dom_sid
*sid
)
357 sid_string
= centry_string(centry
, talloc_tos());
358 if (sid_string
== NULL
) {
361 ret
= string_to_sid(sid
, sid_string
);
362 TALLOC_FREE(sid_string
);
368 pull a NTSTATUS from a cache entry
370 static NTSTATUS
centry_ntstatus(struct cache_entry
*centry
)
374 status
= NT_STATUS(centry_uint32(centry
));
379 /* the server is considered down if it can't give us a sequence number */
380 static bool wcache_server_down(struct winbindd_domain
*domain
)
387 ret
= (domain
->sequence_number
== DOM_SEQUENCE_NONE
);
390 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
395 static bool wcache_fetch_seqnum(const char *domain_name
, uint32_t *seqnum
,
396 uint32_t *last_seq_check
)
401 if (wcache
->tdb
== NULL
) {
402 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
406 key
= talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name
);
408 DEBUG(10, ("talloc failed\n"));
412 data
= tdb_fetch_bystring(wcache
->tdb
, key
);
415 if (data
.dptr
== NULL
) {
416 DEBUG(10, ("wcache_fetch_seqnum: %s not found\n",
420 if (data
.dsize
!= 8) {
421 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
423 SAFE_FREE(data
.dptr
);
427 *seqnum
= IVAL(data
.dptr
, 0);
428 *last_seq_check
= IVAL(data
.dptr
, 4);
429 SAFE_FREE(data
.dptr
);
434 static NTSTATUS
fetch_cache_seqnum( struct winbindd_domain
*domain
, time_t now
)
436 uint32 last_check
, time_diff
;
438 if (!wcache_fetch_seqnum(domain
->name
, &domain
->sequence_number
,
440 return NT_STATUS_UNSUCCESSFUL
;
442 domain
->last_seq_check
= last_check
;
444 /* have we expired? */
446 time_diff
= now
- domain
->last_seq_check
;
447 if ( time_diff
> lp_winbind_cache_time() ) {
448 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
449 domain
->name
, domain
->sequence_number
,
450 (uint32
)domain
->last_seq_check
));
451 return NT_STATUS_UNSUCCESSFUL
;
454 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
455 domain
->name
, domain
->sequence_number
,
456 (uint32
)domain
->last_seq_check
));
461 bool wcache_store_seqnum(const char *domain_name
, uint32_t seqnum
,
462 time_t last_seq_check
)
468 if (wcache
->tdb
== NULL
) {
469 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
473 key_str
= talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name
);
474 if (key_str
== NULL
) {
475 DEBUG(10, ("talloc_asprintf failed\n"));
479 SIVAL(buf
, 0, seqnum
);
480 SIVAL(buf
, 4, last_seq_check
);
482 ret
= tdb_store_bystring(wcache
->tdb
, key_str
,
483 make_tdb_data(buf
, sizeof(buf
)), TDB_REPLACE
);
484 TALLOC_FREE(key_str
);
486 DEBUG(10, ("tdb_store_bystring failed: %s\n",
487 tdb_errorstr_compat(wcache
->tdb
)));
488 TALLOC_FREE(key_str
);
492 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
493 domain_name
, seqnum
, (unsigned)last_seq_check
));
498 static bool store_cache_seqnum( struct winbindd_domain
*domain
)
500 return wcache_store_seqnum(domain
->name
, domain
->sequence_number
,
501 domain
->last_seq_check
);
505 refresh the domain sequence number. If force is true
506 then always refresh it, no matter how recently we fetched it
509 static void refresh_sequence_number(struct winbindd_domain
*domain
, bool force
)
513 time_t t
= time(NULL
);
514 unsigned cache_time
= lp_winbind_cache_time();
516 if (is_domain_offline(domain
)) {
522 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
523 /* trying to reconnect is expensive, don't do it too often */
524 if (domain
->sequence_number
== DOM_SEQUENCE_NONE
) {
529 time_diff
= t
- domain
->last_seq_check
;
531 /* see if we have to refetch the domain sequence number */
532 if (!force
&& (time_diff
< cache_time
) &&
533 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
534 NT_STATUS_IS_OK(domain
->last_status
)) {
535 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain
->name
));
539 /* try to get the sequence number from the tdb cache first */
540 /* this will update the timestamp as well */
542 status
= fetch_cache_seqnum( domain
, t
);
543 if (NT_STATUS_IS_OK(status
) &&
544 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
545 NT_STATUS_IS_OK(domain
->last_status
)) {
549 /* important! make sure that we know if this is a native
550 mode domain or not. And that we can contact it. */
552 if ( winbindd_can_contact_domain( domain
) ) {
553 status
= domain
->backend
->sequence_number(domain
,
554 &domain
->sequence_number
);
556 /* just use the current time */
557 status
= NT_STATUS_OK
;
558 domain
->sequence_number
= time(NULL
);
562 /* the above call could have set our domain->backend to NULL when
563 * coming from offline to online mode, make sure to reinitialize the
564 * backend - Guenther */
567 if (!NT_STATUS_IS_OK(status
)) {
568 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status
)));
569 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
572 domain
->last_status
= status
;
573 domain
->last_seq_check
= time(NULL
);
575 /* save the new sequence number in the cache */
576 store_cache_seqnum( domain
);
579 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
580 domain
->name
, domain
->sequence_number
));
586 decide if a cache entry has expired
588 static bool centry_expired(struct winbindd_domain
*domain
, const char *keystr
, struct cache_entry
*centry
)
590 /* If we've been told to be offline - stay in that state... */
591 if (lp_winbind_offline_logon() && global_winbindd_offline_state
) {
592 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
593 keystr
, domain
->name
));
597 /* when the domain is offline return the cached entry.
598 * This deals with transient offline states... */
600 if (!domain
->online
) {
601 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
602 keystr
, domain
->name
));
606 /* if the server is OK and our cache entry came from when it was down then
607 the entry is invalid */
608 if ((domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
609 (centry
->sequence_number
== DOM_SEQUENCE_NONE
)) {
610 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
611 keystr
, domain
->name
));
615 /* if the server is down or the cache entry is not older than the
616 current sequence number or it did not timeout then it is OK */
617 if (wcache_server_down(domain
)
618 || ((centry
->sequence_number
== domain
->sequence_number
)
619 && (centry
->timeout
> time(NULL
)))) {
620 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
621 keystr
, domain
->name
));
625 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
626 keystr
, domain
->name
));
632 static struct cache_entry
*wcache_fetch_raw(char *kstr
)
635 struct cache_entry
*centry
;
638 key
= string_tdb_data(kstr
);
639 data
= tdb_fetch_compat(wcache
->tdb
, key
);
645 centry
= SMB_XMALLOC_P(struct cache_entry
);
646 centry
->data
= (unsigned char *)data
.dptr
;
647 centry
->len
= data
.dsize
;
650 if (centry
->len
< 16) {
651 /* huh? corrupt cache? */
652 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s "
653 "(len < 16)?\n", kstr
));
658 centry
->status
= centry_ntstatus(centry
);
659 centry
->sequence_number
= centry_uint32(centry
);
660 centry
->timeout
= centry_uint64_t(centry
);
665 static bool is_my_own_sam_domain(struct winbindd_domain
*domain
)
667 if (strequal(domain
->name
, get_global_sam_name()) &&
668 sid_check_is_domain(&domain
->sid
)) {
675 static bool is_builtin_domain(struct winbindd_domain
*domain
)
677 if (strequal(domain
->name
, "BUILTIN") &&
678 sid_check_is_builtin(&domain
->sid
)) {
686 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
687 number and return status
689 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
690 struct winbindd_domain
*domain
,
691 const char *format
, ...) PRINTF_ATTRIBUTE(3,4);
692 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
693 struct winbindd_domain
*domain
,
694 const char *format
, ...)
698 struct cache_entry
*centry
;
700 if (!winbindd_use_cache() ||
701 is_my_own_sam_domain(domain
) ||
702 is_builtin_domain(domain
)) {
706 refresh_sequence_number(domain
, false);
708 va_start(ap
, format
);
709 smb_xvasprintf(&kstr
, format
, ap
);
712 centry
= wcache_fetch_raw(kstr
);
713 if (centry
== NULL
) {
718 if (centry_expired(domain
, kstr
, centry
)) {
720 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
721 kstr
, domain
->name
));
728 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
729 kstr
, domain
->name
));
735 static void wcache_delete(const char *format
, ...) PRINTF_ATTRIBUTE(1,2);
736 static void wcache_delete(const char *format
, ...)
742 va_start(ap
, format
);
743 smb_xvasprintf(&kstr
, format
, ap
);
746 key
= string_tdb_data(kstr
);
748 tdb_delete(wcache
->tdb
, key
);
753 make sure we have at least len bytes available in a centry
755 static void centry_expand(struct cache_entry
*centry
, uint32 len
)
757 if (centry
->len
- centry
->ofs
>= len
)
760 centry
->data
= SMB_REALLOC_ARRAY(centry
->data
, unsigned char,
763 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry
->len
));
764 smb_panic_fn("out of memory in centry_expand");
769 push a uint64_t into a centry
771 static void centry_put_uint64_t(struct cache_entry
*centry
, uint64_t v
)
773 centry_expand(centry
, 8);
774 SBVAL(centry
->data
, centry
->ofs
, v
);
779 push a uint32 into a centry
781 static void centry_put_uint32(struct cache_entry
*centry
, uint32 v
)
783 centry_expand(centry
, 4);
784 SIVAL(centry
->data
, centry
->ofs
, v
);
789 push a uint16 into a centry
791 static void centry_put_uint16(struct cache_entry
*centry
, uint16 v
)
793 centry_expand(centry
, 2);
794 SSVAL(centry
->data
, centry
->ofs
, v
);
799 push a uint8 into a centry
801 static void centry_put_uint8(struct cache_entry
*centry
, uint8 v
)
803 centry_expand(centry
, 1);
804 SCVAL(centry
->data
, centry
->ofs
, v
);
809 push a string into a centry
811 static void centry_put_string(struct cache_entry
*centry
, const char *s
)
816 /* null strings are marked as len 0xFFFF */
817 centry_put_uint8(centry
, 0xFF);
822 /* can't handle more than 254 char strings. Truncating is probably best */
824 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len
));
827 centry_put_uint8(centry
, len
);
828 centry_expand(centry
, len
);
829 memcpy(centry
->data
+ centry
->ofs
, s
, len
);
834 push a 16 byte hash into a centry - treat as 16 byte string.
836 static void centry_put_hash16(struct cache_entry
*centry
, const uint8 val
[16])
838 centry_put_uint8(centry
, 16);
839 centry_expand(centry
, 16);
840 memcpy(centry
->data
+ centry
->ofs
, val
, 16);
844 static void centry_put_sid(struct cache_entry
*centry
, const struct dom_sid
*sid
)
847 centry_put_string(centry
, sid_to_fstring(sid_string
, sid
));
852 put NTSTATUS into a centry
854 static void centry_put_ntstatus(struct cache_entry
*centry
, NTSTATUS status
)
856 uint32 status_value
= NT_STATUS_V(status
);
857 centry_put_uint32(centry
, status_value
);
862 push a NTTIME into a centry
864 static void centry_put_nttime(struct cache_entry
*centry
, NTTIME nt
)
866 centry_expand(centry
, 8);
867 SIVAL(centry
->data
, centry
->ofs
, nt
& 0xFFFFFFFF);
869 SIVAL(centry
->data
, centry
->ofs
, nt
>> 32);
874 push a time_t into a centry - use a 64 bit size.
875 NTTIME here is being used as a convenient 64-bit size.
877 static void centry_put_time(struct cache_entry
*centry
, time_t t
)
879 NTTIME nt
= (NTTIME
)t
;
880 centry_put_nttime(centry
, nt
);
884 start a centry for output. When finished, call centry_end()
886 struct cache_entry
*centry_start(struct winbindd_domain
*domain
, NTSTATUS status
)
888 struct cache_entry
*centry
;
893 centry
= SMB_XMALLOC_P(struct cache_entry
);
895 centry
->len
= 8192; /* reasonable default */
896 centry
->data
= SMB_XMALLOC_ARRAY(uint8
, centry
->len
);
898 centry
->sequence_number
= domain
->sequence_number
;
899 centry
->timeout
= lp_winbind_cache_time() + time(NULL
);
900 centry_put_ntstatus(centry
, status
);
901 centry_put_uint32(centry
, centry
->sequence_number
);
902 centry_put_uint64_t(centry
, centry
->timeout
);
907 finish a centry and write it to the tdb
909 static void centry_end(struct cache_entry
*centry
, const char *format
, ...) PRINTF_ATTRIBUTE(2,3);
910 static void centry_end(struct cache_entry
*centry
, const char *format
, ...)
916 if (!winbindd_use_cache()) {
920 va_start(ap
, format
);
921 smb_xvasprintf(&kstr
, format
, ap
);
924 key
= string_tdb_data(kstr
);
925 data
.dptr
= centry
->data
;
926 data
.dsize
= centry
->ofs
;
928 tdb_store(wcache
->tdb
, key
, data
, TDB_REPLACE
);
932 static void wcache_save_name_to_sid(struct winbindd_domain
*domain
,
933 NTSTATUS status
, const char *domain_name
,
934 const char *name
, const struct dom_sid
*sid
,
935 enum lsa_SidType type
)
937 struct cache_entry
*centry
;
940 centry
= centry_start(domain
, status
);
943 centry_put_uint32(centry
, type
);
944 centry_put_sid(centry
, sid
);
945 fstrcpy(uname
, name
);
947 centry_end(centry
, "NS/%s/%s", domain_name
, uname
);
948 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name
,
949 uname
, sid_string_dbg(sid
), nt_errstr(status
)));
953 static void wcache_save_sid_to_name(struct winbindd_domain
*domain
, NTSTATUS status
,
954 const struct dom_sid
*sid
, const char *domain_name
, const char *name
, enum lsa_SidType type
)
956 struct cache_entry
*centry
;
959 centry
= centry_start(domain
, status
);
963 if (NT_STATUS_IS_OK(status
)) {
964 centry_put_uint32(centry
, type
);
965 centry_put_string(centry
, domain_name
);
966 centry_put_string(centry
, name
);
969 centry_end(centry
, "SN/%s", sid_to_fstring(sid_string
, sid
));
970 DEBUG(10,("wcache_save_sid_to_name: %s -> %s\\%s (%s)\n", sid_string
,
971 domain_name
, name
, nt_errstr(status
)));
976 static void wcache_save_user(struct winbindd_domain
*domain
, NTSTATUS status
,
977 struct wbint_userinfo
*info
)
979 struct cache_entry
*centry
;
982 if (is_null_sid(&info
->user_sid
)) {
986 centry
= centry_start(domain
, status
);
989 centry_put_string(centry
, info
->acct_name
);
990 centry_put_string(centry
, info
->full_name
);
991 centry_put_string(centry
, info
->homedir
);
992 centry_put_string(centry
, info
->shell
);
993 centry_put_uint32(centry
, info
->primary_gid
);
994 centry_put_sid(centry
, &info
->user_sid
);
995 centry_put_sid(centry
, &info
->group_sid
);
996 centry_end(centry
, "U/%s", sid_to_fstring(sid_string
,
998 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string
, info
->acct_name
));
1002 static void wcache_save_lockout_policy(struct winbindd_domain
*domain
,
1004 struct samr_DomInfo12
*lockout_policy
)
1006 struct cache_entry
*centry
;
1008 centry
= centry_start(domain
, status
);
1012 centry_put_nttime(centry
, lockout_policy
->lockout_duration
);
1013 centry_put_nttime(centry
, lockout_policy
->lockout_window
);
1014 centry_put_uint16(centry
, lockout_policy
->lockout_threshold
);
1016 centry_end(centry
, "LOC_POL/%s", domain
->name
);
1018 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain
->name
));
1020 centry_free(centry
);
1025 static void wcache_save_password_policy(struct winbindd_domain
*domain
,
1027 struct samr_DomInfo1
*policy
)
1029 struct cache_entry
*centry
;
1031 centry
= centry_start(domain
, status
);
1035 centry_put_uint16(centry
, policy
->min_password_length
);
1036 centry_put_uint16(centry
, policy
->password_history_length
);
1037 centry_put_uint32(centry
, policy
->password_properties
);
1038 centry_put_nttime(centry
, policy
->max_password_age
);
1039 centry_put_nttime(centry
, policy
->min_password_age
);
1041 centry_end(centry
, "PWD_POL/%s", domain
->name
);
1043 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
1045 centry_free(centry
);
1048 /***************************************************************************
1049 ***************************************************************************/
1051 static void wcache_save_username_alias(struct winbindd_domain
*domain
,
1053 const char *name
, const char *alias
)
1055 struct cache_entry
*centry
;
1058 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1061 centry_put_string( centry
, alias
);
1063 fstrcpy(uname
, name
);
1065 centry_end(centry
, "NSS/NA/%s", uname
);
1067 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name
, alias
));
1069 centry_free(centry
);
1072 static void wcache_save_alias_username(struct winbindd_domain
*domain
,
1074 const char *alias
, const char *name
)
1076 struct cache_entry
*centry
;
1079 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1082 centry_put_string( centry
, name
);
1084 fstrcpy(uname
, alias
);
1086 centry_end(centry
, "NSS/AN/%s", uname
);
1088 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias
, name
));
1090 centry_free(centry
);
1093 /***************************************************************************
1094 ***************************************************************************/
1096 NTSTATUS
resolve_username_to_alias( TALLOC_CTX
*mem_ctx
,
1097 struct winbindd_domain
*domain
,
1098 const char *name
, char **alias
)
1100 struct winbind_cache
*cache
= get_cache(domain
);
1101 struct cache_entry
*centry
= NULL
;
1105 if ( domain
->internal
)
1106 return NT_STATUS_NOT_SUPPORTED
;
1111 if ( (upper_name
= SMB_STRDUP(name
)) == NULL
)
1112 return NT_STATUS_NO_MEMORY
;
1113 strupper_m(upper_name
);
1115 centry
= wcache_fetch(cache
, domain
, "NSS/NA/%s", upper_name
);
1117 SAFE_FREE( upper_name
);
1122 status
= centry
->status
;
1124 if (!NT_STATUS_IS_OK(status
)) {
1125 centry_free(centry
);
1129 *alias
= centry_string( centry
, mem_ctx
);
1131 centry_free(centry
);
1133 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1134 name
, *alias
? *alias
: "(none)"));
1136 return (*alias
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1140 /* If its not in cache and we are offline, then fail */
1142 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1143 DEBUG(8,("resolve_username_to_alias: rejecting query "
1144 "in offline mode\n"));
1145 return NT_STATUS_NOT_FOUND
;
1148 status
= nss_map_to_alias( mem_ctx
, domain
->name
, name
, alias
);
1150 if ( NT_STATUS_IS_OK( status
) ) {
1151 wcache_save_username_alias(domain
, status
, name
, *alias
);
1154 if ( NT_STATUS_EQUAL( status
, NT_STATUS_NONE_MAPPED
) ) {
1155 wcache_save_username_alias(domain
, status
, name
, "(NULL)");
1158 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1159 nt_errstr(status
)));
1161 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1162 set_domain_offline( domain
);
1168 /***************************************************************************
1169 ***************************************************************************/
1171 NTSTATUS
resolve_alias_to_username( TALLOC_CTX
*mem_ctx
,
1172 struct winbindd_domain
*domain
,
1173 const char *alias
, char **name
)
1175 struct winbind_cache
*cache
= get_cache(domain
);
1176 struct cache_entry
*centry
= NULL
;
1180 if ( domain
->internal
)
1181 return NT_STATUS_NOT_SUPPORTED
;
1186 if ( (upper_name
= SMB_STRDUP(alias
)) == NULL
)
1187 return NT_STATUS_NO_MEMORY
;
1188 strupper_m(upper_name
);
1190 centry
= wcache_fetch(cache
, domain
, "NSS/AN/%s", upper_name
);
1192 SAFE_FREE( upper_name
);
1197 status
= centry
->status
;
1199 if (!NT_STATUS_IS_OK(status
)) {
1200 centry_free(centry
);
1204 *name
= centry_string( centry
, mem_ctx
);
1206 centry_free(centry
);
1208 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1209 alias
, *name
? *name
: "(none)"));
1211 return (*name
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1215 /* If its not in cache and we are offline, then fail */
1217 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1218 DEBUG(8,("resolve_alias_to_username: rejecting query "
1219 "in offline mode\n"));
1220 return NT_STATUS_NOT_FOUND
;
1223 /* an alias cannot contain a domain prefix or '@' */
1225 if (strchr(alias
, '\\') || strchr(alias
, '@')) {
1226 DEBUG(10,("resolve_alias_to_username: skipping fully "
1227 "qualified name %s\n", alias
));
1228 return NT_STATUS_OBJECT_NAME_INVALID
;
1231 status
= nss_map_from_alias( mem_ctx
, domain
->name
, alias
, name
);
1233 if ( NT_STATUS_IS_OK( status
) ) {
1234 wcache_save_alias_username( domain
, status
, alias
, *name
);
1237 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1238 wcache_save_alias_username(domain
, status
, alias
, "(NULL)");
1241 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1242 nt_errstr(status
)));
1244 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1245 set_domain_offline( domain
);
1251 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
1253 struct winbind_cache
*cache
= get_cache(domain
);
1255 fstring key_str
, tmp
;
1259 return NT_STATUS_INTERNAL_DB_ERROR
;
1262 if (is_null_sid(sid
)) {
1263 return NT_STATUS_INVALID_SID
;
1266 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1267 return NT_STATUS_INVALID_SID
;
1270 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
1272 data
= tdb_fetch_compat(cache
->tdb
, string_tdb_data(key_str
));
1274 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1277 SAFE_FREE(data
.dptr
);
1278 return NT_STATUS_OK
;
1281 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1282 as new salted ones. */
1284 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
1285 TALLOC_CTX
*mem_ctx
,
1286 const struct dom_sid
*sid
,
1287 const uint8
**cached_nt_pass
,
1288 const uint8
**cached_salt
)
1290 struct winbind_cache
*cache
= get_cache(domain
);
1291 struct cache_entry
*centry
= NULL
;
1297 if (!winbindd_use_cache()) {
1298 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1302 return NT_STATUS_INTERNAL_DB_ERROR
;
1305 if (is_null_sid(sid
)) {
1306 return NT_STATUS_INVALID_SID
;
1309 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1310 return NT_STATUS_INVALID_SID
;
1313 /* Try and get a salted cred first. If we can't
1314 fall back to an unsalted cred. */
1316 centry
= wcache_fetch(cache
, domain
, "CRED/%s",
1317 sid_to_fstring(tmp
, sid
));
1319 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1320 sid_string_dbg(sid
)));
1321 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1324 t
= centry_time(centry
);
1326 /* In the salted case this isn't actually the nt_hash itself,
1327 but the MD5 of the salt + nt_hash. Let the caller
1328 sort this out. It can tell as we only return the cached_salt
1329 if we are returning a salted cred. */
1331 *cached_nt_pass
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1332 if (*cached_nt_pass
== NULL
) {
1335 sid_to_fstring(sidstr
, sid
);
1337 /* Bad (old) cred cache. Delete and pretend we
1339 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1341 wcache_delete("CRED/%s", sidstr
);
1342 centry_free(centry
);
1343 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1346 /* We only have 17 bytes more data in the salted cred case. */
1347 if (centry
->len
- centry
->ofs
== 17) {
1348 *cached_salt
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1350 *cached_salt
= NULL
;
1353 dump_data_pw("cached_nt_pass", *cached_nt_pass
, NT_HASH_LEN
);
1355 dump_data_pw("cached_salt", *cached_salt
, NT_HASH_LEN
);
1358 status
= centry
->status
;
1360 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1361 sid_string_dbg(sid
), nt_errstr(status
) ));
1363 centry_free(centry
);
1367 /* Store creds for a SID - only writes out new salted ones. */
1369 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1370 const struct dom_sid
*sid
,
1371 const uint8 nt_pass
[NT_HASH_LEN
])
1373 struct cache_entry
*centry
;
1376 uint8 cred_salt
[NT_HASH_LEN
];
1377 uint8 salted_hash
[NT_HASH_LEN
];
1379 if (is_null_sid(sid
)) {
1380 return NT_STATUS_INVALID_SID
;
1383 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1384 return NT_STATUS_INVALID_SID
;
1387 centry
= centry_start(domain
, NT_STATUS_OK
);
1389 return NT_STATUS_INTERNAL_DB_ERROR
;
1392 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1394 centry_put_time(centry
, time(NULL
));
1396 /* Create a salt and then salt the hash. */
1397 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1398 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1400 centry_put_hash16(centry
, salted_hash
);
1401 centry_put_hash16(centry
, cred_salt
);
1402 centry_end(centry
, "CRED/%s", sid_to_fstring(sid_string
, sid
));
1404 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1406 centry_free(centry
);
1408 return NT_STATUS_OK
;
1412 /* Query display info. This is the basic user list fn */
1413 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
1414 TALLOC_CTX
*mem_ctx
,
1415 uint32
*num_entries
,
1416 struct wbint_userinfo
**info
)
1418 struct winbind_cache
*cache
= get_cache(domain
);
1419 struct cache_entry
*centry
= NULL
;
1421 unsigned int i
, retry
;
1422 bool old_status
= domain
->online
;
1427 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1432 *num_entries
= centry_uint32(centry
);
1434 if (*num_entries
== 0)
1437 (*info
) = talloc_array(mem_ctx
, struct wbint_userinfo
, *num_entries
);
1439 smb_panic_fn("query_user_list out of memory");
1441 for (i
=0; i
<(*num_entries
); i
++) {
1442 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
1443 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
1444 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
1445 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
1446 centry_sid(centry
, &(*info
)[i
].user_sid
);
1447 centry_sid(centry
, &(*info
)[i
].group_sid
);
1451 status
= centry
->status
;
1453 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1454 domain
->name
, nt_errstr(status
) ));
1456 centry_free(centry
);
1463 /* Return status value returned by seq number check */
1465 if (!NT_STATUS_IS_OK(domain
->last_status
))
1466 return domain
->last_status
;
1468 /* Put the query_user_list() in a retry loop. There appears to be
1469 * some bug either with Windows 2000 or Samba's handling of large
1470 * rpc replies. This manifests itself as sudden disconnection
1471 * at a random point in the enumeration of a large (60k) user list.
1472 * The retry loop simply tries the operation again. )-: It's not
1473 * pretty but an acceptable workaround until we work out what the
1474 * real problem is. */
1479 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1482 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
1483 if (!NT_STATUS_IS_OK(status
)) {
1484 DEBUG(3, ("query_user_list: returned 0x%08x, "
1485 "retrying\n", NT_STATUS_V(status
)));
1487 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1488 DEBUG(3, ("query_user_list: flushing "
1489 "connection cache\n"));
1490 invalidate_cm_connection(&domain
->conn
);
1492 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1493 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1494 if (!domain
->internal
&& old_status
) {
1495 set_domain_offline(domain
);
1497 /* store partial response. */
1498 if (*num_entries
> 0) {
1500 * humm, what about the status used for cache?
1501 * Should it be NT_STATUS_OK?
1506 * domain is offline now, and there is no user entries,
1507 * try to fetch from cache again.
1509 if (cache
->tdb
&& !domain
->online
&& !domain
->internal
&& old_status
) {
1510 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1511 /* partial response... */
1515 goto do_fetch_cache
;
1522 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1526 refresh_sequence_number(domain
, false);
1527 if (!NT_STATUS_IS_OK(status
)) {
1530 centry
= centry_start(domain
, status
);
1533 centry_put_uint32(centry
, *num_entries
);
1534 for (i
=0; i
<(*num_entries
); i
++) {
1535 centry_put_string(centry
, (*info
)[i
].acct_name
);
1536 centry_put_string(centry
, (*info
)[i
].full_name
);
1537 centry_put_string(centry
, (*info
)[i
].homedir
);
1538 centry_put_string(centry
, (*info
)[i
].shell
);
1539 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1540 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1541 if (domain
->backend
&& domain
->backend
->consistent
) {
1542 /* when the backend is consistent we can pre-prime some mappings */
1543 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1545 (*info
)[i
].acct_name
,
1546 &(*info
)[i
].user_sid
,
1548 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1549 &(*info
)[i
].user_sid
,
1551 (*info
)[i
].acct_name
,
1553 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1556 centry_end(centry
, "UL/%s", domain
->name
);
1557 centry_free(centry
);
1563 /* list all domain groups */
1564 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
1565 TALLOC_CTX
*mem_ctx
,
1566 uint32
*num_entries
,
1567 struct wb_acct_info
**info
)
1569 struct winbind_cache
*cache
= get_cache(domain
);
1570 struct cache_entry
*centry
= NULL
;
1575 old_status
= domain
->online
;
1579 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1584 *num_entries
= centry_uint32(centry
);
1586 if (*num_entries
== 0)
1589 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1591 smb_panic_fn("enum_dom_groups out of memory");
1593 for (i
=0; i
<(*num_entries
); i
++) {
1594 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1595 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1596 (*info
)[i
].rid
= centry_uint32(centry
);
1600 status
= centry
->status
;
1602 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1603 domain
->name
, nt_errstr(status
) ));
1605 centry_free(centry
);
1612 /* Return status value returned by seq number check */
1614 if (!NT_STATUS_IS_OK(domain
->last_status
))
1615 return domain
->last_status
;
1617 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1620 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1622 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1623 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1624 if (!domain
->internal
&& old_status
) {
1625 set_domain_offline(domain
);
1629 !domain
->internal
&&
1631 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1633 goto do_fetch_cache
;
1638 refresh_sequence_number(domain
, false);
1639 if (!NT_STATUS_IS_OK(status
)) {
1642 centry
= centry_start(domain
, status
);
1645 centry_put_uint32(centry
, *num_entries
);
1646 for (i
=0; i
<(*num_entries
); i
++) {
1647 centry_put_string(centry
, (*info
)[i
].acct_name
);
1648 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1649 centry_put_uint32(centry
, (*info
)[i
].rid
);
1651 centry_end(centry
, "GL/%s/domain", domain
->name
);
1652 centry_free(centry
);
1658 /* list all domain groups */
1659 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
1660 TALLOC_CTX
*mem_ctx
,
1661 uint32
*num_entries
,
1662 struct wb_acct_info
**info
)
1664 struct winbind_cache
*cache
= get_cache(domain
);
1665 struct cache_entry
*centry
= NULL
;
1670 old_status
= domain
->online
;
1674 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1679 *num_entries
= centry_uint32(centry
);
1681 if (*num_entries
== 0)
1684 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1686 smb_panic_fn("enum_dom_groups out of memory");
1688 for (i
=0; i
<(*num_entries
); i
++) {
1689 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1690 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1691 (*info
)[i
].rid
= centry_uint32(centry
);
1696 /* If we are returning cached data and the domain controller
1697 is down then we don't know whether the data is up to date
1698 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1701 if (wcache_server_down(domain
)) {
1702 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1703 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1705 status
= centry
->status
;
1707 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1708 domain
->name
, nt_errstr(status
) ));
1710 centry_free(centry
);
1717 /* Return status value returned by seq number check */
1719 if (!NT_STATUS_IS_OK(domain
->last_status
))
1720 return domain
->last_status
;
1722 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1725 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1727 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1728 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1729 if (!domain
->internal
&& old_status
) {
1730 set_domain_offline(domain
);
1733 !domain
->internal
&&
1736 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1738 goto do_fetch_cache
;
1743 refresh_sequence_number(domain
, false);
1744 if (!NT_STATUS_IS_OK(status
)) {
1747 centry
= centry_start(domain
, status
);
1750 centry_put_uint32(centry
, *num_entries
);
1751 for (i
=0; i
<(*num_entries
); i
++) {
1752 centry_put_string(centry
, (*info
)[i
].acct_name
);
1753 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1754 centry_put_uint32(centry
, (*info
)[i
].rid
);
1756 centry_end(centry
, "GL/%s/local", domain
->name
);
1757 centry_free(centry
);
1763 NTSTATUS
wcache_name_to_sid(struct winbindd_domain
*domain
,
1764 const char *domain_name
,
1766 struct dom_sid
*sid
,
1767 enum lsa_SidType
*type
)
1769 struct winbind_cache
*cache
= get_cache(domain
);
1770 struct cache_entry
*centry
;
1774 if (cache
->tdb
== NULL
) {
1775 return NT_STATUS_NOT_FOUND
;
1778 uname
= talloc_strdup_upper(talloc_tos(), name
);
1779 if (uname
== NULL
) {
1780 return NT_STATUS_NO_MEMORY
;
1783 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1785 if (centry
== NULL
) {
1786 return NT_STATUS_NOT_FOUND
;
1789 status
= centry
->status
;
1790 if (NT_STATUS_IS_OK(status
)) {
1791 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1792 centry_sid(centry
, sid
);
1795 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1796 "%s\n", domain
->name
, nt_errstr(status
) ));
1798 centry_free(centry
);
1802 /* convert a single name to a sid in a domain */
1803 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
1804 TALLOC_CTX
*mem_ctx
,
1805 const char *domain_name
,
1808 struct dom_sid
*sid
,
1809 enum lsa_SidType
*type
)
1814 old_status
= domain
->online
;
1816 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1817 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1823 /* If the seq number check indicated that there is a problem
1824 * with this DC, then return that status... except for
1825 * access_denied. This is special because the dc may be in
1826 * "restrict anonymous = 1" mode, in which case it will deny
1827 * most unauthenticated operations, but *will* allow the LSA
1828 * name-to-sid that we try as a fallback. */
1830 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1831 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1832 return domain
->last_status
;
1834 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1837 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
,
1838 name
, flags
, sid
, type
);
1840 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1841 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1842 if (!domain
->internal
&& old_status
) {
1843 set_domain_offline(domain
);
1845 if (!domain
->internal
&&
1848 NTSTATUS cache_status
;
1849 cache_status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1850 return cache_status
;
1854 refresh_sequence_number(domain
, false);
1856 if (domain
->online
&&
1857 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1858 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1860 /* Only save the reverse mapping if this was not a UPN */
1861 if (!strchr(name
, '@')) {
1862 strupper_m(discard_const_p(char, domain_name
));
1863 strlower_m(discard_const_p(char, name
));
1864 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1871 NTSTATUS
wcache_sid_to_name(struct winbindd_domain
*domain
,
1872 const struct dom_sid
*sid
,
1873 TALLOC_CTX
*mem_ctx
,
1876 enum lsa_SidType
*type
)
1878 struct winbind_cache
*cache
= get_cache(domain
);
1879 struct cache_entry
*centry
;
1883 if (cache
->tdb
== NULL
) {
1884 return NT_STATUS_NOT_FOUND
;
1887 sid_string
= sid_string_tos(sid
);
1888 if (sid_string
== NULL
) {
1889 return NT_STATUS_NO_MEMORY
;
1892 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_string
);
1893 TALLOC_FREE(sid_string
);
1894 if (centry
== NULL
) {
1895 return NT_STATUS_NOT_FOUND
;
1898 if (NT_STATUS_IS_OK(centry
->status
)) {
1899 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1900 *domain_name
= centry_string(centry
, mem_ctx
);
1901 *name
= centry_string(centry
, mem_ctx
);
1904 status
= centry
->status
;
1905 centry_free(centry
);
1907 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1908 "%s\n", domain
->name
, nt_errstr(status
) ));
1913 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1915 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1916 TALLOC_CTX
*mem_ctx
,
1917 const struct dom_sid
*sid
,
1920 enum lsa_SidType
*type
)
1925 old_status
= domain
->online
;
1926 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
1928 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1933 *domain_name
= NULL
;
1935 /* If the seq number check indicated that there is a problem
1936 * with this DC, then return that status... except for
1937 * access_denied. This is special because the dc may be in
1938 * "restrict anonymous = 1" mode, in which case it will deny
1939 * most unauthenticated operations, but *will* allow the LSA
1940 * sid-to-name that we try as a fallback. */
1942 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1943 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1944 return domain
->last_status
;
1946 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1949 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1951 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1952 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1953 if (!domain
->internal
&& old_status
) {
1954 set_domain_offline(domain
);
1956 if (!domain
->internal
&&
1959 NTSTATUS cache_status
;
1960 cache_status
= wcache_sid_to_name(domain
, sid
, mem_ctx
,
1961 domain_name
, name
, type
);
1962 return cache_status
;
1966 refresh_sequence_number(domain
, false);
1967 if (!NT_STATUS_IS_OK(status
)) {
1970 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
1972 /* We can't save the name to sid mapping here, as with sid history a
1973 * later name2sid would give the wrong sid. */
1978 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
1979 TALLOC_CTX
*mem_ctx
,
1980 const struct dom_sid
*domain_sid
,
1985 enum lsa_SidType
**types
)
1987 struct winbind_cache
*cache
= get_cache(domain
);
1989 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1994 old_status
= domain
->online
;
1995 *domain_name
= NULL
;
2003 if (num_rids
== 0) {
2004 return NT_STATUS_OK
;
2007 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2008 *types
= talloc_array(mem_ctx
, enum lsa_SidType
, num_rids
);
2010 if ((*names
== NULL
) || (*types
== NULL
)) {
2011 result
= NT_STATUS_NO_MEMORY
;
2015 have_mapped
= have_unmapped
= false;
2017 for (i
=0; i
<num_rids
; i
++) {
2019 struct cache_entry
*centry
;
2022 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2023 result
= NT_STATUS_INTERNAL_ERROR
;
2027 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2028 sid_to_fstring(tmp
, &sid
));
2033 (*types
)[i
] = SID_NAME_UNKNOWN
;
2034 (*names
)[i
] = talloc_strdup(*names
, "");
2036 if (NT_STATUS_IS_OK(centry
->status
)) {
2039 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2041 dom
= centry_string(centry
, mem_ctx
);
2042 if (*domain_name
== NULL
) {
2048 (*names
)[i
] = centry_string(centry
, *names
);
2050 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)
2051 || NT_STATUS_EQUAL(centry
->status
, STATUS_SOME_UNMAPPED
)) {
2052 have_unmapped
= true;
2055 /* something's definitely wrong */
2056 result
= centry
->status
;
2060 centry_free(centry
);
2064 return NT_STATUS_NONE_MAPPED
;
2066 if (!have_unmapped
) {
2067 return NT_STATUS_OK
;
2069 return STATUS_SOME_UNMAPPED
;
2073 TALLOC_FREE(*names
);
2074 TALLOC_FREE(*types
);
2076 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
2077 rids
, num_rids
, domain_name
,
2080 if (NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
2081 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2082 if (!domain
->internal
&& old_status
) {
2083 set_domain_offline(domain
);
2086 !domain
->internal
&&
2089 have_mapped
= have_unmapped
= false;
2091 for (i
=0; i
<num_rids
; i
++) {
2093 struct cache_entry
*centry
;
2096 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2097 result
= NT_STATUS_INTERNAL_ERROR
;
2101 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2102 sid_to_fstring(tmp
, &sid
));
2104 (*types
)[i
] = SID_NAME_UNKNOWN
;
2105 (*names
)[i
] = talloc_strdup(*names
, "");
2109 (*types
)[i
] = SID_NAME_UNKNOWN
;
2110 (*names
)[i
] = talloc_strdup(*names
, "");
2112 if (NT_STATUS_IS_OK(centry
->status
)) {
2115 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2117 dom
= centry_string(centry
, mem_ctx
);
2118 if (*domain_name
== NULL
) {
2124 (*names
)[i
] = centry_string(centry
, *names
);
2126 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)) {
2127 have_unmapped
= true;
2130 /* something's definitely wrong */
2131 result
= centry
->status
;
2135 centry_free(centry
);
2139 return NT_STATUS_NONE_MAPPED
;
2141 if (!have_unmapped
) {
2142 return NT_STATUS_OK
;
2144 return STATUS_SOME_UNMAPPED
;
2148 None of the queried rids has been found so save all negative entries
2150 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
2151 for (i
= 0; i
< num_rids
; i
++) {
2153 const char *name
= "";
2154 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
2155 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
2157 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2158 return NT_STATUS_INTERNAL_ERROR
;
2161 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2169 Some or all of the queried rids have been found.
2171 if (!NT_STATUS_IS_OK(result
) &&
2172 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
2176 refresh_sequence_number(domain
, false);
2178 for (i
=0; i
<num_rids
; i
++) {
2182 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2183 result
= NT_STATUS_INTERNAL_ERROR
;
2187 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
2188 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
2190 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2191 (*names
)[i
], (*types
)[i
]);
2197 TALLOC_FREE(*names
);
2198 TALLOC_FREE(*types
);
2202 NTSTATUS
wcache_query_user(struct winbindd_domain
*domain
,
2203 TALLOC_CTX
*mem_ctx
,
2204 const struct dom_sid
*user_sid
,
2205 struct wbint_userinfo
*info
)
2207 struct winbind_cache
*cache
= get_cache(domain
);
2208 struct cache_entry
*centry
= NULL
;
2212 if (cache
->tdb
== NULL
) {
2213 return NT_STATUS_NOT_FOUND
;
2216 sid_string
= sid_string_tos(user_sid
);
2217 if (sid_string
== NULL
) {
2218 return NT_STATUS_NO_MEMORY
;
2221 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string
);
2222 TALLOC_FREE(sid_string
);
2223 if (centry
== NULL
) {
2224 return NT_STATUS_NOT_FOUND
;
2228 * If we have an access denied cache entry and a cached info3
2229 * in the samlogon cache then do a query. This will force the
2230 * rpc back end to return the info3 data.
2233 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
) &&
2234 netsamlogon_cache_have(user_sid
)) {
2235 DEBUG(10, ("query_user: cached access denied and have cached "
2237 domain
->last_status
= NT_STATUS_OK
;
2238 centry_free(centry
);
2239 return NT_STATUS_NOT_FOUND
;
2242 /* if status is not ok then this is a negative hit
2243 and the rest of the data doesn't matter */
2244 status
= centry
->status
;
2245 if (NT_STATUS_IS_OK(status
)) {
2246 info
->acct_name
= centry_string(centry
, mem_ctx
);
2247 info
->full_name
= centry_string(centry
, mem_ctx
);
2248 info
->homedir
= centry_string(centry
, mem_ctx
);
2249 info
->shell
= centry_string(centry
, mem_ctx
);
2250 info
->primary_gid
= centry_uint32(centry
);
2251 centry_sid(centry
, &info
->user_sid
);
2252 centry_sid(centry
, &info
->group_sid
);
2255 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2256 "%s\n", domain
->name
, nt_errstr(status
) ));
2258 centry_free(centry
);
2262 /* Lookup user information from a rid */
2263 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
2264 TALLOC_CTX
*mem_ctx
,
2265 const struct dom_sid
*user_sid
,
2266 struct wbint_userinfo
*info
)
2271 old_status
= domain
->online
;
2272 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2273 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2279 /* Return status value returned by seq number check */
2281 if (!NT_STATUS_IS_OK(domain
->last_status
))
2282 return domain
->last_status
;
2284 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2287 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
2289 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2290 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2291 if (!domain
->internal
&& old_status
) {
2292 set_domain_offline(domain
);
2294 if (!domain
->internal
&&
2297 NTSTATUS cache_status
;
2298 cache_status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2299 return cache_status
;
2303 refresh_sequence_number(domain
, false);
2304 if (!NT_STATUS_IS_OK(status
)) {
2307 wcache_save_user(domain
, status
, info
);
2312 NTSTATUS
wcache_lookup_usergroups(struct winbindd_domain
*domain
,
2313 TALLOC_CTX
*mem_ctx
,
2314 const struct dom_sid
*user_sid
,
2315 uint32_t *pnum_sids
,
2316 struct dom_sid
**psids
)
2318 struct winbind_cache
*cache
= get_cache(domain
);
2319 struct cache_entry
*centry
= NULL
;
2321 uint32_t i
, num_sids
;
2322 struct dom_sid
*sids
;
2325 if (cache
->tdb
== NULL
) {
2326 return NT_STATUS_NOT_FOUND
;
2329 centry
= wcache_fetch(cache
, domain
, "UG/%s",
2330 sid_to_fstring(sid_string
, user_sid
));
2331 if (centry
== NULL
) {
2332 return NT_STATUS_NOT_FOUND
;
2335 /* If we have an access denied cache entry and a cached info3 in the
2336 samlogon cache then do a query. This will force the rpc back end
2337 to return the info3 data. */
2339 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)
2340 && netsamlogon_cache_have(user_sid
)) {
2341 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2343 domain
->last_status
= NT_STATUS_OK
;
2344 centry_free(centry
);
2345 return NT_STATUS_NOT_FOUND
;
2348 num_sids
= centry_uint32(centry
);
2349 sids
= talloc_array(mem_ctx
, struct dom_sid
, num_sids
);
2351 centry_free(centry
);
2352 return NT_STATUS_NO_MEMORY
;
2355 for (i
=0; i
<num_sids
; i
++) {
2356 centry_sid(centry
, &sids
[i
]);
2359 status
= centry
->status
;
2361 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2362 "status: %s\n", domain
->name
, nt_errstr(status
)));
2364 centry_free(centry
);
2366 *pnum_sids
= num_sids
;
2371 /* Lookup groups a user is a member of. */
2372 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
2373 TALLOC_CTX
*mem_ctx
,
2374 const struct dom_sid
*user_sid
,
2375 uint32
*num_groups
, struct dom_sid
**user_gids
)
2377 struct cache_entry
*centry
= NULL
;
2383 old_status
= domain
->online
;
2384 status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2385 num_groups
, user_gids
);
2386 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2391 (*user_gids
) = NULL
;
2393 /* Return status value returned by seq number check */
2395 if (!NT_STATUS_IS_OK(domain
->last_status
))
2396 return domain
->last_status
;
2398 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2401 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
2403 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2404 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2405 if (!domain
->internal
&& old_status
) {
2406 set_domain_offline(domain
);
2408 if (!domain
->internal
&&
2411 NTSTATUS cache_status
;
2412 cache_status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2413 num_groups
, user_gids
);
2414 return cache_status
;
2417 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
2421 refresh_sequence_number(domain
, false);
2422 if (!NT_STATUS_IS_OK(status
)) {
2425 centry
= centry_start(domain
, status
);
2429 centry_put_uint32(centry
, *num_groups
);
2430 for (i
=0; i
<(*num_groups
); i
++) {
2431 centry_put_sid(centry
, &(*user_gids
)[i
]);
2434 centry_end(centry
, "UG/%s", sid_to_fstring(sid_string
, user_sid
));
2435 centry_free(centry
);
2441 static char *wcache_make_sidlist(TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2442 const struct dom_sid
*sids
)
2447 sidlist
= talloc_strdup(mem_ctx
, "");
2448 if (sidlist
== NULL
) {
2451 for (i
=0; i
<num_sids
; i
++) {
2453 sidlist
= talloc_asprintf_append_buffer(
2454 sidlist
, "/%s", sid_to_fstring(tmp
, &sids
[i
]));
2455 if (sidlist
== NULL
) {
2462 NTSTATUS
wcache_lookup_useraliases(struct winbindd_domain
*domain
,
2463 TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2464 const struct dom_sid
*sids
,
2465 uint32_t *pnum_aliases
, uint32_t **paliases
)
2467 struct winbind_cache
*cache
= get_cache(domain
);
2468 struct cache_entry
*centry
= NULL
;
2469 uint32_t num_aliases
;
2475 if (cache
->tdb
== NULL
) {
2476 return NT_STATUS_NOT_FOUND
;
2479 if (num_sids
== 0) {
2482 return NT_STATUS_OK
;
2485 /* We need to cache indexed by the whole list of SIDs, the aliases
2486 * resulting might come from any of the SIDs. */
2488 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2489 if (sidlist
== NULL
) {
2490 return NT_STATUS_NO_MEMORY
;
2493 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2494 TALLOC_FREE(sidlist
);
2495 if (centry
== NULL
) {
2496 return NT_STATUS_NOT_FOUND
;
2499 num_aliases
= centry_uint32(centry
);
2500 aliases
= talloc_array(mem_ctx
, uint32_t, num_aliases
);
2501 if (aliases
== NULL
) {
2502 centry_free(centry
);
2503 return NT_STATUS_NO_MEMORY
;
2506 for (i
=0; i
<num_aliases
; i
++) {
2507 aliases
[i
] = centry_uint32(centry
);
2510 status
= centry
->status
;
2512 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2513 "status %s\n", domain
->name
, nt_errstr(status
)));
2515 centry_free(centry
);
2517 *pnum_aliases
= num_aliases
;
2518 *paliases
= aliases
;
2523 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
2524 TALLOC_CTX
*mem_ctx
,
2525 uint32 num_sids
, const struct dom_sid
*sids
,
2526 uint32
*num_aliases
, uint32
**alias_rids
)
2528 struct cache_entry
*centry
= NULL
;
2534 old_status
= domain
->online
;
2535 status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
2536 num_aliases
, alias_rids
);
2537 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2542 (*alias_rids
) = NULL
;
2544 if (!NT_STATUS_IS_OK(domain
->last_status
))
2545 return domain
->last_status
;
2547 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2548 "for domain %s\n", domain
->name
));
2550 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2551 if (sidlist
== NULL
) {
2552 return NT_STATUS_NO_MEMORY
;
2555 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2557 num_aliases
, alias_rids
);
2559 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2560 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2561 if (!domain
->internal
&& old_status
) {
2562 set_domain_offline(domain
);
2564 if (!domain
->internal
&&
2567 NTSTATUS cache_status
;
2568 cache_status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
,
2569 sids
, num_aliases
, alias_rids
);
2570 return cache_status
;
2574 refresh_sequence_number(domain
, false);
2575 if (!NT_STATUS_IS_OK(status
)) {
2578 centry
= centry_start(domain
, status
);
2581 centry_put_uint32(centry
, *num_aliases
);
2582 for (i
=0; i
<(*num_aliases
); i
++)
2583 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2584 centry_end(centry
, "UA%s", sidlist
);
2585 centry_free(centry
);
2591 NTSTATUS
wcache_lookup_groupmem(struct winbindd_domain
*domain
,
2592 TALLOC_CTX
*mem_ctx
,
2593 const struct dom_sid
*group_sid
,
2594 uint32_t *num_names
,
2595 struct dom_sid
**sid_mem
, char ***names
,
2596 uint32_t **name_types
)
2598 struct winbind_cache
*cache
= get_cache(domain
);
2599 struct cache_entry
*centry
= NULL
;
2604 if (cache
->tdb
== NULL
) {
2605 return NT_STATUS_NOT_FOUND
;
2608 sid_string
= sid_string_tos(group_sid
);
2609 if (sid_string
== NULL
) {
2610 return NT_STATUS_NO_MEMORY
;
2613 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_string
);
2614 TALLOC_FREE(sid_string
);
2615 if (centry
== NULL
) {
2616 return NT_STATUS_NOT_FOUND
;
2623 *num_names
= centry_uint32(centry
);
2624 if (*num_names
== 0) {
2625 centry_free(centry
);
2626 return NT_STATUS_OK
;
2629 *sid_mem
= talloc_array(mem_ctx
, struct dom_sid
, *num_names
);
2630 *names
= talloc_array(mem_ctx
, char *, *num_names
);
2631 *name_types
= talloc_array(mem_ctx
, uint32
, *num_names
);
2633 if ((*sid_mem
== NULL
) || (*names
== NULL
) || (*name_types
== NULL
)) {
2634 TALLOC_FREE(*sid_mem
);
2635 TALLOC_FREE(*names
);
2636 TALLOC_FREE(*name_types
);
2637 centry_free(centry
);
2638 return NT_STATUS_NO_MEMORY
;
2641 for (i
=0; i
<(*num_names
); i
++) {
2642 centry_sid(centry
, &(*sid_mem
)[i
]);
2643 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2644 (*name_types
)[i
] = centry_uint32(centry
);
2647 status
= centry
->status
;
2649 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2650 "status: %s\n", domain
->name
, nt_errstr(status
)));
2652 centry_free(centry
);
2656 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
2657 TALLOC_CTX
*mem_ctx
,
2658 const struct dom_sid
*group_sid
,
2659 enum lsa_SidType type
,
2661 struct dom_sid
**sid_mem
, char ***names
,
2662 uint32
**name_types
)
2664 struct cache_entry
*centry
= NULL
;
2670 old_status
= domain
->online
;
2671 status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2672 sid_mem
, names
, name_types
);
2673 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2680 (*name_types
) = NULL
;
2682 /* Return status value returned by seq number check */
2684 if (!NT_STATUS_IS_OK(domain
->last_status
))
2685 return domain
->last_status
;
2687 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2690 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
,
2692 sid_mem
, names
, name_types
);
2694 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2695 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2696 if (!domain
->internal
&& old_status
) {
2697 set_domain_offline(domain
);
2699 if (!domain
->internal
&&
2702 NTSTATUS cache_status
;
2703 cache_status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
,
2704 num_names
, sid_mem
, names
,
2706 return cache_status
;
2710 refresh_sequence_number(domain
, false);
2711 if (!NT_STATUS_IS_OK(status
)) {
2714 centry
= centry_start(domain
, status
);
2717 centry_put_uint32(centry
, *num_names
);
2718 for (i
=0; i
<(*num_names
); i
++) {
2719 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2720 centry_put_string(centry
, (*names
)[i
]);
2721 centry_put_uint32(centry
, (*name_types
)[i
]);
2723 centry_end(centry
, "GM/%s", sid_to_fstring(sid_string
, group_sid
));
2724 centry_free(centry
);
2730 /* find the sequence number for a domain */
2731 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
2733 refresh_sequence_number(domain
, false);
2735 *seq
= domain
->sequence_number
;
2737 return NT_STATUS_OK
;
2740 /* enumerate trusted domains
2741 * (we need to have the list of trustdoms in the cache when we go offline) -
2743 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
2744 TALLOC_CTX
*mem_ctx
,
2745 struct netr_DomainTrustList
*trusts
)
2748 struct winbind_cache
*cache
;
2749 struct winbindd_tdc_domain
*dom_list
= NULL
;
2750 size_t num_domains
= 0;
2751 bool retval
= false;
2755 old_status
= domain
->online
;
2757 trusts
->array
= NULL
;
2759 cache
= get_cache(domain
);
2760 if (!cache
|| !cache
->tdb
) {
2764 if (domain
->online
) {
2768 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2769 if (!retval
|| !num_domains
|| !dom_list
) {
2770 TALLOC_FREE(dom_list
);
2775 trusts
->array
= talloc_zero_array(mem_ctx
, struct netr_DomainTrust
, num_domains
);
2776 if (!trusts
->array
) {
2777 TALLOC_FREE(dom_list
);
2778 return NT_STATUS_NO_MEMORY
;
2781 for (i
= 0; i
< num_domains
; i
++) {
2782 struct netr_DomainTrust
*trust
;
2783 struct dom_sid
*sid
;
2784 struct winbindd_domain
*dom
;
2786 dom
= find_domain_from_name_noinit(dom_list
[i
].domain_name
);
2787 if (dom
&& dom
->internal
) {
2791 trust
= &trusts
->array
[trusts
->count
];
2792 trust
->netbios_name
= talloc_strdup(trusts
->array
, dom_list
[i
].domain_name
);
2793 trust
->dns_name
= talloc_strdup(trusts
->array
, dom_list
[i
].dns_name
);
2794 sid
= talloc(trusts
->array
, struct dom_sid
);
2795 if (!trust
->netbios_name
|| !trust
->dns_name
||
2797 TALLOC_FREE(dom_list
);
2798 TALLOC_FREE(trusts
->array
);
2799 return NT_STATUS_NO_MEMORY
;
2802 trust
->trust_flags
= dom_list
[i
].trust_flags
;
2803 trust
->trust_attributes
= dom_list
[i
].trust_attribs
;
2804 trust
->trust_type
= dom_list
[i
].trust_type
;
2805 sid_copy(sid
, &dom_list
[i
].sid
);
2810 TALLOC_FREE(dom_list
);
2811 return NT_STATUS_OK
;
2814 /* Return status value returned by seq number check */
2816 if (!NT_STATUS_IS_OK(domain
->last_status
))
2817 return domain
->last_status
;
2819 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2822 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, trusts
);
2824 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2825 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2826 if (!domain
->internal
&& old_status
) {
2827 set_domain_offline(domain
);
2829 if (!domain
->internal
&&
2832 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2833 if (retval
&& num_domains
&& dom_list
) {
2834 TALLOC_FREE(trusts
->array
);
2836 goto do_fetch_cache
;
2840 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2841 * so that the generic centry handling still applies correctly -
2844 if (!NT_STATUS_IS_ERR(status
)) {
2845 status
= NT_STATUS_OK
;
2850 /* get lockout policy */
2851 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
2852 TALLOC_CTX
*mem_ctx
,
2853 struct samr_DomInfo12
*policy
)
2855 struct winbind_cache
*cache
= get_cache(domain
);
2856 struct cache_entry
*centry
= NULL
;
2860 old_status
= domain
->online
;
2864 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2870 policy
->lockout_duration
= centry_nttime(centry
);
2871 policy
->lockout_window
= centry_nttime(centry
);
2872 policy
->lockout_threshold
= centry_uint16(centry
);
2874 status
= centry
->status
;
2876 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2877 domain
->name
, nt_errstr(status
) ));
2879 centry_free(centry
);
2883 ZERO_STRUCTP(policy
);
2885 /* Return status value returned by seq number check */
2887 if (!NT_STATUS_IS_OK(domain
->last_status
))
2888 return domain
->last_status
;
2890 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2893 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2895 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2896 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2897 if (!domain
->internal
&& old_status
) {
2898 set_domain_offline(domain
);
2901 !domain
->internal
&&
2904 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2906 goto do_fetch_cache
;
2911 refresh_sequence_number(domain
, false);
2912 if (!NT_STATUS_IS_OK(status
)) {
2915 wcache_save_lockout_policy(domain
, status
, policy
);
2920 /* get password policy */
2921 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
2922 TALLOC_CTX
*mem_ctx
,
2923 struct samr_DomInfo1
*policy
)
2925 struct winbind_cache
*cache
= get_cache(domain
);
2926 struct cache_entry
*centry
= NULL
;
2930 old_status
= domain
->online
;
2934 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2940 policy
->min_password_length
= centry_uint16(centry
);
2941 policy
->password_history_length
= centry_uint16(centry
);
2942 policy
->password_properties
= centry_uint32(centry
);
2943 policy
->max_password_age
= centry_nttime(centry
);
2944 policy
->min_password_age
= centry_nttime(centry
);
2946 status
= centry
->status
;
2948 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2949 domain
->name
, nt_errstr(status
) ));
2951 centry_free(centry
);
2955 ZERO_STRUCTP(policy
);
2957 /* Return status value returned by seq number check */
2959 if (!NT_STATUS_IS_OK(domain
->last_status
))
2960 return domain
->last_status
;
2962 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2965 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
2967 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2968 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2969 if (!domain
->internal
&& old_status
) {
2970 set_domain_offline(domain
);
2973 !domain
->internal
&&
2976 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2978 goto do_fetch_cache
;
2983 refresh_sequence_number(domain
, false);
2984 if (!NT_STATUS_IS_OK(status
)) {
2987 wcache_save_password_policy(domain
, status
, policy
);
2993 /* Invalidate cached user and group lists coherently */
2995 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2998 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
2999 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
3000 tdb_delete(the_tdb
, kbuf
);
3005 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3007 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
3008 const struct dom_sid
*sid
)
3010 fstring key_str
, sid_string
;
3011 struct winbind_cache
*cache
;
3013 /* dont clear cached U/SID and UG/SID entries when we want to logon
3016 if (lp_winbind_offline_logon()) {
3023 cache
= get_cache(domain
);
3029 /* Clear U/SID cache entry */
3030 fstr_sprintf(key_str
, "U/%s", sid_to_fstring(sid_string
, sid
));
3031 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3032 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3034 /* Clear UG/SID cache entry */
3035 fstr_sprintf(key_str
, "UG/%s", sid_to_fstring(sid_string
, sid
));
3036 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3037 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3039 /* Samba/winbindd never needs this. */
3040 netsamlogon_clear_cached_user(sid
);
3043 bool wcache_invalidate_cache(void)
3045 struct winbindd_domain
*domain
;
3047 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3048 struct winbind_cache
*cache
= get_cache(domain
);
3050 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3051 "entries for %s\n", domain
->name
));
3054 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3063 bool wcache_invalidate_cache_noinit(void)
3065 struct winbindd_domain
*domain
;
3067 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3068 struct winbind_cache
*cache
;
3070 /* Skip uninitialized domains. */
3071 if (!domain
->initialized
&& !domain
->internal
) {
3075 cache
= get_cache(domain
);
3077 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3078 "entries for %s\n", domain
->name
));
3081 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3083 * Flushing cache has nothing to with domains.
3084 * return here if we successfully flushed once.
3085 * To avoid unnecessary traversing the cache.
3096 bool init_wcache(void)
3098 if (wcache
== NULL
) {
3099 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
3100 ZERO_STRUCTP(wcache
);
3103 if (wcache
->tdb
!= NULL
)
3106 /* when working offline we must not clear the cache on restart */
3107 wcache
->tdb
= tdb_open_log(state_path("winbindd_cache.tdb"),
3108 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3109 TDB_INCOMPATIBLE_HASH
|
3110 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3111 O_RDWR
|O_CREAT
, 0600);
3113 if (wcache
->tdb
== NULL
) {
3114 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3121 /************************************************************************
3122 This is called by the parent to initialize the cache file.
3123 We don't need sophisticated locking here as we know we're the
3125 ************************************************************************/
3127 bool initialize_winbindd_cache(void)
3129 bool cache_bad
= true;
3132 if (!init_wcache()) {
3133 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3137 /* Check version number. */
3138 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
3139 vers
== WINBINDD_CACHE_VERSION
) {
3144 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3145 "and re-creating with version number %d\n",
3146 WINBINDD_CACHE_VERSION
));
3148 tdb_close(wcache
->tdb
);
3151 if (unlink(state_path("winbindd_cache.tdb")) == -1) {
3152 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3153 state_path("winbindd_cache.tdb"),
3157 if (!init_wcache()) {
3158 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3159 "init_wcache failed.\n"));
3163 /* Write the version. */
3164 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
3165 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3166 tdb_errorstr_compat(wcache
->tdb
) ));
3171 tdb_close(wcache
->tdb
);
3176 void close_winbindd_cache(void)
3182 tdb_close(wcache
->tdb
);
3187 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*sid
,
3188 char **domain_name
, char **name
,
3189 enum lsa_SidType
*type
)
3191 struct winbindd_domain
*domain
;
3194 domain
= find_lookup_domain_from_sid(sid
);
3195 if (domain
== NULL
) {
3198 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
3200 return NT_STATUS_IS_OK(status
);
3203 bool lookup_cached_name(const char *domain_name
,
3205 struct dom_sid
*sid
,
3206 enum lsa_SidType
*type
)
3208 struct winbindd_domain
*domain
;
3210 bool original_online_state
;
3212 domain
= find_lookup_domain_from_name(domain_name
);
3213 if (domain
== NULL
) {
3217 /* If we are doing a cached logon, temporarily set the domain
3218 offline so the cache won't expire the entry */
3220 original_online_state
= domain
->online
;
3221 domain
->online
= false;
3222 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
3223 domain
->online
= original_online_state
;
3225 return NT_STATUS_IS_OK(status
);
3228 void cache_name2sid(struct winbindd_domain
*domain
,
3229 const char *domain_name
, const char *name
,
3230 enum lsa_SidType type
, const struct dom_sid
*sid
)
3232 refresh_sequence_number(domain
, false);
3233 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
3238 * The original idea that this cache only contains centries has
3239 * been blurred - now other stuff gets put in here. Ensure we
3240 * ignore these things on cleanup.
3243 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
3244 TDB_DATA dbuf
, void *state
)
3246 struct cache_entry
*centry
;
3248 if (is_non_centry_key(kbuf
)) {
3252 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
3257 if (!NT_STATUS_IS_OK(centry
->status
)) {
3258 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
3259 tdb_delete(the_tdb
, kbuf
);
3262 centry_free(centry
);
3266 /* flush the cache */
3267 void wcache_flush_cache(void)
3272 tdb_close(wcache
->tdb
);
3275 if (!winbindd_use_cache()) {
3279 /* when working offline we must not clear the cache on restart */
3280 wcache
->tdb
= tdb_open_log(state_path("winbindd_cache.tdb"),
3281 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3282 TDB_INCOMPATIBLE_HASH
|
3283 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3284 O_RDWR
|O_CREAT
, 0600);
3287 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3291 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
3293 DEBUG(10,("wcache_flush_cache success\n"));
3296 /* Count cached creds */
3298 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3301 int *cred_count
= (int*)state
;
3303 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3309 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
3311 struct winbind_cache
*cache
= get_cache(domain
);
3316 return NT_STATUS_INTERNAL_DB_ERROR
;
3319 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
3321 return NT_STATUS_OK
;
3325 struct cred_list
*prev
, *next
;
3330 static struct cred_list
*wcache_cred_list
;
3332 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3335 struct cred_list
*cred
;
3337 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3339 cred
= SMB_MALLOC_P(struct cred_list
);
3341 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3347 /* save a copy of the key */
3349 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
3350 DLIST_ADD(wcache_cred_list
, cred
);
3356 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
3358 struct winbind_cache
*cache
= get_cache(domain
);
3361 struct cred_list
*cred
, *oldest
= NULL
;
3364 return NT_STATUS_INTERNAL_DB_ERROR
;
3367 /* we possibly already have an entry */
3368 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
3370 fstring key_str
, tmp
;
3372 DEBUG(11,("we already have an entry, deleting that\n"));
3374 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
3376 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3378 return NT_STATUS_OK
;
3381 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
3383 return NT_STATUS_OK
;
3384 } else if ((ret
< 0) || (wcache_cred_list
== NULL
)) {
3385 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3388 ZERO_STRUCTP(oldest
);
3390 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
3395 data
= tdb_fetch_compat(cache
->tdb
, string_tdb_data(cred
->name
));
3397 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3399 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3403 t
= IVAL(data
.dptr
, 0);
3404 SAFE_FREE(data
.dptr
);
3407 oldest
= SMB_MALLOC_P(struct cred_list
);
3408 if (oldest
== NULL
) {
3409 status
= NT_STATUS_NO_MEMORY
;
3413 fstrcpy(oldest
->name
, cred
->name
);
3414 oldest
->created
= t
;
3418 if (t
< oldest
->created
) {
3419 fstrcpy(oldest
->name
, cred
->name
);
3420 oldest
->created
= t
;
3424 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3425 status
= NT_STATUS_OK
;
3427 status
= NT_STATUS_UNSUCCESSFUL
;
3430 SAFE_FREE(wcache_cred_list
);
3436 /* Change the global online/offline state. */
3437 bool set_global_winbindd_state_offline(void)
3441 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3443 /* Only go offline if someone has created
3444 the key "WINBINDD_OFFLINE" in the cache tdb. */
3446 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3447 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3451 if (!lp_winbind_offline_logon()) {
3452 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3456 if (global_winbindd_offline_state
) {
3457 /* Already offline. */
3461 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
3463 if (!data
.dptr
|| data
.dsize
!= 4) {
3464 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3465 SAFE_FREE(data
.dptr
);
3468 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3469 global_winbindd_offline_state
= true;
3470 SAFE_FREE(data
.dptr
);
3475 void set_global_winbindd_state_online(void)
3477 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3479 if (!lp_winbind_offline_logon()) {
3480 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3484 if (!global_winbindd_offline_state
) {
3485 /* Already online. */
3488 global_winbindd_offline_state
= false;
3494 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3495 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3498 bool get_global_winbindd_state_offline(void)
3500 return global_winbindd_offline_state
;
3503 /***********************************************************************
3504 Validate functions for all possible cache tdb keys.
3505 ***********************************************************************/
3507 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3508 struct tdb_validation_status
*state
)
3510 struct cache_entry
*centry
;
3512 centry
= SMB_XMALLOC_P(struct cache_entry
);
3513 centry
->data
= (unsigned char *)memdup(data
.dptr
, data
.dsize
);
3514 if (!centry
->data
) {
3518 centry
->len
= data
.dsize
;
3521 if (centry
->len
< 16) {
3522 /* huh? corrupt cache? */
3523 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3524 "(len < 16) ?\n", kstr
));
3525 centry_free(centry
);
3526 state
->bad_entry
= true;
3527 state
->success
= false;
3531 centry
->status
= NT_STATUS(centry_uint32(centry
));
3532 centry
->sequence_number
= centry_uint32(centry
);
3533 centry
->timeout
= centry_uint64_t(centry
);
3537 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3538 struct tdb_validation_status
*state
)
3540 if (dbuf
.dsize
!= 8) {
3541 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3542 keystr
, (unsigned int)dbuf
.dsize
));
3543 state
->bad_entry
= true;
3549 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3550 struct tdb_validation_status
*state
)
3552 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3557 (void)centry_uint32(centry
);
3558 if (NT_STATUS_IS_OK(centry
->status
)) {
3560 (void)centry_sid(centry
, &sid
);
3563 centry_free(centry
);
3565 if (!(state
->success
)) {
3568 DEBUG(10,("validate_ns: %s ok\n", keystr
));
3572 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3573 struct tdb_validation_status
*state
)
3575 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3580 if (NT_STATUS_IS_OK(centry
->status
)) {
3581 (void)centry_uint32(centry
);
3582 (void)centry_string(centry
, mem_ctx
);
3583 (void)centry_string(centry
, mem_ctx
);
3586 centry_free(centry
);
3588 if (!(state
->success
)) {
3591 DEBUG(10,("validate_sn: %s ok\n", keystr
));
3595 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3596 struct tdb_validation_status
*state
)
3598 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3605 (void)centry_string(centry
, mem_ctx
);
3606 (void)centry_string(centry
, mem_ctx
);
3607 (void)centry_string(centry
, mem_ctx
);
3608 (void)centry_string(centry
, mem_ctx
);
3609 (void)centry_uint32(centry
);
3610 (void)centry_sid(centry
, &sid
);
3611 (void)centry_sid(centry
, &sid
);
3613 centry_free(centry
);
3615 if (!(state
->success
)) {
3618 DEBUG(10,("validate_u: %s ok\n", keystr
));
3622 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3623 struct tdb_validation_status
*state
)
3625 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3631 (void)centry_nttime(centry
);
3632 (void)centry_nttime(centry
);
3633 (void)centry_uint16(centry
);
3635 centry_free(centry
);
3637 if (!(state
->success
)) {
3640 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3644 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3645 struct tdb_validation_status
*state
)
3647 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3653 (void)centry_uint16(centry
);
3654 (void)centry_uint16(centry
);
3655 (void)centry_uint32(centry
);
3656 (void)centry_nttime(centry
);
3657 (void)centry_nttime(centry
);
3659 centry_free(centry
);
3661 if (!(state
->success
)) {
3664 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3668 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3669 struct tdb_validation_status
*state
)
3671 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3677 (void)centry_time(centry
);
3678 (void)centry_hash16(centry
, mem_ctx
);
3680 /* We only have 17 bytes more data in the salted cred case. */
3681 if (centry
->len
- centry
->ofs
== 17) {
3682 (void)centry_hash16(centry
, mem_ctx
);
3685 centry_free(centry
);
3687 if (!(state
->success
)) {
3690 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3694 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3695 struct tdb_validation_status
*state
)
3697 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3698 int32 num_entries
, i
;
3704 num_entries
= (int32
)centry_uint32(centry
);
3706 for (i
=0; i
< num_entries
; i
++) {
3708 (void)centry_string(centry
, mem_ctx
);
3709 (void)centry_string(centry
, mem_ctx
);
3710 (void)centry_string(centry
, mem_ctx
);
3711 (void)centry_string(centry
, mem_ctx
);
3712 (void)centry_sid(centry
, &sid
);
3713 (void)centry_sid(centry
, &sid
);
3716 centry_free(centry
);
3718 if (!(state
->success
)) {
3721 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3725 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3726 struct tdb_validation_status
*state
)
3728 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3729 int32 num_entries
, i
;
3735 num_entries
= centry_uint32(centry
);
3737 for (i
=0; i
< num_entries
; i
++) {
3738 (void)centry_string(centry
, mem_ctx
);
3739 (void)centry_string(centry
, mem_ctx
);
3740 (void)centry_uint32(centry
);
3743 centry_free(centry
);
3745 if (!(state
->success
)) {
3748 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3752 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3753 struct tdb_validation_status
*state
)
3755 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3756 int32 num_groups
, i
;
3762 num_groups
= centry_uint32(centry
);
3764 for (i
=0; i
< num_groups
; i
++) {
3766 centry_sid(centry
, &sid
);
3769 centry_free(centry
);
3771 if (!(state
->success
)) {
3774 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3778 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3779 struct tdb_validation_status
*state
)
3781 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3782 int32 num_aliases
, i
;
3788 num_aliases
= centry_uint32(centry
);
3790 for (i
=0; i
< num_aliases
; i
++) {
3791 (void)centry_uint32(centry
);
3794 centry_free(centry
);
3796 if (!(state
->success
)) {
3799 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3803 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3804 struct tdb_validation_status
*state
)
3806 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3813 num_names
= centry_uint32(centry
);
3815 for (i
=0; i
< num_names
; i
++) {
3817 centry_sid(centry
, &sid
);
3818 (void)centry_string(centry
, mem_ctx
);
3819 (void)centry_uint32(centry
);
3822 centry_free(centry
);
3824 if (!(state
->success
)) {
3827 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3831 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3832 struct tdb_validation_status
*state
)
3834 /* Can't say anything about this other than must be nonzero. */
3835 if (dbuf
.dsize
== 0) {
3836 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3838 state
->bad_entry
= true;
3839 state
->success
= false;
3843 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3847 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3848 struct tdb_validation_status
*state
)
3850 /* Can't say anything about this other than must be nonzero. */
3851 if (dbuf
.dsize
== 0) {
3852 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3854 state
->bad_entry
= true;
3855 state
->success
= false;
3859 DEBUG(10,("validate_de: %s ok\n", keystr
));
3863 static int validate_pwinfo(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3864 TDB_DATA dbuf
, struct tdb_validation_status
*state
)
3866 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3872 (void)centry_string(centry
, mem_ctx
);
3873 (void)centry_string(centry
, mem_ctx
);
3874 (void)centry_string(centry
, mem_ctx
);
3875 (void)centry_uint32(centry
);
3877 centry_free(centry
);
3879 if (!(state
->success
)) {
3882 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3886 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3888 struct tdb_validation_status
*state
)
3890 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3896 (void)centry_string( centry
, mem_ctx
);
3898 centry_free(centry
);
3900 if (!(state
->success
)) {
3903 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3907 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3909 struct tdb_validation_status
*state
)
3911 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3917 (void)centry_string( centry
, mem_ctx
);
3919 centry_free(centry
);
3921 if (!(state
->success
)) {
3924 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3928 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3930 struct tdb_validation_status
*state
)
3932 if (dbuf
.dsize
== 0) {
3933 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3934 "key %s (len ==0) ?\n", keystr
));
3935 state
->bad_entry
= true;
3936 state
->success
= false;
3940 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3941 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3945 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3946 struct tdb_validation_status
*state
)
3948 if (dbuf
.dsize
!= 4) {
3949 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3950 keystr
, (unsigned int)dbuf
.dsize
));
3951 state
->bad_entry
= true;
3952 state
->success
= false;
3955 DEBUG(10,("validate_offline: %s ok\n", keystr
));
3959 static int validate_ndr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3960 struct tdb_validation_status
*state
)
3963 * Ignore validation for now. The proper way to do this is with a
3964 * checksum. Just pure parsing does not really catch much.
3969 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3970 struct tdb_validation_status
*state
)
3972 if (dbuf
.dsize
!= 4) {
3973 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3974 "key %s (len %u != 4) ?\n",
3975 keystr
, (unsigned int)dbuf
.dsize
));
3976 state
->bad_entry
= true;
3977 state
->success
= false;
3981 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
3985 /***********************************************************************
3986 A list of all possible cache tdb keys with associated validation
3988 ***********************************************************************/
3990 struct key_val_struct
{
3991 const char *keyname
;
3992 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
3994 {"SEQNUM/", validate_seqnum
},
3995 {"NS/", validate_ns
},
3996 {"SN/", validate_sn
},
3998 {"LOC_POL/", validate_loc_pol
},
3999 {"PWD_POL/", validate_pwd_pol
},
4000 {"CRED/", validate_cred
},
4001 {"UL/", validate_ul
},
4002 {"GL/", validate_gl
},
4003 {"UG/", validate_ug
},
4004 {"UA", validate_ua
},
4005 {"GM/", validate_gm
},
4006 {"DR/", validate_dr
},
4007 {"DE/", validate_de
},
4008 {"NSS/PWINFO/", validate_pwinfo
},
4009 {"TRUSTDOMCACHE/", validate_trustdomcache
},
4010 {"NSS/NA/", validate_nss_na
},
4011 {"NSS/AN/", validate_nss_an
},
4012 {"WINBINDD_OFFLINE", validate_offline
},
4013 {"NDR/", validate_ndr
},
4014 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
4018 /***********************************************************************
4019 Function to look at every entry in the tdb and validate it as far as
4021 ***********************************************************************/
4023 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
4026 unsigned int max_key_len
= 1024;
4027 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
4029 /* Paranoia check. */
4030 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0) {
4031 max_key_len
= 1024 * 1024;
4033 if (kbuf
.dsize
> max_key_len
) {
4034 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4036 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
4040 for (i
= 0; key_val
[i
].keyname
; i
++) {
4041 size_t namelen
= strlen(key_val
[i
].keyname
);
4042 if (kbuf
.dsize
>= namelen
&& (
4043 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
4044 TALLOC_CTX
*mem_ctx
;
4048 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
4052 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
4053 keystr
[kbuf
.dsize
] = '\0';
4055 mem_ctx
= talloc_init("validate_ctx");
4061 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
4065 talloc_destroy(mem_ctx
);
4070 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4071 dump_data(0, (uint8
*)kbuf
.dptr
, kbuf
.dsize
);
4072 DEBUG(0,("data :\n"));
4073 dump_data(0, (uint8
*)dbuf
.dptr
, dbuf
.dsize
);
4074 v_state
->unknown_key
= true;
4075 v_state
->success
= false;
4076 return 1; /* terminate. */
4079 static void validate_panic(const char *const why
)
4081 DEBUG(0,("validating cache: would panic %s\n", why
));
4082 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4086 /***********************************************************************
4087 Try and validate every entry in the winbindd cache. If we fail here,
4088 delete the cache tdb and return non-zero.
4089 ***********************************************************************/
4091 int winbindd_validate_cache(void)
4094 const char *tdb_path
= state_path("winbindd_cache.tdb");
4095 TDB_CONTEXT
*tdb
= NULL
;
4097 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4098 smb_panic_fn
= validate_panic
;
4101 tdb
= tdb_open_log(tdb_path
,
4102 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
4103 TDB_INCOMPATIBLE_HASH
|
4104 ( lp_winbind_offline_logon()
4106 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
4110 DEBUG(0, ("winbindd_validate_cache: "
4111 "error opening/initializing tdb\n"));
4116 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
4119 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4120 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
4125 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4126 smb_panic_fn
= smb_panic
;
4130 /***********************************************************************
4131 Try and validate every entry in the winbindd cache.
4132 ***********************************************************************/
4134 int winbindd_validate_cache_nobackup(void)
4137 const char *tdb_path
= state_path("winbindd_cache.tdb");
4139 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4140 smb_panic_fn
= validate_panic
;
4143 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
4144 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
4146 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
4150 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4154 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4156 smb_panic_fn
= smb_panic
;
4160 bool winbindd_cache_validate_and_initialize(void)
4162 close_winbindd_cache();
4164 if (lp_winbind_offline_logon()) {
4165 if (winbindd_validate_cache() < 0) {
4166 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4167 "could be restored.\n"));
4171 return initialize_winbindd_cache();
4174 /*********************************************************************
4175 ********************************************************************/
4177 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
4178 struct winbindd_tdc_domain
**domains
,
4179 size_t *num_domains
)
4181 struct winbindd_tdc_domain
*list
= NULL
;
4184 bool set_only
= false;
4186 /* don't allow duplicates */
4191 for ( i
=0; i
< (*num_domains
); i
++ ) {
4192 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
4193 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4204 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, 1 );
4207 list
= talloc_realloc( *domains
, *domains
,
4208 struct winbindd_tdc_domain
,
4213 ZERO_STRUCT( list
[idx
] );
4219 list
[idx
].domain_name
= talloc_strdup( list
, new_dom
->name
);
4220 list
[idx
].dns_name
= talloc_strdup( list
, new_dom
->alt_name
);
4222 if ( !is_null_sid( &new_dom
->sid
) ) {
4223 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
4225 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
4228 if ( new_dom
->domain_flags
!= 0x0 )
4229 list
[idx
].trust_flags
= new_dom
->domain_flags
;
4231 if ( new_dom
->domain_type
!= 0x0 )
4232 list
[idx
].trust_type
= new_dom
->domain_type
;
4234 if ( new_dom
->domain_trust_attribs
!= 0x0 )
4235 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
4239 *num_domains
= idx
+ 1;
4245 /*********************************************************************
4246 ********************************************************************/
4248 static TDB_DATA
make_tdc_key( const char *domain_name
)
4250 char *keystr
= NULL
;
4251 TDB_DATA key
= { NULL
, 0 };
4253 if ( !domain_name
) {
4254 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4258 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
4261 key
= string_term_tdb_data(keystr
);
4266 /*********************************************************************
4267 ********************************************************************/
4269 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
4271 unsigned char **buf
)
4273 unsigned char *buffer
= NULL
;
4278 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4286 /* Store the number of array items first */
4287 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
4290 /* now pack each domain trust record */
4291 for ( i
=0; i
<num_domains
; i
++ ) {
4296 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4297 domains
[i
].domain_name
,
4298 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
4301 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
4302 domains
[i
].domain_name
,
4303 domains
[i
].dns_name
,
4304 sid_to_fstring(tmp
, &domains
[i
].sid
),
4305 domains
[i
].trust_flags
,
4306 domains
[i
].trust_attribs
,
4307 domains
[i
].trust_type
);
4310 if ( buflen
< len
) {
4312 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
4313 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4327 /*********************************************************************
4328 ********************************************************************/
4330 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
4331 struct winbindd_tdc_domain
**domains
)
4333 fstring domain_name
, dns_name
, sid_string
;
4334 uint32 type
, attribs
, flags
;
4338 struct winbindd_tdc_domain
*list
= NULL
;
4340 /* get the number of domains */
4341 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
4343 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4347 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, num_domains
);
4349 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4353 for ( i
=0; i
<num_domains
; i
++ ) {
4354 len
+= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
4363 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4364 TALLOC_FREE( list
);
4368 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4369 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4370 domain_name
, dns_name
, sid_string
,
4371 flags
, attribs
, type
));
4373 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
4374 list
[i
].dns_name
= talloc_strdup( list
, dns_name
);
4375 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
4376 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4379 list
[i
].trust_flags
= flags
;
4380 list
[i
].trust_attribs
= attribs
;
4381 list
[i
].trust_type
= type
;
4389 /*********************************************************************
4390 ********************************************************************/
4392 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
4394 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4395 TDB_DATA data
= { NULL
, 0 };
4401 /* See if we were asked to delete the cache entry */
4404 ret
= tdb_delete( wcache
->tdb
, key
);
4408 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4415 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4418 SAFE_FREE( data
.dptr
);
4419 SAFE_FREE( key
.dptr
);
4421 return ( ret
== 0 );
4424 /*********************************************************************
4425 ********************************************************************/
4427 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4429 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4430 TDB_DATA data
= { NULL
, 0 };
4438 data
= tdb_fetch_compat( wcache
->tdb
, key
);
4440 SAFE_FREE( key
.dptr
);
4445 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4447 SAFE_FREE( data
.dptr
);
4455 /*********************************************************************
4456 ********************************************************************/
4458 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4460 struct winbindd_tdc_domain
*dom_list
= NULL
;
4461 size_t num_domains
= 0;
4464 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4465 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4466 domain
->name
, domain
->alt_name
,
4467 sid_string_dbg(&domain
->sid
),
4468 domain
->domain_flags
,
4469 domain
->domain_trust_attribs
,
4470 domain
->domain_type
));
4472 if ( !init_wcache() ) {
4476 /* fetch the list */
4478 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4480 /* add the new domain */
4482 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4486 /* pack the domain */
4488 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4496 TALLOC_FREE( dom_list
);
4501 /*********************************************************************
4502 ********************************************************************/
4504 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4506 struct winbindd_tdc_domain
*dom_list
= NULL
;
4507 size_t num_domains
= 0;
4509 struct winbindd_tdc_domain
*d
= NULL
;
4511 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4513 if ( !init_wcache() ) {
4517 /* fetch the list */
4519 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4521 for ( i
=0; i
<num_domains
; i
++ ) {
4522 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4523 strequal(name
, dom_list
[i
].dns_name
) )
4525 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4528 d
= talloc( ctx
, struct winbindd_tdc_domain
);
4532 d
->domain_name
= talloc_strdup( d
, dom_list
[i
].domain_name
);
4533 d
->dns_name
= talloc_strdup( d
, dom_list
[i
].dns_name
);
4534 sid_copy( &d
->sid
, &dom_list
[i
].sid
);
4535 d
->trust_flags
= dom_list
[i
].trust_flags
;
4536 d
->trust_type
= dom_list
[i
].trust_type
;
4537 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
4543 TALLOC_FREE( dom_list
);
4548 /*********************************************************************
4549 ********************************************************************/
4551 struct winbindd_tdc_domain
*
4552 wcache_tdc_fetch_domainbysid(TALLOC_CTX
*ctx
,
4553 const struct dom_sid
*sid
)
4555 struct winbindd_tdc_domain
*dom_list
= NULL
;
4556 size_t num_domains
= 0;
4558 struct winbindd_tdc_domain
*d
= NULL
;
4560 DEBUG(10,("wcache_tdc_fetch_domainbysid: Searching for domain %s\n",
4561 sid_string_dbg(sid
)));
4563 if (!init_wcache()) {
4567 /* fetch the list */
4569 wcache_tdc_fetch_list(&dom_list
, &num_domains
);
4571 for (i
= 0; i
<num_domains
; i
++) {
4572 if (dom_sid_equal(sid
, &(dom_list
[i
].sid
))) {
4573 DEBUG(10, ("wcache_tdc_fetch_domainbysid: "
4574 "Found domain %s for SID %s\n",
4575 dom_list
[i
].domain_name
,
4576 sid_string_dbg(sid
)));
4578 d
= talloc(ctx
, struct winbindd_tdc_domain
);
4582 d
->domain_name
= talloc_strdup(d
,
4583 dom_list
[i
].domain_name
);
4585 d
->dns_name
= talloc_strdup(d
, dom_list
[i
].dns_name
);
4586 sid_copy(&d
->sid
, &dom_list
[i
].sid
);
4587 d
->trust_flags
= dom_list
[i
].trust_flags
;
4588 d
->trust_type
= dom_list
[i
].trust_type
;
4589 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
4595 TALLOC_FREE(dom_list
);
4601 /*********************************************************************
4602 ********************************************************************/
4604 void wcache_tdc_clear( void )
4606 if ( !init_wcache() )
4609 wcache_tdc_store_list( NULL
, 0 );
4615 /*********************************************************************
4616 ********************************************************************/
4618 static void wcache_save_user_pwinfo(struct winbindd_domain
*domain
,
4620 const struct dom_sid
*user_sid
,
4621 const char *homedir
,
4626 struct cache_entry
*centry
;
4629 if ( (centry
= centry_start(domain
, status
)) == NULL
)
4632 centry_put_string( centry
, homedir
);
4633 centry_put_string( centry
, shell
);
4634 centry_put_string( centry
, gecos
);
4635 centry_put_uint32( centry
, gid
);
4637 centry_end(centry
, "NSS/PWINFO/%s", sid_to_fstring(tmp
, user_sid
) );
4639 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid
) ));
4641 centry_free(centry
);
4646 NTSTATUS
nss_get_info_cached( struct winbindd_domain
*domain
,
4647 const struct dom_sid
*user_sid
,
4649 const char **homedir
, const char **shell
,
4650 const char **gecos
, gid_t
*p_gid
)
4652 struct winbind_cache
*cache
= get_cache(domain
);
4653 struct cache_entry
*centry
= NULL
;
4660 centry
= wcache_fetch(cache
, domain
, "NSS/PWINFO/%s",
4661 sid_to_fstring(tmp
, user_sid
));
4666 *homedir
= centry_string( centry
, ctx
);
4667 *shell
= centry_string( centry
, ctx
);
4668 *gecos
= centry_string( centry
, ctx
);
4669 *p_gid
= centry_uint32( centry
);
4671 centry_free(centry
);
4673 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4674 sid_string_dbg(user_sid
)));
4676 return NT_STATUS_OK
;
4680 nt_status
= nss_get_info( domain
->name
, user_sid
, ctx
,
4681 homedir
, shell
, gecos
, p_gid
);
4683 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status
)));
4685 if ( NT_STATUS_IS_OK(nt_status
) ) {
4686 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir
));
4687 DEBUGADD(10, ("\tshell = '%s'\n", *shell
));
4688 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos
));
4689 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid
));
4691 wcache_save_user_pwinfo( domain
, nt_status
, user_sid
,
4692 *homedir
, *shell
, *gecos
, *p_gid
);
4695 if ( NT_STATUS_EQUAL( nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
4696 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4698 set_domain_offline( domain
);
4706 /* the cache backend methods are exposed via this structure */
4707 struct winbindd_methods cache_methods
= {
4725 static bool wcache_ndr_key(TALLOC_CTX
*mem_ctx
, char *domain_name
,
4726 uint32_t opnum
, const DATA_BLOB
*req
,
4732 key
= talloc_asprintf(mem_ctx
, "NDR/%s/%d/", domain_name
, (int)opnum
);
4736 keylen
= talloc_get_size(key
) - 1;
4738 key
= talloc_realloc(mem_ctx
, key
, char, keylen
+ req
->length
);
4742 memcpy(key
+ keylen
, req
->data
, req
->length
);
4744 pkey
->dptr
= (uint8_t *)key
;
4745 pkey
->dsize
= talloc_get_size(key
);
4749 static bool wcache_opnum_cacheable(uint32_t opnum
)
4752 case NDR_WBINT_PING
:
4753 case NDR_WBINT_QUERYSEQUENCENUMBER
:
4754 case NDR_WBINT_ALLOCATEUID
:
4755 case NDR_WBINT_ALLOCATEGID
:
4756 case NDR_WBINT_CHECKMACHINEACCOUNT
:
4757 case NDR_WBINT_CHANGEMACHINEACCOUNT
:
4758 case NDR_WBINT_PINGDC
:
4764 bool wcache_fetch_ndr(TALLOC_CTX
*mem_ctx
, struct winbindd_domain
*domain
,
4765 uint32_t opnum
, const DATA_BLOB
*req
, DATA_BLOB
*resp
)
4770 if (!wcache_opnum_cacheable(opnum
) ||
4771 is_my_own_sam_domain(domain
) ||
4772 is_builtin_domain(domain
)) {
4776 if (wcache
->tdb
== NULL
) {
4780 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4783 data
= tdb_fetch_compat(wcache
->tdb
, key
);
4784 TALLOC_FREE(key
.dptr
);
4786 if (data
.dptr
== NULL
) {
4789 if (data
.dsize
< 12) {
4793 if (!is_domain_offline(domain
)) {
4794 uint32_t entry_seqnum
, dom_seqnum
, last_check
;
4795 uint64_t entry_timeout
;
4797 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
,
4801 entry_seqnum
= IVAL(data
.dptr
, 0);
4802 if (entry_seqnum
!= dom_seqnum
) {
4803 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4804 (int)entry_seqnum
));
4807 entry_timeout
= BVAL(data
.dptr
, 4);
4808 if (time(NULL
) > entry_timeout
) {
4809 DEBUG(10, ("Entry has timed out\n"));
4814 resp
->data
= (uint8_t *)talloc_memdup(mem_ctx
, data
.dptr
+ 12,
4816 if (resp
->data
== NULL
) {
4817 DEBUG(10, ("talloc failed\n"));
4820 resp
->length
= data
.dsize
- 12;
4824 SAFE_FREE(data
.dptr
);
4828 void wcache_store_ndr(struct winbindd_domain
*domain
, uint32_t opnum
,
4829 const DATA_BLOB
*req
, const DATA_BLOB
*resp
)
4832 uint32_t dom_seqnum
, last_check
;
4835 if (!wcache_opnum_cacheable(opnum
) ||
4836 is_my_own_sam_domain(domain
) ||
4837 is_builtin_domain(domain
)) {
4841 if (wcache
->tdb
== NULL
) {
4845 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
, &last_check
)) {
4846 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4851 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4855 timeout
= time(NULL
) + lp_winbind_cache_time();
4857 data
.dsize
= resp
->length
+ 12;
4858 data
.dptr
= talloc_array(key
.dptr
, uint8_t, data
.dsize
);
4859 if (data
.dptr
== NULL
) {
4863 SIVAL(data
.dptr
, 0, dom_seqnum
);
4864 SBVAL(data
.dptr
, 4, timeout
);
4865 memcpy(data
.dptr
+ 12, resp
->data
, resp
->length
);
4867 tdb_store(wcache
->tdb
, key
, data
, 0);
4870 TALLOC_FREE(key
.dptr
);