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_VER1 1 /* initial db version */
42 #define WINBINDD_CACHE_VER2 2 /* second version with timeouts for NDR entries */
44 #define WINBINDD_CACHE_VERSION WINBINDD_CACHE_VER2
45 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
47 extern struct winbindd_methods reconnect_methods
;
49 extern struct winbindd_methods ads_methods
;
51 extern struct winbindd_methods builtin_passdb_methods
;
52 extern struct winbindd_methods sam_passdb_methods
;
55 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
56 * Here are the list of entry types that are *not* stored
57 * as form struct cache_entry in the cache.
60 static const char *non_centry_keys
[] = {
63 WINBINDD_CACHE_VERSION_KEYSTR
,
67 /************************************************************************
68 Is this key a non-centry type ?
69 ************************************************************************/
71 static bool is_non_centry_key(TDB_DATA kbuf
)
75 if (kbuf
.dptr
== NULL
|| kbuf
.dsize
== 0) {
78 for (i
= 0; non_centry_keys
[i
] != NULL
; i
++) {
79 size_t namelen
= strlen(non_centry_keys
[i
]);
80 if (kbuf
.dsize
< namelen
) {
83 if (strncmp(non_centry_keys
[i
], (const char *)kbuf
.dptr
, namelen
) == 0) {
90 /* Global online/offline state - False when online. winbindd starts up online
91 and sets this to true if the first query fails and there's an entry in
92 the cache tdb telling us to stay offline. */
94 static bool global_winbindd_offline_state
;
96 struct winbind_cache
{
102 uint32 sequence_number
;
108 void (*smb_panic_fn
)(const char *const why
) = smb_panic
;
110 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
112 static struct winbind_cache
*wcache
;
114 /* get the winbind_cache structure */
115 static struct winbind_cache
*get_cache(struct winbindd_domain
*domain
)
117 struct winbind_cache
*ret
= wcache
;
119 /* We have to know what type of domain we are dealing with first. */
121 if (domain
->internal
) {
122 domain
->backend
= &builtin_passdb_methods
;
123 domain
->initialized
= True
;
126 if (strequal(domain
->name
, get_global_sam_name()) &&
127 sid_check_is_our_sam(&domain
->sid
)) {
128 domain
->backend
= &sam_passdb_methods
;
129 domain
->initialized
= True
;
132 if ( !domain
->initialized
) {
133 init_dc_connection( domain
);
137 OK. listen up becasue I'm only going to say this once.
138 We have the following scenarios to consider
139 (a) trusted AD domains on a Samba DC,
140 (b) trusted AD domains and we are joined to a non-kerberos domain
141 (c) trusted AD domains and we are joined to a kerberos (AD) domain
143 For (a) we can always contact the trusted domain using krb5
144 since we have the domain trust account password
146 For (b) we can only use RPC since we have no way of
147 getting a krb5 ticket in our own domain
149 For (c) we can always use krb5 since we have a kerberos trust
154 if (!domain
->backend
) {
156 struct winbindd_domain
*our_domain
= domain
;
158 /* find our domain first so we can figure out if we
159 are joined to a kerberized domain */
161 if ( !domain
->primary
)
162 our_domain
= find_our_domain();
164 if ((our_domain
->active_directory
|| IS_DC
)
165 && domain
->active_directory
166 && !lp_winbind_rpc_only()) {
167 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain
->name
));
168 domain
->backend
= &ads_methods
;
170 #endif /* HAVE_ADS */
171 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain
->name
));
172 domain
->backend
= &reconnect_methods
;
175 #endif /* HAVE_ADS */
181 ret
= SMB_XMALLOC_P(struct winbind_cache
);
185 wcache_flush_cache();
191 free a centry structure
193 static void centry_free(struct cache_entry
*centry
)
197 SAFE_FREE(centry
->data
);
201 static bool centry_check_bytes(struct cache_entry
*centry
, size_t nbytes
)
203 if (centry
->len
- centry
->ofs
< nbytes
) {
204 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
205 (unsigned int)nbytes
,
206 centry
->len
- centry
->ofs
));
213 pull a uint64_t from a cache entry
215 static uint64_t centry_uint64_t(struct cache_entry
*centry
)
219 if (!centry_check_bytes(centry
, 8)) {
220 smb_panic_fn("centry_uint64_t");
222 ret
= BVAL(centry
->data
, centry
->ofs
);
228 pull a uint32 from a cache entry
230 static uint32
centry_uint32(struct cache_entry
*centry
)
234 if (!centry_check_bytes(centry
, 4)) {
235 smb_panic_fn("centry_uint32");
237 ret
= IVAL(centry
->data
, centry
->ofs
);
243 pull a uint16 from a cache entry
245 static uint16
centry_uint16(struct cache_entry
*centry
)
248 if (!centry_check_bytes(centry
, 2)) {
249 smb_panic_fn("centry_uint16");
251 ret
= SVAL(centry
->data
, centry
->ofs
);
257 pull a uint8 from a cache entry
259 static uint8
centry_uint8(struct cache_entry
*centry
)
262 if (!centry_check_bytes(centry
, 1)) {
263 smb_panic_fn("centry_uint8");
265 ret
= CVAL(centry
->data
, centry
->ofs
);
271 pull a NTTIME from a cache entry
273 static NTTIME
centry_nttime(struct cache_entry
*centry
)
276 if (!centry_check_bytes(centry
, 8)) {
277 smb_panic_fn("centry_nttime");
279 ret
= IVAL(centry
->data
, centry
->ofs
);
281 ret
+= (uint64
)IVAL(centry
->data
, centry
->ofs
) << 32;
287 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
289 static time_t centry_time(struct cache_entry
*centry
)
291 return (time_t)centry_nttime(centry
);
294 /* pull a string from a cache entry, using the supplied
297 static char *centry_string(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
302 len
= centry_uint8(centry
);
305 /* a deliberate NULL string */
309 if (!centry_check_bytes(centry
, (size_t)len
)) {
310 smb_panic_fn("centry_string");
313 ret
= talloc_array(mem_ctx
, char, len
+1);
315 smb_panic_fn("centry_string out of memory\n");
317 memcpy(ret
,centry
->data
+ centry
->ofs
, len
);
323 /* pull a hash16 from a cache entry, using the supplied
326 static char *centry_hash16(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
331 len
= centry_uint8(centry
);
334 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
339 if (!centry_check_bytes(centry
, 16)) {
343 ret
= talloc_array(mem_ctx
, char, 16);
345 smb_panic_fn("centry_hash out of memory\n");
347 memcpy(ret
,centry
->data
+ centry
->ofs
, 16);
352 /* pull a sid from a cache entry, using the supplied
355 static bool centry_sid(struct cache_entry
*centry
, struct dom_sid
*sid
)
360 sid_string
= centry_string(centry
, talloc_tos());
361 if (sid_string
== NULL
) {
364 ret
= string_to_sid(sid
, sid_string
);
365 TALLOC_FREE(sid_string
);
371 pull a NTSTATUS from a cache entry
373 static NTSTATUS
centry_ntstatus(struct cache_entry
*centry
)
377 status
= NT_STATUS(centry_uint32(centry
));
382 /* the server is considered down if it can't give us a sequence number */
383 static bool wcache_server_down(struct winbindd_domain
*domain
)
390 ret
= (domain
->sequence_number
== DOM_SEQUENCE_NONE
);
393 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
398 static bool wcache_fetch_seqnum(const char *domain_name
, uint32_t *seqnum
,
399 uint32_t *last_seq_check
)
404 if (wcache
->tdb
== NULL
) {
405 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
409 key
= talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name
);
411 DEBUG(10, ("talloc failed\n"));
415 data
= tdb_fetch_bystring(wcache
->tdb
, key
);
418 if (data
.dptr
== NULL
) {
419 DEBUG(10, ("wcache_fetch_seqnum: %s not found\n",
423 if (data
.dsize
!= 8) {
424 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
426 SAFE_FREE(data
.dptr
);
430 *seqnum
= IVAL(data
.dptr
, 0);
431 *last_seq_check
= IVAL(data
.dptr
, 4);
432 SAFE_FREE(data
.dptr
);
437 static NTSTATUS
fetch_cache_seqnum( struct winbindd_domain
*domain
, time_t now
)
439 uint32 last_check
, time_diff
;
441 if (!wcache_fetch_seqnum(domain
->name
, &domain
->sequence_number
,
443 return NT_STATUS_UNSUCCESSFUL
;
445 domain
->last_seq_check
= last_check
;
447 /* have we expired? */
449 time_diff
= now
- domain
->last_seq_check
;
450 if ( time_diff
> lp_winbind_cache_time() ) {
451 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
452 domain
->name
, domain
->sequence_number
,
453 (uint32
)domain
->last_seq_check
));
454 return NT_STATUS_UNSUCCESSFUL
;
457 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
458 domain
->name
, domain
->sequence_number
,
459 (uint32
)domain
->last_seq_check
));
464 bool wcache_store_seqnum(const char *domain_name
, uint32_t seqnum
,
465 time_t last_seq_check
)
471 if (wcache
->tdb
== NULL
) {
472 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
476 key_str
= talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name
);
477 if (key_str
== NULL
) {
478 DEBUG(10, ("talloc_asprintf failed\n"));
482 SIVAL(buf
, 0, seqnum
);
483 SIVAL(buf
, 4, last_seq_check
);
485 ret
= tdb_store_bystring(wcache
->tdb
, key_str
,
486 make_tdb_data(buf
, sizeof(buf
)), TDB_REPLACE
);
487 TALLOC_FREE(key_str
);
489 DEBUG(10, ("tdb_store_bystring failed: %s\n",
490 tdb_errorstr_compat(wcache
->tdb
)));
491 TALLOC_FREE(key_str
);
495 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
496 domain_name
, seqnum
, (unsigned)last_seq_check
));
501 static bool store_cache_seqnum( struct winbindd_domain
*domain
)
503 return wcache_store_seqnum(domain
->name
, domain
->sequence_number
,
504 domain
->last_seq_check
);
508 refresh the domain sequence number. If force is true
509 then always refresh it, no matter how recently we fetched it
512 static void refresh_sequence_number(struct winbindd_domain
*domain
, bool force
)
516 time_t t
= time(NULL
);
517 unsigned cache_time
= lp_winbind_cache_time();
519 if (is_domain_offline(domain
)) {
525 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
526 /* trying to reconnect is expensive, don't do it too often */
527 if (domain
->sequence_number
== DOM_SEQUENCE_NONE
) {
532 time_diff
= t
- domain
->last_seq_check
;
534 /* see if we have to refetch the domain sequence number */
535 if (!force
&& (time_diff
< cache_time
) &&
536 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
537 NT_STATUS_IS_OK(domain
->last_status
)) {
538 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain
->name
));
542 /* try to get the sequence number from the tdb cache first */
543 /* this will update the timestamp as well */
545 status
= fetch_cache_seqnum( domain
, t
);
546 if (NT_STATUS_IS_OK(status
) &&
547 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
548 NT_STATUS_IS_OK(domain
->last_status
)) {
552 /* important! make sure that we know if this is a native
553 mode domain or not. And that we can contact it. */
555 if ( winbindd_can_contact_domain( domain
) ) {
556 status
= domain
->backend
->sequence_number(domain
,
557 &domain
->sequence_number
);
559 /* just use the current time */
560 status
= NT_STATUS_OK
;
561 domain
->sequence_number
= time(NULL
);
565 /* the above call could have set our domain->backend to NULL when
566 * coming from offline to online mode, make sure to reinitialize the
567 * backend - Guenther */
570 if (!NT_STATUS_IS_OK(status
)) {
571 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status
)));
572 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
575 domain
->last_status
= status
;
576 domain
->last_seq_check
= time(NULL
);
578 /* save the new sequence number in the cache */
579 store_cache_seqnum( domain
);
582 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
583 domain
->name
, domain
->sequence_number
));
589 decide if a cache entry has expired
591 static bool centry_expired(struct winbindd_domain
*domain
, const char *keystr
, struct cache_entry
*centry
)
593 /* If we've been told to be offline - stay in that state... */
594 if (lp_winbind_offline_logon() && global_winbindd_offline_state
) {
595 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
596 keystr
, domain
->name
));
600 /* when the domain is offline return the cached entry.
601 * This deals with transient offline states... */
603 if (!domain
->online
) {
604 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
605 keystr
, domain
->name
));
609 /* if the server is OK and our cache entry came from when it was down then
610 the entry is invalid */
611 if ((domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
612 (centry
->sequence_number
== DOM_SEQUENCE_NONE
)) {
613 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
614 keystr
, domain
->name
));
618 /* if the server is down or the cache entry is not older than the
619 current sequence number or it did not timeout then it is OK */
620 if (wcache_server_down(domain
)
621 || ((centry
->sequence_number
== domain
->sequence_number
)
622 && (centry
->timeout
> time(NULL
)))) {
623 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
624 keystr
, domain
->name
));
628 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
629 keystr
, domain
->name
));
635 static struct cache_entry
*wcache_fetch_raw(char *kstr
)
638 struct cache_entry
*centry
;
641 key
= string_tdb_data(kstr
);
642 data
= tdb_fetch_compat(wcache
->tdb
, key
);
648 centry
= SMB_XMALLOC_P(struct cache_entry
);
649 centry
->data
= (unsigned char *)data
.dptr
;
650 centry
->len
= data
.dsize
;
653 if (centry
->len
< 16) {
654 /* huh? corrupt cache? */
655 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s "
656 "(len < 16)?\n", kstr
));
661 centry
->status
= centry_ntstatus(centry
);
662 centry
->sequence_number
= centry_uint32(centry
);
663 centry
->timeout
= centry_uint64_t(centry
);
668 static bool is_my_own_sam_domain(struct winbindd_domain
*domain
)
670 if (strequal(domain
->name
, get_global_sam_name()) &&
671 sid_check_is_our_sam(&domain
->sid
)) {
678 static bool is_builtin_domain(struct winbindd_domain
*domain
)
680 if (strequal(domain
->name
, "BUILTIN") &&
681 sid_check_is_builtin(&domain
->sid
)) {
689 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
690 number and return status
692 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
693 struct winbindd_domain
*domain
,
694 const char *format
, ...) PRINTF_ATTRIBUTE(3,4);
695 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
696 struct winbindd_domain
*domain
,
697 const char *format
, ...)
701 struct cache_entry
*centry
;
703 if (!winbindd_use_cache() ||
704 is_my_own_sam_domain(domain
) ||
705 is_builtin_domain(domain
)) {
709 refresh_sequence_number(domain
, false);
711 va_start(ap
, format
);
712 smb_xvasprintf(&kstr
, format
, ap
);
715 centry
= wcache_fetch_raw(kstr
);
716 if (centry
== NULL
) {
721 if (centry_expired(domain
, kstr
, centry
)) {
723 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
724 kstr
, domain
->name
));
731 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
732 kstr
, domain
->name
));
738 static void wcache_delete(const char *format
, ...) PRINTF_ATTRIBUTE(1,2);
739 static void wcache_delete(const char *format
, ...)
745 va_start(ap
, format
);
746 smb_xvasprintf(&kstr
, format
, ap
);
749 key
= string_tdb_data(kstr
);
751 tdb_delete(wcache
->tdb
, key
);
756 make sure we have at least len bytes available in a centry
758 static void centry_expand(struct cache_entry
*centry
, uint32 len
)
760 if (centry
->len
- centry
->ofs
>= len
)
763 centry
->data
= SMB_REALLOC_ARRAY(centry
->data
, unsigned char,
766 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry
->len
));
767 smb_panic_fn("out of memory in centry_expand");
772 push a uint64_t into a centry
774 static void centry_put_uint64_t(struct cache_entry
*centry
, uint64_t v
)
776 centry_expand(centry
, 8);
777 SBVAL(centry
->data
, centry
->ofs
, v
);
782 push a uint32 into a centry
784 static void centry_put_uint32(struct cache_entry
*centry
, uint32 v
)
786 centry_expand(centry
, 4);
787 SIVAL(centry
->data
, centry
->ofs
, v
);
792 push a uint16 into a centry
794 static void centry_put_uint16(struct cache_entry
*centry
, uint16 v
)
796 centry_expand(centry
, 2);
797 SSVAL(centry
->data
, centry
->ofs
, v
);
802 push a uint8 into a centry
804 static void centry_put_uint8(struct cache_entry
*centry
, uint8 v
)
806 centry_expand(centry
, 1);
807 SCVAL(centry
->data
, centry
->ofs
, v
);
812 push a string into a centry
814 static void centry_put_string(struct cache_entry
*centry
, const char *s
)
819 /* null strings are marked as len 0xFFFF */
820 centry_put_uint8(centry
, 0xFF);
825 /* can't handle more than 254 char strings. Truncating is probably best */
827 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len
));
830 centry_put_uint8(centry
, len
);
831 centry_expand(centry
, len
);
832 memcpy(centry
->data
+ centry
->ofs
, s
, len
);
837 push a 16 byte hash into a centry - treat as 16 byte string.
839 static void centry_put_hash16(struct cache_entry
*centry
, const uint8 val
[16])
841 centry_put_uint8(centry
, 16);
842 centry_expand(centry
, 16);
843 memcpy(centry
->data
+ centry
->ofs
, val
, 16);
847 static void centry_put_sid(struct cache_entry
*centry
, const struct dom_sid
*sid
)
850 centry_put_string(centry
, sid_to_fstring(sid_string
, sid
));
855 put NTSTATUS into a centry
857 static void centry_put_ntstatus(struct cache_entry
*centry
, NTSTATUS status
)
859 uint32 status_value
= NT_STATUS_V(status
);
860 centry_put_uint32(centry
, status_value
);
865 push a NTTIME into a centry
867 static void centry_put_nttime(struct cache_entry
*centry
, NTTIME nt
)
869 centry_expand(centry
, 8);
870 SIVAL(centry
->data
, centry
->ofs
, nt
& 0xFFFFFFFF);
872 SIVAL(centry
->data
, centry
->ofs
, nt
>> 32);
877 push a time_t into a centry - use a 64 bit size.
878 NTTIME here is being used as a convenient 64-bit size.
880 static void centry_put_time(struct cache_entry
*centry
, time_t t
)
882 NTTIME nt
= (NTTIME
)t
;
883 centry_put_nttime(centry
, nt
);
887 start a centry for output. When finished, call centry_end()
889 struct cache_entry
*centry_start(struct winbindd_domain
*domain
, NTSTATUS status
)
891 struct cache_entry
*centry
;
896 centry
= SMB_XMALLOC_P(struct cache_entry
);
898 centry
->len
= 8192; /* reasonable default */
899 centry
->data
= SMB_XMALLOC_ARRAY(uint8
, centry
->len
);
901 centry
->sequence_number
= domain
->sequence_number
;
902 centry
->timeout
= lp_winbind_cache_time() + time(NULL
);
903 centry_put_ntstatus(centry
, status
);
904 centry_put_uint32(centry
, centry
->sequence_number
);
905 centry_put_uint64_t(centry
, centry
->timeout
);
910 finish a centry and write it to the tdb
912 static void centry_end(struct cache_entry
*centry
, const char *format
, ...) PRINTF_ATTRIBUTE(2,3);
913 static void centry_end(struct cache_entry
*centry
, const char *format
, ...)
919 if (!winbindd_use_cache()) {
923 va_start(ap
, format
);
924 smb_xvasprintf(&kstr
, format
, ap
);
927 key
= string_tdb_data(kstr
);
928 data
.dptr
= centry
->data
;
929 data
.dsize
= centry
->ofs
;
931 tdb_store(wcache
->tdb
, key
, data
, TDB_REPLACE
);
935 static void wcache_save_name_to_sid(struct winbindd_domain
*domain
,
936 NTSTATUS status
, const char *domain_name
,
937 const char *name
, const struct dom_sid
*sid
,
938 enum lsa_SidType type
)
940 struct cache_entry
*centry
;
943 centry
= centry_start(domain
, status
);
946 centry_put_uint32(centry
, type
);
947 centry_put_sid(centry
, sid
);
948 fstrcpy(uname
, name
);
949 (void)strupper_m(uname
);
950 centry_end(centry
, "NS/%s/%s", domain_name
, uname
);
951 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name
,
952 uname
, sid_string_dbg(sid
), nt_errstr(status
)));
956 static void wcache_save_sid_to_name(struct winbindd_domain
*domain
, NTSTATUS status
,
957 const struct dom_sid
*sid
, const char *domain_name
, const char *name
, enum lsa_SidType type
)
959 struct cache_entry
*centry
;
962 centry
= centry_start(domain
, status
);
966 if (NT_STATUS_IS_OK(status
)) {
967 centry_put_uint32(centry
, type
);
968 centry_put_string(centry
, domain_name
);
969 centry_put_string(centry
, name
);
972 centry_end(centry
, "SN/%s", sid_to_fstring(sid_string
, sid
));
973 DEBUG(10,("wcache_save_sid_to_name: %s -> %s\\%s (%s)\n", sid_string
,
974 domain_name
, name
, nt_errstr(status
)));
979 static void wcache_save_user(struct winbindd_domain
*domain
, NTSTATUS status
,
980 struct wbint_userinfo
*info
)
982 struct cache_entry
*centry
;
985 if (is_null_sid(&info
->user_sid
)) {
989 centry
= centry_start(domain
, status
);
992 centry_put_string(centry
, info
->acct_name
);
993 centry_put_string(centry
, info
->full_name
);
994 centry_put_string(centry
, info
->homedir
);
995 centry_put_string(centry
, info
->shell
);
996 centry_put_uint32(centry
, info
->primary_gid
);
997 centry_put_sid(centry
, &info
->user_sid
);
998 centry_put_sid(centry
, &info
->group_sid
);
999 centry_end(centry
, "U/%s", sid_to_fstring(sid_string
,
1001 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string
, info
->acct_name
));
1002 centry_free(centry
);
1005 static void wcache_save_lockout_policy(struct winbindd_domain
*domain
,
1007 struct samr_DomInfo12
*lockout_policy
)
1009 struct cache_entry
*centry
;
1011 centry
= centry_start(domain
, status
);
1015 centry_put_nttime(centry
, lockout_policy
->lockout_duration
);
1016 centry_put_nttime(centry
, lockout_policy
->lockout_window
);
1017 centry_put_uint16(centry
, lockout_policy
->lockout_threshold
);
1019 centry_end(centry
, "LOC_POL/%s", domain
->name
);
1021 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain
->name
));
1023 centry_free(centry
);
1028 static void wcache_save_password_policy(struct winbindd_domain
*domain
,
1030 struct samr_DomInfo1
*policy
)
1032 struct cache_entry
*centry
;
1034 centry
= centry_start(domain
, status
);
1038 centry_put_uint16(centry
, policy
->min_password_length
);
1039 centry_put_uint16(centry
, policy
->password_history_length
);
1040 centry_put_uint32(centry
, policy
->password_properties
);
1041 centry_put_nttime(centry
, policy
->max_password_age
);
1042 centry_put_nttime(centry
, policy
->min_password_age
);
1044 centry_end(centry
, "PWD_POL/%s", domain
->name
);
1046 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
1048 centry_free(centry
);
1051 /***************************************************************************
1052 ***************************************************************************/
1054 static void wcache_save_username_alias(struct winbindd_domain
*domain
,
1056 const char *name
, const char *alias
)
1058 struct cache_entry
*centry
;
1061 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1064 centry_put_string( centry
, alias
);
1066 fstrcpy(uname
, name
);
1067 (void)strupper_m(uname
);
1068 centry_end(centry
, "NSS/NA/%s", uname
);
1070 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name
, alias
));
1072 centry_free(centry
);
1075 static void wcache_save_alias_username(struct winbindd_domain
*domain
,
1077 const char *alias
, const char *name
)
1079 struct cache_entry
*centry
;
1082 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1085 centry_put_string( centry
, name
);
1087 fstrcpy(uname
, alias
);
1088 (void)strupper_m(uname
);
1089 centry_end(centry
, "NSS/AN/%s", uname
);
1091 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias
, name
));
1093 centry_free(centry
);
1096 /***************************************************************************
1097 ***************************************************************************/
1099 NTSTATUS
resolve_username_to_alias( TALLOC_CTX
*mem_ctx
,
1100 struct winbindd_domain
*domain
,
1101 const char *name
, char **alias
)
1103 struct winbind_cache
*cache
= get_cache(domain
);
1104 struct cache_entry
*centry
= NULL
;
1108 if ( domain
->internal
)
1109 return NT_STATUS_NOT_SUPPORTED
;
1114 if ( (upper_name
= SMB_STRDUP(name
)) == NULL
)
1115 return NT_STATUS_NO_MEMORY
;
1116 if (!strupper_m(upper_name
)) {
1118 return NT_STATUS_INVALID_PARAMETER
;
1121 centry
= wcache_fetch(cache
, domain
, "NSS/NA/%s", upper_name
);
1123 SAFE_FREE( upper_name
);
1128 status
= centry
->status
;
1130 if (!NT_STATUS_IS_OK(status
)) {
1131 centry_free(centry
);
1135 *alias
= centry_string( centry
, mem_ctx
);
1137 centry_free(centry
);
1139 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1140 name
, *alias
? *alias
: "(none)"));
1142 return (*alias
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1146 /* If its not in cache and we are offline, then fail */
1148 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1149 DEBUG(8,("resolve_username_to_alias: rejecting query "
1150 "in offline mode\n"));
1151 return NT_STATUS_NOT_FOUND
;
1154 status
= nss_map_to_alias( mem_ctx
, domain
->name
, name
, alias
);
1156 if ( NT_STATUS_IS_OK( status
) ) {
1157 wcache_save_username_alias(domain
, status
, name
, *alias
);
1160 if ( NT_STATUS_EQUAL( status
, NT_STATUS_NONE_MAPPED
) ) {
1161 wcache_save_username_alias(domain
, status
, name
, "(NULL)");
1164 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1165 nt_errstr(status
)));
1167 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1168 set_domain_offline( domain
);
1174 /***************************************************************************
1175 ***************************************************************************/
1177 NTSTATUS
resolve_alias_to_username( TALLOC_CTX
*mem_ctx
,
1178 struct winbindd_domain
*domain
,
1179 const char *alias
, char **name
)
1181 struct winbind_cache
*cache
= get_cache(domain
);
1182 struct cache_entry
*centry
= NULL
;
1186 if ( domain
->internal
)
1187 return NT_STATUS_NOT_SUPPORTED
;
1192 if ( (upper_name
= SMB_STRDUP(alias
)) == NULL
)
1193 return NT_STATUS_NO_MEMORY
;
1194 if (!strupper_m(upper_name
)) {
1196 return NT_STATUS_INVALID_PARAMETER
;
1199 centry
= wcache_fetch(cache
, domain
, "NSS/AN/%s", upper_name
);
1201 SAFE_FREE( upper_name
);
1206 status
= centry
->status
;
1208 if (!NT_STATUS_IS_OK(status
)) {
1209 centry_free(centry
);
1213 *name
= centry_string( centry
, mem_ctx
);
1215 centry_free(centry
);
1217 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1218 alias
, *name
? *name
: "(none)"));
1220 return (*name
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1224 /* If its not in cache and we are offline, then fail */
1226 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1227 DEBUG(8,("resolve_alias_to_username: rejecting query "
1228 "in offline mode\n"));
1229 return NT_STATUS_NOT_FOUND
;
1232 /* an alias cannot contain a domain prefix or '@' */
1234 if (strchr(alias
, '\\') || strchr(alias
, '@')) {
1235 DEBUG(10,("resolve_alias_to_username: skipping fully "
1236 "qualified name %s\n", alias
));
1237 return NT_STATUS_OBJECT_NAME_INVALID
;
1240 status
= nss_map_from_alias( mem_ctx
, domain
->name
, alias
, name
);
1242 if ( NT_STATUS_IS_OK( status
) ) {
1243 wcache_save_alias_username( domain
, status
, alias
, *name
);
1246 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1247 wcache_save_alias_username(domain
, status
, alias
, "(NULL)");
1250 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1251 nt_errstr(status
)));
1253 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1254 set_domain_offline( domain
);
1260 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
1262 struct winbind_cache
*cache
= get_cache(domain
);
1264 fstring key_str
, tmp
;
1268 return NT_STATUS_INTERNAL_DB_ERROR
;
1271 if (is_null_sid(sid
)) {
1272 return NT_STATUS_INVALID_SID
;
1275 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1276 return NT_STATUS_INVALID_SID
;
1279 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
1281 data
= tdb_fetch_compat(cache
->tdb
, string_tdb_data(key_str
));
1283 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1286 SAFE_FREE(data
.dptr
);
1287 return NT_STATUS_OK
;
1290 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1291 as new salted ones. */
1293 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
1294 TALLOC_CTX
*mem_ctx
,
1295 const struct dom_sid
*sid
,
1296 const uint8
**cached_nt_pass
,
1297 const uint8
**cached_salt
)
1299 struct winbind_cache
*cache
= get_cache(domain
);
1300 struct cache_entry
*centry
= NULL
;
1305 if (!winbindd_use_cache()) {
1306 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1310 return NT_STATUS_INTERNAL_DB_ERROR
;
1313 if (is_null_sid(sid
)) {
1314 return NT_STATUS_INVALID_SID
;
1317 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1318 return NT_STATUS_INVALID_SID
;
1321 /* Try and get a salted cred first. If we can't
1322 fall back to an unsalted cred. */
1324 centry
= wcache_fetch(cache
, domain
, "CRED/%s",
1325 sid_to_fstring(tmp
, sid
));
1327 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1328 sid_string_dbg(sid
)));
1329 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1332 /* In the salted case this isn't actually the nt_hash itself,
1333 but the MD5 of the salt + nt_hash. Let the caller
1334 sort this out. It can tell as we only return the cached_salt
1335 if we are returning a salted cred. */
1337 *cached_nt_pass
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1338 if (*cached_nt_pass
== NULL
) {
1341 sid_to_fstring(sidstr
, sid
);
1343 /* Bad (old) cred cache. Delete and pretend we
1345 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1347 wcache_delete("CRED/%s", sidstr
);
1348 centry_free(centry
);
1349 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1352 /* We only have 17 bytes more data in the salted cred case. */
1353 if (centry
->len
- centry
->ofs
== 17) {
1354 *cached_salt
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1356 *cached_salt
= NULL
;
1359 dump_data_pw("cached_nt_pass", *cached_nt_pass
, NT_HASH_LEN
);
1361 dump_data_pw("cached_salt", *cached_salt
, NT_HASH_LEN
);
1364 status
= centry
->status
;
1366 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1367 sid_string_dbg(sid
), nt_errstr(status
) ));
1369 centry_free(centry
);
1373 /* Store creds for a SID - only writes out new salted ones. */
1375 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1376 const struct dom_sid
*sid
,
1377 const uint8 nt_pass
[NT_HASH_LEN
])
1379 struct cache_entry
*centry
;
1382 uint8 cred_salt
[NT_HASH_LEN
];
1383 uint8 salted_hash
[NT_HASH_LEN
];
1385 if (is_null_sid(sid
)) {
1386 return NT_STATUS_INVALID_SID
;
1389 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1390 return NT_STATUS_INVALID_SID
;
1393 centry
= centry_start(domain
, NT_STATUS_OK
);
1395 return NT_STATUS_INTERNAL_DB_ERROR
;
1398 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1400 centry_put_time(centry
, time(NULL
));
1402 /* Create a salt and then salt the hash. */
1403 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1404 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1406 centry_put_hash16(centry
, salted_hash
);
1407 centry_put_hash16(centry
, cred_salt
);
1408 centry_end(centry
, "CRED/%s", sid_to_fstring(sid_string
, sid
));
1410 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1412 centry_free(centry
);
1414 return NT_STATUS_OK
;
1418 /* Query display info. This is the basic user list fn */
1419 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
1420 TALLOC_CTX
*mem_ctx
,
1421 uint32
*num_entries
,
1422 struct wbint_userinfo
**info
)
1424 struct winbind_cache
*cache
= get_cache(domain
);
1425 struct cache_entry
*centry
= NULL
;
1427 unsigned int i
, retry
;
1428 bool old_status
= domain
->online
;
1433 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1438 *num_entries
= centry_uint32(centry
);
1440 if (*num_entries
== 0)
1443 (*info
) = talloc_array(mem_ctx
, struct wbint_userinfo
, *num_entries
);
1445 smb_panic_fn("query_user_list out of memory");
1447 for (i
=0; i
<(*num_entries
); i
++) {
1448 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
1449 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
1450 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
1451 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
1452 centry_sid(centry
, &(*info
)[i
].user_sid
);
1453 centry_sid(centry
, &(*info
)[i
].group_sid
);
1457 status
= centry
->status
;
1459 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1460 domain
->name
, nt_errstr(status
) ));
1462 centry_free(centry
);
1469 /* Return status value returned by seq number check */
1471 if (!NT_STATUS_IS_OK(domain
->last_status
))
1472 return domain
->last_status
;
1474 /* Put the query_user_list() in a retry loop. There appears to be
1475 * some bug either with Windows 2000 or Samba's handling of large
1476 * rpc replies. This manifests itself as sudden disconnection
1477 * at a random point in the enumeration of a large (60k) user list.
1478 * The retry loop simply tries the operation again. )-: It's not
1479 * pretty but an acceptable workaround until we work out what the
1480 * real problem is. */
1485 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1488 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
1489 if (!NT_STATUS_IS_OK(status
)) {
1490 DEBUG(3, ("query_user_list: returned 0x%08x, "
1491 "retrying\n", NT_STATUS_V(status
)));
1493 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1494 DEBUG(3, ("query_user_list: flushing "
1495 "connection cache\n"));
1496 invalidate_cm_connection(&domain
->conn
);
1498 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1499 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1500 if (!domain
->internal
&& old_status
) {
1501 set_domain_offline(domain
);
1503 /* store partial response. */
1504 if (*num_entries
> 0) {
1506 * humm, what about the status used for cache?
1507 * Should it be NT_STATUS_OK?
1512 * domain is offline now, and there is no user entries,
1513 * try to fetch from cache again.
1515 if (cache
->tdb
&& !domain
->online
&& !domain
->internal
&& old_status
) {
1516 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1517 /* partial response... */
1521 goto do_fetch_cache
;
1528 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1532 refresh_sequence_number(domain
, false);
1533 if (!NT_STATUS_IS_OK(status
)) {
1536 centry
= centry_start(domain
, status
);
1539 centry_put_uint32(centry
, *num_entries
);
1540 for (i
=0; i
<(*num_entries
); i
++) {
1541 centry_put_string(centry
, (*info
)[i
].acct_name
);
1542 centry_put_string(centry
, (*info
)[i
].full_name
);
1543 centry_put_string(centry
, (*info
)[i
].homedir
);
1544 centry_put_string(centry
, (*info
)[i
].shell
);
1545 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1546 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1547 if (domain
->backend
&& domain
->backend
->consistent
) {
1548 /* when the backend is consistent we can pre-prime some mappings */
1549 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1551 (*info
)[i
].acct_name
,
1552 &(*info
)[i
].user_sid
,
1554 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1555 &(*info
)[i
].user_sid
,
1557 (*info
)[i
].acct_name
,
1559 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1562 centry_end(centry
, "UL/%s", domain
->name
);
1563 centry_free(centry
);
1569 /* list all domain groups */
1570 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
1571 TALLOC_CTX
*mem_ctx
,
1572 uint32
*num_entries
,
1573 struct wb_acct_info
**info
)
1575 struct winbind_cache
*cache
= get_cache(domain
);
1576 struct cache_entry
*centry
= NULL
;
1581 old_status
= domain
->online
;
1585 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1590 *num_entries
= centry_uint32(centry
);
1592 if (*num_entries
== 0)
1595 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1597 smb_panic_fn("enum_dom_groups out of memory");
1599 for (i
=0; i
<(*num_entries
); i
++) {
1600 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1601 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1602 (*info
)[i
].rid
= centry_uint32(centry
);
1606 status
= centry
->status
;
1608 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1609 domain
->name
, nt_errstr(status
) ));
1611 centry_free(centry
);
1618 /* Return status value returned by seq number check */
1620 if (!NT_STATUS_IS_OK(domain
->last_status
))
1621 return domain
->last_status
;
1623 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1626 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1628 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1629 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1630 if (!domain
->internal
&& old_status
) {
1631 set_domain_offline(domain
);
1635 !domain
->internal
&&
1637 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1639 goto do_fetch_cache
;
1644 refresh_sequence_number(domain
, false);
1645 if (!NT_STATUS_IS_OK(status
)) {
1648 centry
= centry_start(domain
, status
);
1651 centry_put_uint32(centry
, *num_entries
);
1652 for (i
=0; i
<(*num_entries
); i
++) {
1653 centry_put_string(centry
, (*info
)[i
].acct_name
);
1654 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1655 centry_put_uint32(centry
, (*info
)[i
].rid
);
1657 centry_end(centry
, "GL/%s/domain", domain
->name
);
1658 centry_free(centry
);
1664 /* list all domain groups */
1665 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
1666 TALLOC_CTX
*mem_ctx
,
1667 uint32
*num_entries
,
1668 struct wb_acct_info
**info
)
1670 struct winbind_cache
*cache
= get_cache(domain
);
1671 struct cache_entry
*centry
= NULL
;
1676 old_status
= domain
->online
;
1680 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1685 *num_entries
= centry_uint32(centry
);
1687 if (*num_entries
== 0)
1690 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1692 smb_panic_fn("enum_dom_groups out of memory");
1694 for (i
=0; i
<(*num_entries
); i
++) {
1695 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1696 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1697 (*info
)[i
].rid
= centry_uint32(centry
);
1702 /* If we are returning cached data and the domain controller
1703 is down then we don't know whether the data is up to date
1704 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1707 if (wcache_server_down(domain
)) {
1708 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1709 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1711 status
= centry
->status
;
1713 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1714 domain
->name
, nt_errstr(status
) ));
1716 centry_free(centry
);
1723 /* Return status value returned by seq number check */
1725 if (!NT_STATUS_IS_OK(domain
->last_status
))
1726 return domain
->last_status
;
1728 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1731 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1733 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1734 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1735 if (!domain
->internal
&& old_status
) {
1736 set_domain_offline(domain
);
1739 !domain
->internal
&&
1742 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1744 goto do_fetch_cache
;
1749 refresh_sequence_number(domain
, false);
1750 if (!NT_STATUS_IS_OK(status
)) {
1753 centry
= centry_start(domain
, status
);
1756 centry_put_uint32(centry
, *num_entries
);
1757 for (i
=0; i
<(*num_entries
); i
++) {
1758 centry_put_string(centry
, (*info
)[i
].acct_name
);
1759 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1760 centry_put_uint32(centry
, (*info
)[i
].rid
);
1762 centry_end(centry
, "GL/%s/local", domain
->name
);
1763 centry_free(centry
);
1769 NTSTATUS
wcache_name_to_sid(struct winbindd_domain
*domain
,
1770 const char *domain_name
,
1772 struct dom_sid
*sid
,
1773 enum lsa_SidType
*type
)
1775 struct winbind_cache
*cache
= get_cache(domain
);
1776 struct cache_entry
*centry
;
1780 if (cache
->tdb
== NULL
) {
1781 return NT_STATUS_NOT_FOUND
;
1784 uname
= talloc_strdup_upper(talloc_tos(), name
);
1785 if (uname
== NULL
) {
1786 return NT_STATUS_NO_MEMORY
;
1789 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1791 if (centry
== NULL
) {
1792 return NT_STATUS_NOT_FOUND
;
1795 status
= centry
->status
;
1796 if (NT_STATUS_IS_OK(status
)) {
1797 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1798 centry_sid(centry
, sid
);
1801 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1802 "%s\n", domain
->name
, nt_errstr(status
) ));
1804 centry_free(centry
);
1808 /* convert a single name to a sid in a domain */
1809 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
1810 TALLOC_CTX
*mem_ctx
,
1811 const char *domain_name
,
1814 struct dom_sid
*sid
,
1815 enum lsa_SidType
*type
)
1820 old_status
= domain
->online
;
1822 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1823 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1829 /* If the seq number check indicated that there is a problem
1830 * with this DC, then return that status... except for
1831 * access_denied. This is special because the dc may be in
1832 * "restrict anonymous = 1" mode, in which case it will deny
1833 * most unauthenticated operations, but *will* allow the LSA
1834 * name-to-sid that we try as a fallback. */
1836 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1837 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1838 return domain
->last_status
;
1840 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1843 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
,
1844 name
, flags
, sid
, type
);
1846 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1847 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1848 if (!domain
->internal
&& old_status
) {
1849 set_domain_offline(domain
);
1851 if (!domain
->internal
&&
1854 NTSTATUS cache_status
;
1855 cache_status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1856 return cache_status
;
1860 refresh_sequence_number(domain
, false);
1862 if (domain
->online
&&
1863 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1864 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1866 /* Only save the reverse mapping if this was not a UPN */
1867 if (!strchr(name
, '@')) {
1868 if (!strupper_m(discard_const_p(char, domain_name
))) {
1869 return NT_STATUS_INVALID_PARAMETER
;
1871 (void)strlower_m(discard_const_p(char, name
));
1872 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1879 NTSTATUS
wcache_sid_to_name(struct winbindd_domain
*domain
,
1880 const struct dom_sid
*sid
,
1881 TALLOC_CTX
*mem_ctx
,
1884 enum lsa_SidType
*type
)
1886 struct winbind_cache
*cache
= get_cache(domain
);
1887 struct cache_entry
*centry
;
1891 if (cache
->tdb
== NULL
) {
1892 return NT_STATUS_NOT_FOUND
;
1895 sid_string
= sid_string_tos(sid
);
1896 if (sid_string
== NULL
) {
1897 return NT_STATUS_NO_MEMORY
;
1900 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_string
);
1901 TALLOC_FREE(sid_string
);
1902 if (centry
== NULL
) {
1903 return NT_STATUS_NOT_FOUND
;
1906 if (NT_STATUS_IS_OK(centry
->status
)) {
1907 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1908 *domain_name
= centry_string(centry
, mem_ctx
);
1909 *name
= centry_string(centry
, mem_ctx
);
1912 status
= centry
->status
;
1913 centry_free(centry
);
1915 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1916 "%s\n", domain
->name
, nt_errstr(status
) ));
1921 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1923 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1924 TALLOC_CTX
*mem_ctx
,
1925 const struct dom_sid
*sid
,
1928 enum lsa_SidType
*type
)
1933 old_status
= domain
->online
;
1934 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
1936 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1941 *domain_name
= NULL
;
1943 /* If the seq number check indicated that there is a problem
1944 * with this DC, then return that status... except for
1945 * access_denied. This is special because the dc may be in
1946 * "restrict anonymous = 1" mode, in which case it will deny
1947 * most unauthenticated operations, but *will* allow the LSA
1948 * sid-to-name that we try as a fallback. */
1950 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1951 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1952 return domain
->last_status
;
1954 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1957 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1959 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1960 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1961 if (!domain
->internal
&& old_status
) {
1962 set_domain_offline(domain
);
1964 if (!domain
->internal
&&
1967 NTSTATUS cache_status
;
1968 cache_status
= wcache_sid_to_name(domain
, sid
, mem_ctx
,
1969 domain_name
, name
, type
);
1970 return cache_status
;
1974 refresh_sequence_number(domain
, false);
1975 if (!NT_STATUS_IS_OK(status
)) {
1978 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
1980 /* We can't save the name to sid mapping here, as with sid history a
1981 * later name2sid would give the wrong sid. */
1986 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
1987 TALLOC_CTX
*mem_ctx
,
1988 const struct dom_sid
*domain_sid
,
1993 enum lsa_SidType
**types
)
1995 struct winbind_cache
*cache
= get_cache(domain
);
1997 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
2002 old_status
= domain
->online
;
2003 *domain_name
= NULL
;
2011 if (num_rids
== 0) {
2012 return NT_STATUS_OK
;
2015 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2016 *types
= talloc_array(mem_ctx
, enum lsa_SidType
, num_rids
);
2018 if ((*names
== NULL
) || (*types
== NULL
)) {
2019 result
= NT_STATUS_NO_MEMORY
;
2023 have_mapped
= have_unmapped
= false;
2025 for (i
=0; i
<num_rids
; i
++) {
2027 struct cache_entry
*centry
;
2030 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2031 result
= NT_STATUS_INTERNAL_ERROR
;
2035 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2036 sid_to_fstring(tmp
, &sid
));
2041 (*types
)[i
] = SID_NAME_UNKNOWN
;
2042 (*names
)[i
] = talloc_strdup(*names
, "");
2044 if (NT_STATUS_IS_OK(centry
->status
)) {
2047 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2049 dom
= centry_string(centry
, mem_ctx
);
2050 if (*domain_name
== NULL
) {
2056 (*names
)[i
] = centry_string(centry
, *names
);
2058 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)
2059 || NT_STATUS_EQUAL(centry
->status
, STATUS_SOME_UNMAPPED
)) {
2060 have_unmapped
= true;
2063 /* something's definitely wrong */
2064 result
= centry
->status
;
2068 centry_free(centry
);
2072 return NT_STATUS_NONE_MAPPED
;
2074 if (!have_unmapped
) {
2075 return NT_STATUS_OK
;
2077 return STATUS_SOME_UNMAPPED
;
2081 TALLOC_FREE(*names
);
2082 TALLOC_FREE(*types
);
2084 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
2085 rids
, num_rids
, domain_name
,
2088 if (NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
2089 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2090 if (!domain
->internal
&& old_status
) {
2091 set_domain_offline(domain
);
2094 !domain
->internal
&&
2097 have_mapped
= have_unmapped
= false;
2099 for (i
=0; i
<num_rids
; i
++) {
2101 struct cache_entry
*centry
;
2104 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2105 result
= NT_STATUS_INTERNAL_ERROR
;
2109 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2110 sid_to_fstring(tmp
, &sid
));
2112 (*types
)[i
] = SID_NAME_UNKNOWN
;
2113 (*names
)[i
] = talloc_strdup(*names
, "");
2117 (*types
)[i
] = SID_NAME_UNKNOWN
;
2118 (*names
)[i
] = talloc_strdup(*names
, "");
2120 if (NT_STATUS_IS_OK(centry
->status
)) {
2123 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2125 dom
= centry_string(centry
, mem_ctx
);
2126 if (*domain_name
== NULL
) {
2132 (*names
)[i
] = centry_string(centry
, *names
);
2134 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)) {
2135 have_unmapped
= true;
2138 /* something's definitely wrong */
2139 result
= centry
->status
;
2143 centry_free(centry
);
2147 return NT_STATUS_NONE_MAPPED
;
2149 if (!have_unmapped
) {
2150 return NT_STATUS_OK
;
2152 return STATUS_SOME_UNMAPPED
;
2156 None of the queried rids has been found so save all negative entries
2158 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
2159 for (i
= 0; i
< num_rids
; i
++) {
2161 const char *name
= "";
2162 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
2163 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
2165 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2166 return NT_STATUS_INTERNAL_ERROR
;
2169 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2177 Some or all of the queried rids have been found.
2179 if (!NT_STATUS_IS_OK(result
) &&
2180 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
2184 refresh_sequence_number(domain
, false);
2186 for (i
=0; i
<num_rids
; i
++) {
2190 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2191 result
= NT_STATUS_INTERNAL_ERROR
;
2195 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
2196 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
2198 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2199 (*names
)[i
], (*types
)[i
]);
2205 TALLOC_FREE(*names
);
2206 TALLOC_FREE(*types
);
2210 NTSTATUS
wcache_query_user(struct winbindd_domain
*domain
,
2211 TALLOC_CTX
*mem_ctx
,
2212 const struct dom_sid
*user_sid
,
2213 struct wbint_userinfo
*info
)
2215 struct winbind_cache
*cache
= get_cache(domain
);
2216 struct cache_entry
*centry
= NULL
;
2220 if (cache
->tdb
== NULL
) {
2221 return NT_STATUS_NOT_FOUND
;
2224 sid_string
= sid_string_tos(user_sid
);
2225 if (sid_string
== NULL
) {
2226 return NT_STATUS_NO_MEMORY
;
2229 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string
);
2230 TALLOC_FREE(sid_string
);
2231 if (centry
== NULL
) {
2232 return NT_STATUS_NOT_FOUND
;
2236 * If we have an access denied cache entry and a cached info3
2237 * in the samlogon cache then do a query. This will force the
2238 * rpc back end to return the info3 data.
2241 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
) &&
2242 netsamlogon_cache_have(user_sid
)) {
2243 DEBUG(10, ("query_user: cached access denied and have cached "
2245 domain
->last_status
= NT_STATUS_OK
;
2246 centry_free(centry
);
2247 return NT_STATUS_NOT_FOUND
;
2250 /* if status is not ok then this is a negative hit
2251 and the rest of the data doesn't matter */
2252 status
= centry
->status
;
2253 if (NT_STATUS_IS_OK(status
)) {
2254 info
->acct_name
= centry_string(centry
, mem_ctx
);
2255 info
->full_name
= centry_string(centry
, mem_ctx
);
2256 info
->homedir
= centry_string(centry
, mem_ctx
);
2257 info
->shell
= centry_string(centry
, mem_ctx
);
2258 info
->primary_gid
= centry_uint32(centry
);
2259 centry_sid(centry
, &info
->user_sid
);
2260 centry_sid(centry
, &info
->group_sid
);
2263 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2264 "%s\n", domain
->name
, nt_errstr(status
) ));
2266 centry_free(centry
);
2270 /* Lookup user information from a rid */
2271 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
2272 TALLOC_CTX
*mem_ctx
,
2273 const struct dom_sid
*user_sid
,
2274 struct wbint_userinfo
*info
)
2279 old_status
= domain
->online
;
2280 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2281 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2287 /* Return status value returned by seq number check */
2289 if (!NT_STATUS_IS_OK(domain
->last_status
))
2290 return domain
->last_status
;
2292 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2295 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
2297 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2298 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2299 if (!domain
->internal
&& old_status
) {
2300 set_domain_offline(domain
);
2302 if (!domain
->internal
&&
2305 NTSTATUS cache_status
;
2306 cache_status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2307 return cache_status
;
2311 refresh_sequence_number(domain
, false);
2312 if (!NT_STATUS_IS_OK(status
)) {
2315 wcache_save_user(domain
, status
, info
);
2320 NTSTATUS
wcache_lookup_usergroups(struct winbindd_domain
*domain
,
2321 TALLOC_CTX
*mem_ctx
,
2322 const struct dom_sid
*user_sid
,
2323 uint32_t *pnum_sids
,
2324 struct dom_sid
**psids
)
2326 struct winbind_cache
*cache
= get_cache(domain
);
2327 struct cache_entry
*centry
= NULL
;
2329 uint32_t i
, num_sids
;
2330 struct dom_sid
*sids
;
2333 if (cache
->tdb
== NULL
) {
2334 return NT_STATUS_NOT_FOUND
;
2337 centry
= wcache_fetch(cache
, domain
, "UG/%s",
2338 sid_to_fstring(sid_string
, user_sid
));
2339 if (centry
== NULL
) {
2340 return NT_STATUS_NOT_FOUND
;
2343 /* If we have an access denied cache entry and a cached info3 in the
2344 samlogon cache then do a query. This will force the rpc back end
2345 to return the info3 data. */
2347 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)
2348 && netsamlogon_cache_have(user_sid
)) {
2349 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2351 domain
->last_status
= NT_STATUS_OK
;
2352 centry_free(centry
);
2353 return NT_STATUS_NOT_FOUND
;
2356 num_sids
= centry_uint32(centry
);
2357 sids
= talloc_array(mem_ctx
, struct dom_sid
, num_sids
);
2359 centry_free(centry
);
2360 return NT_STATUS_NO_MEMORY
;
2363 for (i
=0; i
<num_sids
; i
++) {
2364 centry_sid(centry
, &sids
[i
]);
2367 status
= centry
->status
;
2369 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2370 "status: %s\n", domain
->name
, nt_errstr(status
)));
2372 centry_free(centry
);
2374 *pnum_sids
= num_sids
;
2379 /* Lookup groups a user is a member of. */
2380 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
2381 TALLOC_CTX
*mem_ctx
,
2382 const struct dom_sid
*user_sid
,
2383 uint32
*num_groups
, struct dom_sid
**user_gids
)
2385 struct cache_entry
*centry
= NULL
;
2391 old_status
= domain
->online
;
2392 status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2393 num_groups
, user_gids
);
2394 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2399 (*user_gids
) = NULL
;
2401 /* Return status value returned by seq number check */
2403 if (!NT_STATUS_IS_OK(domain
->last_status
))
2404 return domain
->last_status
;
2406 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2409 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
2411 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2412 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2413 if (!domain
->internal
&& old_status
) {
2414 set_domain_offline(domain
);
2416 if (!domain
->internal
&&
2419 NTSTATUS cache_status
;
2420 cache_status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2421 num_groups
, user_gids
);
2422 return cache_status
;
2425 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
2429 refresh_sequence_number(domain
, false);
2430 if (!NT_STATUS_IS_OK(status
)) {
2433 centry
= centry_start(domain
, status
);
2437 centry_put_uint32(centry
, *num_groups
);
2438 for (i
=0; i
<(*num_groups
); i
++) {
2439 centry_put_sid(centry
, &(*user_gids
)[i
]);
2442 centry_end(centry
, "UG/%s", sid_to_fstring(sid_string
, user_sid
));
2443 centry_free(centry
);
2449 static char *wcache_make_sidlist(TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2450 const struct dom_sid
*sids
)
2455 sidlist
= talloc_strdup(mem_ctx
, "");
2456 if (sidlist
== NULL
) {
2459 for (i
=0; i
<num_sids
; i
++) {
2461 sidlist
= talloc_asprintf_append_buffer(
2462 sidlist
, "/%s", sid_to_fstring(tmp
, &sids
[i
]));
2463 if (sidlist
== NULL
) {
2470 NTSTATUS
wcache_lookup_useraliases(struct winbindd_domain
*domain
,
2471 TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2472 const struct dom_sid
*sids
,
2473 uint32_t *pnum_aliases
, uint32_t **paliases
)
2475 struct winbind_cache
*cache
= get_cache(domain
);
2476 struct cache_entry
*centry
= NULL
;
2477 uint32_t num_aliases
;
2483 if (cache
->tdb
== NULL
) {
2484 return NT_STATUS_NOT_FOUND
;
2487 if (num_sids
== 0) {
2490 return NT_STATUS_OK
;
2493 /* We need to cache indexed by the whole list of SIDs, the aliases
2494 * resulting might come from any of the SIDs. */
2496 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2497 if (sidlist
== NULL
) {
2498 return NT_STATUS_NO_MEMORY
;
2501 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2502 TALLOC_FREE(sidlist
);
2503 if (centry
== NULL
) {
2504 return NT_STATUS_NOT_FOUND
;
2507 num_aliases
= centry_uint32(centry
);
2508 aliases
= talloc_array(mem_ctx
, uint32_t, num_aliases
);
2509 if (aliases
== NULL
) {
2510 centry_free(centry
);
2511 return NT_STATUS_NO_MEMORY
;
2514 for (i
=0; i
<num_aliases
; i
++) {
2515 aliases
[i
] = centry_uint32(centry
);
2518 status
= centry
->status
;
2520 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2521 "status %s\n", domain
->name
, nt_errstr(status
)));
2523 centry_free(centry
);
2525 *pnum_aliases
= num_aliases
;
2526 *paliases
= aliases
;
2531 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
2532 TALLOC_CTX
*mem_ctx
,
2533 uint32 num_sids
, const struct dom_sid
*sids
,
2534 uint32
*num_aliases
, uint32
**alias_rids
)
2536 struct cache_entry
*centry
= NULL
;
2542 old_status
= domain
->online
;
2543 status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
2544 num_aliases
, alias_rids
);
2545 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2550 (*alias_rids
) = NULL
;
2552 if (!NT_STATUS_IS_OK(domain
->last_status
))
2553 return domain
->last_status
;
2555 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2556 "for domain %s\n", domain
->name
));
2558 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2559 if (sidlist
== NULL
) {
2560 return NT_STATUS_NO_MEMORY
;
2563 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2565 num_aliases
, alias_rids
);
2567 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2568 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2569 if (!domain
->internal
&& old_status
) {
2570 set_domain_offline(domain
);
2572 if (!domain
->internal
&&
2575 NTSTATUS cache_status
;
2576 cache_status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
,
2577 sids
, num_aliases
, alias_rids
);
2578 return cache_status
;
2582 refresh_sequence_number(domain
, false);
2583 if (!NT_STATUS_IS_OK(status
)) {
2586 centry
= centry_start(domain
, status
);
2589 centry_put_uint32(centry
, *num_aliases
);
2590 for (i
=0; i
<(*num_aliases
); i
++)
2591 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2592 centry_end(centry
, "UA%s", sidlist
);
2593 centry_free(centry
);
2599 NTSTATUS
wcache_lookup_groupmem(struct winbindd_domain
*domain
,
2600 TALLOC_CTX
*mem_ctx
,
2601 const struct dom_sid
*group_sid
,
2602 uint32_t *num_names
,
2603 struct dom_sid
**sid_mem
, char ***names
,
2604 uint32_t **name_types
)
2606 struct winbind_cache
*cache
= get_cache(domain
);
2607 struct cache_entry
*centry
= NULL
;
2612 if (cache
->tdb
== NULL
) {
2613 return NT_STATUS_NOT_FOUND
;
2616 sid_string
= sid_string_tos(group_sid
);
2617 if (sid_string
== NULL
) {
2618 return NT_STATUS_NO_MEMORY
;
2621 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_string
);
2622 TALLOC_FREE(sid_string
);
2623 if (centry
== NULL
) {
2624 return NT_STATUS_NOT_FOUND
;
2631 *num_names
= centry_uint32(centry
);
2632 if (*num_names
== 0) {
2633 centry_free(centry
);
2634 return NT_STATUS_OK
;
2637 *sid_mem
= talloc_array(mem_ctx
, struct dom_sid
, *num_names
);
2638 *names
= talloc_array(mem_ctx
, char *, *num_names
);
2639 *name_types
= talloc_array(mem_ctx
, uint32
, *num_names
);
2641 if ((*sid_mem
== NULL
) || (*names
== NULL
) || (*name_types
== NULL
)) {
2642 TALLOC_FREE(*sid_mem
);
2643 TALLOC_FREE(*names
);
2644 TALLOC_FREE(*name_types
);
2645 centry_free(centry
);
2646 return NT_STATUS_NO_MEMORY
;
2649 for (i
=0; i
<(*num_names
); i
++) {
2650 centry_sid(centry
, &(*sid_mem
)[i
]);
2651 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2652 (*name_types
)[i
] = centry_uint32(centry
);
2655 status
= centry
->status
;
2657 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2658 "status: %s\n", domain
->name
, nt_errstr(status
)));
2660 centry_free(centry
);
2664 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
2665 TALLOC_CTX
*mem_ctx
,
2666 const struct dom_sid
*group_sid
,
2667 enum lsa_SidType type
,
2669 struct dom_sid
**sid_mem
, char ***names
,
2670 uint32
**name_types
)
2672 struct cache_entry
*centry
= NULL
;
2678 old_status
= domain
->online
;
2679 status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2680 sid_mem
, names
, name_types
);
2681 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2688 (*name_types
) = NULL
;
2690 /* Return status value returned by seq number check */
2692 if (!NT_STATUS_IS_OK(domain
->last_status
))
2693 return domain
->last_status
;
2695 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2698 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
,
2700 sid_mem
, names
, name_types
);
2702 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2703 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2704 if (!domain
->internal
&& old_status
) {
2705 set_domain_offline(domain
);
2707 if (!domain
->internal
&&
2710 NTSTATUS cache_status
;
2711 cache_status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
,
2712 num_names
, sid_mem
, names
,
2714 return cache_status
;
2718 refresh_sequence_number(domain
, false);
2719 if (!NT_STATUS_IS_OK(status
)) {
2722 centry
= centry_start(domain
, status
);
2725 centry_put_uint32(centry
, *num_names
);
2726 for (i
=0; i
<(*num_names
); i
++) {
2727 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2728 centry_put_string(centry
, (*names
)[i
]);
2729 centry_put_uint32(centry
, (*name_types
)[i
]);
2731 centry_end(centry
, "GM/%s", sid_to_fstring(sid_string
, group_sid
));
2732 centry_free(centry
);
2738 /* find the sequence number for a domain */
2739 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
2741 refresh_sequence_number(domain
, false);
2743 *seq
= domain
->sequence_number
;
2745 return NT_STATUS_OK
;
2748 /* enumerate trusted domains
2749 * (we need to have the list of trustdoms in the cache when we go offline) -
2751 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
2752 TALLOC_CTX
*mem_ctx
,
2753 struct netr_DomainTrustList
*trusts
)
2756 struct winbind_cache
*cache
;
2757 struct winbindd_tdc_domain
*dom_list
= NULL
;
2758 size_t num_domains
= 0;
2759 bool retval
= false;
2763 old_status
= domain
->online
;
2765 trusts
->array
= NULL
;
2767 cache
= get_cache(domain
);
2768 if (!cache
|| !cache
->tdb
) {
2772 if (domain
->online
) {
2776 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2777 if (!retval
|| !num_domains
|| !dom_list
) {
2778 TALLOC_FREE(dom_list
);
2783 trusts
->array
= talloc_zero_array(mem_ctx
, struct netr_DomainTrust
, num_domains
);
2784 if (!trusts
->array
) {
2785 TALLOC_FREE(dom_list
);
2786 return NT_STATUS_NO_MEMORY
;
2789 for (i
= 0; i
< num_domains
; i
++) {
2790 struct netr_DomainTrust
*trust
;
2791 struct dom_sid
*sid
;
2792 struct winbindd_domain
*dom
;
2794 dom
= find_domain_from_name_noinit(dom_list
[i
].domain_name
);
2795 if (dom
&& dom
->internal
) {
2799 trust
= &trusts
->array
[trusts
->count
];
2800 trust
->netbios_name
= talloc_strdup(trusts
->array
, dom_list
[i
].domain_name
);
2801 trust
->dns_name
= talloc_strdup(trusts
->array
, dom_list
[i
].dns_name
);
2802 sid
= talloc(trusts
->array
, struct dom_sid
);
2803 if (!trust
->netbios_name
|| !trust
->dns_name
||
2805 TALLOC_FREE(dom_list
);
2806 TALLOC_FREE(trusts
->array
);
2807 return NT_STATUS_NO_MEMORY
;
2810 trust
->trust_flags
= dom_list
[i
].trust_flags
;
2811 trust
->trust_attributes
= dom_list
[i
].trust_attribs
;
2812 trust
->trust_type
= dom_list
[i
].trust_type
;
2813 sid_copy(sid
, &dom_list
[i
].sid
);
2818 TALLOC_FREE(dom_list
);
2819 return NT_STATUS_OK
;
2822 /* Return status value returned by seq number check */
2824 if (!NT_STATUS_IS_OK(domain
->last_status
))
2825 return domain
->last_status
;
2827 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2830 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, trusts
);
2832 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2833 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2834 if (!domain
->internal
&& old_status
) {
2835 set_domain_offline(domain
);
2837 if (!domain
->internal
&&
2840 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2841 if (retval
&& num_domains
&& dom_list
) {
2842 TALLOC_FREE(trusts
->array
);
2844 goto do_fetch_cache
;
2848 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2849 * so that the generic centry handling still applies correctly -
2852 if (!NT_STATUS_IS_ERR(status
)) {
2853 status
= NT_STATUS_OK
;
2858 /* get lockout policy */
2859 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
2860 TALLOC_CTX
*mem_ctx
,
2861 struct samr_DomInfo12
*policy
)
2863 struct winbind_cache
*cache
= get_cache(domain
);
2864 struct cache_entry
*centry
= NULL
;
2868 old_status
= domain
->online
;
2872 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2878 policy
->lockout_duration
= centry_nttime(centry
);
2879 policy
->lockout_window
= centry_nttime(centry
);
2880 policy
->lockout_threshold
= centry_uint16(centry
);
2882 status
= centry
->status
;
2884 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2885 domain
->name
, nt_errstr(status
) ));
2887 centry_free(centry
);
2891 ZERO_STRUCTP(policy
);
2893 /* Return status value returned by seq number check */
2895 if (!NT_STATUS_IS_OK(domain
->last_status
))
2896 return domain
->last_status
;
2898 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2901 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2903 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2904 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2905 if (!domain
->internal
&& old_status
) {
2906 set_domain_offline(domain
);
2909 !domain
->internal
&&
2912 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2914 goto do_fetch_cache
;
2919 refresh_sequence_number(domain
, false);
2920 if (!NT_STATUS_IS_OK(status
)) {
2923 wcache_save_lockout_policy(domain
, status
, policy
);
2928 /* get password policy */
2929 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
2930 TALLOC_CTX
*mem_ctx
,
2931 struct samr_DomInfo1
*policy
)
2933 struct winbind_cache
*cache
= get_cache(domain
);
2934 struct cache_entry
*centry
= NULL
;
2938 old_status
= domain
->online
;
2942 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2948 policy
->min_password_length
= centry_uint16(centry
);
2949 policy
->password_history_length
= centry_uint16(centry
);
2950 policy
->password_properties
= centry_uint32(centry
);
2951 policy
->max_password_age
= centry_nttime(centry
);
2952 policy
->min_password_age
= centry_nttime(centry
);
2954 status
= centry
->status
;
2956 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2957 domain
->name
, nt_errstr(status
) ));
2959 centry_free(centry
);
2963 ZERO_STRUCTP(policy
);
2965 /* Return status value returned by seq number check */
2967 if (!NT_STATUS_IS_OK(domain
->last_status
))
2968 return domain
->last_status
;
2970 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2973 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
2975 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2976 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2977 if (!domain
->internal
&& old_status
) {
2978 set_domain_offline(domain
);
2981 !domain
->internal
&&
2984 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2986 goto do_fetch_cache
;
2991 refresh_sequence_number(domain
, false);
2992 if (!NT_STATUS_IS_OK(status
)) {
2995 wcache_save_password_policy(domain
, status
, policy
);
3001 /* Invalidate cached user and group lists coherently */
3003 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3006 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
3007 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
3008 tdb_delete(the_tdb
, kbuf
);
3013 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3015 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
3016 const struct dom_sid
*sid
)
3018 fstring key_str
, sid_string
;
3019 struct winbind_cache
*cache
;
3021 /* dont clear cached U/SID and UG/SID entries when we want to logon
3024 if (lp_winbind_offline_logon()) {
3031 cache
= get_cache(domain
);
3037 /* Clear U/SID cache entry */
3038 fstr_sprintf(key_str
, "U/%s", sid_to_fstring(sid_string
, sid
));
3039 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3040 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3042 /* Clear UG/SID cache entry */
3043 fstr_sprintf(key_str
, "UG/%s", sid_to_fstring(sid_string
, sid
));
3044 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3045 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3047 /* Samba/winbindd never needs this. */
3048 netsamlogon_clear_cached_user(sid
);
3051 bool wcache_invalidate_cache(void)
3053 struct winbindd_domain
*domain
;
3055 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3056 struct winbind_cache
*cache
= get_cache(domain
);
3058 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3059 "entries for %s\n", domain
->name
));
3062 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3071 bool wcache_invalidate_cache_noinit(void)
3073 struct winbindd_domain
*domain
;
3075 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3076 struct winbind_cache
*cache
;
3078 /* Skip uninitialized domains. */
3079 if (!domain
->initialized
&& !domain
->internal
) {
3083 cache
= get_cache(domain
);
3085 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3086 "entries for %s\n", domain
->name
));
3089 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3091 * Flushing cache has nothing to with domains.
3092 * return here if we successfully flushed once.
3093 * To avoid unnecessary traversing the cache.
3104 bool init_wcache(void)
3106 if (wcache
== NULL
) {
3107 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
3108 ZERO_STRUCTP(wcache
);
3111 if (wcache
->tdb
!= NULL
)
3114 /* when working offline we must not clear the cache on restart */
3115 wcache
->tdb
= tdb_open_log(state_path("winbindd_cache.tdb"),
3116 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3117 TDB_INCOMPATIBLE_HASH
|
3118 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3119 O_RDWR
|O_CREAT
, 0600);
3121 if (wcache
->tdb
== NULL
) {
3122 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3129 /************************************************************************
3130 This is called by the parent to initialize the cache file.
3131 We don't need sophisticated locking here as we know we're the
3133 ************************************************************************/
3135 bool initialize_winbindd_cache(void)
3137 bool cache_bad
= true;
3140 if (!init_wcache()) {
3141 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3145 /* Check version number. */
3146 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
3147 vers
== WINBINDD_CACHE_VERSION
) {
3152 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3153 "and re-creating with version number %d\n",
3154 WINBINDD_CACHE_VERSION
));
3156 tdb_close(wcache
->tdb
);
3159 if (unlink(state_path("winbindd_cache.tdb")) == -1) {
3160 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3161 state_path("winbindd_cache.tdb"),
3165 if (!init_wcache()) {
3166 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3167 "init_wcache failed.\n"));
3171 /* Write the version. */
3172 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
3173 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3174 tdb_errorstr_compat(wcache
->tdb
) ));
3179 tdb_close(wcache
->tdb
);
3184 void close_winbindd_cache(void)
3190 tdb_close(wcache
->tdb
);
3195 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*sid
,
3196 char **domain_name
, char **name
,
3197 enum lsa_SidType
*type
)
3199 struct winbindd_domain
*domain
;
3202 domain
= find_lookup_domain_from_sid(sid
);
3203 if (domain
== NULL
) {
3206 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
3208 return NT_STATUS_IS_OK(status
);
3211 bool lookup_cached_name(const char *domain_name
,
3213 struct dom_sid
*sid
,
3214 enum lsa_SidType
*type
)
3216 struct winbindd_domain
*domain
;
3218 bool original_online_state
;
3220 domain
= find_lookup_domain_from_name(domain_name
);
3221 if (domain
== NULL
) {
3225 /* If we are doing a cached logon, temporarily set the domain
3226 offline so the cache won't expire the entry */
3228 original_online_state
= domain
->online
;
3229 domain
->online
= false;
3230 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
3231 domain
->online
= original_online_state
;
3233 return NT_STATUS_IS_OK(status
);
3236 void cache_name2sid(struct winbindd_domain
*domain
,
3237 const char *domain_name
, const char *name
,
3238 enum lsa_SidType type
, const struct dom_sid
*sid
)
3240 refresh_sequence_number(domain
, false);
3241 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
3246 * The original idea that this cache only contains centries has
3247 * been blurred - now other stuff gets put in here. Ensure we
3248 * ignore these things on cleanup.
3251 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
3252 TDB_DATA dbuf
, void *state
)
3254 struct cache_entry
*centry
;
3256 if (is_non_centry_key(kbuf
)) {
3260 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
3265 if (!NT_STATUS_IS_OK(centry
->status
)) {
3266 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
3267 tdb_delete(the_tdb
, kbuf
);
3270 centry_free(centry
);
3274 /* flush the cache */
3275 void wcache_flush_cache(void)
3280 tdb_close(wcache
->tdb
);
3283 if (!winbindd_use_cache()) {
3287 /* when working offline we must not clear the cache on restart */
3288 wcache
->tdb
= tdb_open_log(state_path("winbindd_cache.tdb"),
3289 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3290 TDB_INCOMPATIBLE_HASH
|
3291 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3292 O_RDWR
|O_CREAT
, 0600);
3295 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3299 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
3301 DEBUG(10,("wcache_flush_cache success\n"));
3304 /* Count cached creds */
3306 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3309 int *cred_count
= (int*)state
;
3311 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3317 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
3319 struct winbind_cache
*cache
= get_cache(domain
);
3324 return NT_STATUS_INTERNAL_DB_ERROR
;
3327 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
3329 return NT_STATUS_OK
;
3333 struct cred_list
*prev
, *next
;
3338 static struct cred_list
*wcache_cred_list
;
3340 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3343 struct cred_list
*cred
;
3345 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3347 cred
= SMB_MALLOC_P(struct cred_list
);
3349 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3355 /* save a copy of the key */
3357 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
3358 DLIST_ADD(wcache_cred_list
, cred
);
3364 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
3366 struct winbind_cache
*cache
= get_cache(domain
);
3369 struct cred_list
*cred
, *oldest
= NULL
;
3372 return NT_STATUS_INTERNAL_DB_ERROR
;
3375 /* we possibly already have an entry */
3376 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
3378 fstring key_str
, tmp
;
3380 DEBUG(11,("we already have an entry, deleting that\n"));
3382 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
3384 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3386 return NT_STATUS_OK
;
3389 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
3391 return NT_STATUS_OK
;
3392 } else if ((ret
< 0) || (wcache_cred_list
== NULL
)) {
3393 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3396 ZERO_STRUCTP(oldest
);
3398 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
3403 data
= tdb_fetch_compat(cache
->tdb
, string_tdb_data(cred
->name
));
3405 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3407 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3411 t
= IVAL(data
.dptr
, 0);
3412 SAFE_FREE(data
.dptr
);
3415 oldest
= SMB_MALLOC_P(struct cred_list
);
3416 if (oldest
== NULL
) {
3417 status
= NT_STATUS_NO_MEMORY
;
3421 fstrcpy(oldest
->name
, cred
->name
);
3422 oldest
->created
= t
;
3426 if (t
< oldest
->created
) {
3427 fstrcpy(oldest
->name
, cred
->name
);
3428 oldest
->created
= t
;
3432 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3433 status
= NT_STATUS_OK
;
3435 status
= NT_STATUS_UNSUCCESSFUL
;
3438 SAFE_FREE(wcache_cred_list
);
3444 /* Change the global online/offline state. */
3445 bool set_global_winbindd_state_offline(void)
3449 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3451 /* Only go offline if someone has created
3452 the key "WINBINDD_OFFLINE" in the cache tdb. */
3454 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3455 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3459 if (!lp_winbind_offline_logon()) {
3460 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3464 if (global_winbindd_offline_state
) {
3465 /* Already offline. */
3469 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
3471 if (!data
.dptr
|| data
.dsize
!= 4) {
3472 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3473 SAFE_FREE(data
.dptr
);
3476 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3477 global_winbindd_offline_state
= true;
3478 SAFE_FREE(data
.dptr
);
3483 void set_global_winbindd_state_online(void)
3485 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3487 if (!lp_winbind_offline_logon()) {
3488 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3492 if (!global_winbindd_offline_state
) {
3493 /* Already online. */
3496 global_winbindd_offline_state
= false;
3502 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3503 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3506 bool get_global_winbindd_state_offline(void)
3508 return global_winbindd_offline_state
;
3511 /***********************************************************************
3512 Validate functions for all possible cache tdb keys.
3513 ***********************************************************************/
3515 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3516 struct tdb_validation_status
*state
)
3518 struct cache_entry
*centry
;
3520 centry
= SMB_XMALLOC_P(struct cache_entry
);
3521 centry
->data
= (unsigned char *)memdup(data
.dptr
, data
.dsize
);
3522 if (!centry
->data
) {
3526 centry
->len
= data
.dsize
;
3529 if (centry
->len
< 16) {
3530 /* huh? corrupt cache? */
3531 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3532 "(len < 16) ?\n", kstr
));
3533 centry_free(centry
);
3534 state
->bad_entry
= true;
3535 state
->success
= false;
3539 centry
->status
= NT_STATUS(centry_uint32(centry
));
3540 centry
->sequence_number
= centry_uint32(centry
);
3541 centry
->timeout
= centry_uint64_t(centry
);
3545 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3546 struct tdb_validation_status
*state
)
3548 if (dbuf
.dsize
!= 8) {
3549 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3550 keystr
, (unsigned int)dbuf
.dsize
));
3551 state
->bad_entry
= true;
3557 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3558 struct tdb_validation_status
*state
)
3560 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3565 (void)centry_uint32(centry
);
3566 if (NT_STATUS_IS_OK(centry
->status
)) {
3568 (void)centry_sid(centry
, &sid
);
3571 centry_free(centry
);
3573 if (!(state
->success
)) {
3576 DEBUG(10,("validate_ns: %s ok\n", keystr
));
3580 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3581 struct tdb_validation_status
*state
)
3583 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3588 if (NT_STATUS_IS_OK(centry
->status
)) {
3589 (void)centry_uint32(centry
);
3590 (void)centry_string(centry
, mem_ctx
);
3591 (void)centry_string(centry
, mem_ctx
);
3594 centry_free(centry
);
3596 if (!(state
->success
)) {
3599 DEBUG(10,("validate_sn: %s ok\n", keystr
));
3603 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3604 struct tdb_validation_status
*state
)
3606 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3613 (void)centry_string(centry
, mem_ctx
);
3614 (void)centry_string(centry
, mem_ctx
);
3615 (void)centry_string(centry
, mem_ctx
);
3616 (void)centry_string(centry
, mem_ctx
);
3617 (void)centry_uint32(centry
);
3618 (void)centry_sid(centry
, &sid
);
3619 (void)centry_sid(centry
, &sid
);
3621 centry_free(centry
);
3623 if (!(state
->success
)) {
3626 DEBUG(10,("validate_u: %s ok\n", keystr
));
3630 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3631 struct tdb_validation_status
*state
)
3633 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3639 (void)centry_nttime(centry
);
3640 (void)centry_nttime(centry
);
3641 (void)centry_uint16(centry
);
3643 centry_free(centry
);
3645 if (!(state
->success
)) {
3648 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3652 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3653 struct tdb_validation_status
*state
)
3655 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3661 (void)centry_uint16(centry
);
3662 (void)centry_uint16(centry
);
3663 (void)centry_uint32(centry
);
3664 (void)centry_nttime(centry
);
3665 (void)centry_nttime(centry
);
3667 centry_free(centry
);
3669 if (!(state
->success
)) {
3672 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3676 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3677 struct tdb_validation_status
*state
)
3679 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3685 (void)centry_time(centry
);
3686 (void)centry_hash16(centry
, mem_ctx
);
3688 /* We only have 17 bytes more data in the salted cred case. */
3689 if (centry
->len
- centry
->ofs
== 17) {
3690 (void)centry_hash16(centry
, mem_ctx
);
3693 centry_free(centry
);
3695 if (!(state
->success
)) {
3698 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3702 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3703 struct tdb_validation_status
*state
)
3705 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3706 int32 num_entries
, i
;
3712 num_entries
= (int32
)centry_uint32(centry
);
3714 for (i
=0; i
< num_entries
; i
++) {
3716 (void)centry_string(centry
, mem_ctx
);
3717 (void)centry_string(centry
, mem_ctx
);
3718 (void)centry_string(centry
, mem_ctx
);
3719 (void)centry_string(centry
, mem_ctx
);
3720 (void)centry_sid(centry
, &sid
);
3721 (void)centry_sid(centry
, &sid
);
3724 centry_free(centry
);
3726 if (!(state
->success
)) {
3729 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3733 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3734 struct tdb_validation_status
*state
)
3736 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3737 int32 num_entries
, i
;
3743 num_entries
= centry_uint32(centry
);
3745 for (i
=0; i
< num_entries
; i
++) {
3746 (void)centry_string(centry
, mem_ctx
);
3747 (void)centry_string(centry
, mem_ctx
);
3748 (void)centry_uint32(centry
);
3751 centry_free(centry
);
3753 if (!(state
->success
)) {
3756 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3760 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3761 struct tdb_validation_status
*state
)
3763 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3764 int32 num_groups
, i
;
3770 num_groups
= centry_uint32(centry
);
3772 for (i
=0; i
< num_groups
; i
++) {
3774 centry_sid(centry
, &sid
);
3777 centry_free(centry
);
3779 if (!(state
->success
)) {
3782 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3786 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3787 struct tdb_validation_status
*state
)
3789 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3790 int32 num_aliases
, i
;
3796 num_aliases
= centry_uint32(centry
);
3798 for (i
=0; i
< num_aliases
; i
++) {
3799 (void)centry_uint32(centry
);
3802 centry_free(centry
);
3804 if (!(state
->success
)) {
3807 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3811 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3812 struct tdb_validation_status
*state
)
3814 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3821 num_names
= centry_uint32(centry
);
3823 for (i
=0; i
< num_names
; i
++) {
3825 centry_sid(centry
, &sid
);
3826 (void)centry_string(centry
, mem_ctx
);
3827 (void)centry_uint32(centry
);
3830 centry_free(centry
);
3832 if (!(state
->success
)) {
3835 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3839 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3840 struct tdb_validation_status
*state
)
3842 /* Can't say anything about this other than must be nonzero. */
3843 if (dbuf
.dsize
== 0) {
3844 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3846 state
->bad_entry
= true;
3847 state
->success
= false;
3851 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3855 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3856 struct tdb_validation_status
*state
)
3858 /* Can't say anything about this other than must be nonzero. */
3859 if (dbuf
.dsize
== 0) {
3860 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3862 state
->bad_entry
= true;
3863 state
->success
= false;
3867 DEBUG(10,("validate_de: %s ok\n", keystr
));
3871 static int validate_pwinfo(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3872 TDB_DATA dbuf
, struct tdb_validation_status
*state
)
3874 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3880 (void)centry_string(centry
, mem_ctx
);
3881 (void)centry_string(centry
, mem_ctx
);
3882 (void)centry_string(centry
, mem_ctx
);
3883 (void)centry_uint32(centry
);
3885 centry_free(centry
);
3887 if (!(state
->success
)) {
3890 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3894 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3896 struct tdb_validation_status
*state
)
3898 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3904 (void)centry_string( centry
, mem_ctx
);
3906 centry_free(centry
);
3908 if (!(state
->success
)) {
3911 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3915 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3917 struct tdb_validation_status
*state
)
3919 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3925 (void)centry_string( centry
, mem_ctx
);
3927 centry_free(centry
);
3929 if (!(state
->success
)) {
3932 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3936 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3938 struct tdb_validation_status
*state
)
3940 if (dbuf
.dsize
== 0) {
3941 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3942 "key %s (len ==0) ?\n", keystr
));
3943 state
->bad_entry
= true;
3944 state
->success
= false;
3948 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3949 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3953 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3954 struct tdb_validation_status
*state
)
3956 if (dbuf
.dsize
!= 4) {
3957 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3958 keystr
, (unsigned int)dbuf
.dsize
));
3959 state
->bad_entry
= true;
3960 state
->success
= false;
3963 DEBUG(10,("validate_offline: %s ok\n", keystr
));
3967 static int validate_ndr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3968 struct tdb_validation_status
*state
)
3971 * Ignore validation for now. The proper way to do this is with a
3972 * checksum. Just pure parsing does not really catch much.
3977 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3978 struct tdb_validation_status
*state
)
3980 if (dbuf
.dsize
!= 4) {
3981 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3982 "key %s (len %u != 4) ?\n",
3983 keystr
, (unsigned int)dbuf
.dsize
));
3984 state
->bad_entry
= true;
3985 state
->success
= false;
3989 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
3993 /***********************************************************************
3994 A list of all possible cache tdb keys with associated validation
3996 ***********************************************************************/
3998 struct key_val_struct
{
3999 const char *keyname
;
4000 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
4002 {"SEQNUM/", validate_seqnum
},
4003 {"NS/", validate_ns
},
4004 {"SN/", validate_sn
},
4006 {"LOC_POL/", validate_loc_pol
},
4007 {"PWD_POL/", validate_pwd_pol
},
4008 {"CRED/", validate_cred
},
4009 {"UL/", validate_ul
},
4010 {"GL/", validate_gl
},
4011 {"UG/", validate_ug
},
4012 {"UA", validate_ua
},
4013 {"GM/", validate_gm
},
4014 {"DR/", validate_dr
},
4015 {"DE/", validate_de
},
4016 {"NSS/PWINFO/", validate_pwinfo
},
4017 {"TRUSTDOMCACHE/", validate_trustdomcache
},
4018 {"NSS/NA/", validate_nss_na
},
4019 {"NSS/AN/", validate_nss_an
},
4020 {"WINBINDD_OFFLINE", validate_offline
},
4021 {"NDR/", validate_ndr
},
4022 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
4026 /***********************************************************************
4027 Function to look at every entry in the tdb and validate it as far as
4029 ***********************************************************************/
4031 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
4034 unsigned int max_key_len
= 1024;
4035 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
4037 /* Paranoia check. */
4038 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0) {
4039 max_key_len
= 1024 * 1024;
4041 if (kbuf
.dsize
> max_key_len
) {
4042 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4044 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
4048 for (i
= 0; key_val
[i
].keyname
; i
++) {
4049 size_t namelen
= strlen(key_val
[i
].keyname
);
4050 if (kbuf
.dsize
>= namelen
&& (
4051 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
4052 TALLOC_CTX
*mem_ctx
;
4056 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
4060 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
4061 keystr
[kbuf
.dsize
] = '\0';
4063 mem_ctx
= talloc_init("validate_ctx");
4069 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
4073 talloc_destroy(mem_ctx
);
4078 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4079 dump_data(0, (uint8
*)kbuf
.dptr
, kbuf
.dsize
);
4080 DEBUG(0,("data :\n"));
4081 dump_data(0, (uint8
*)dbuf
.dptr
, dbuf
.dsize
);
4082 v_state
->unknown_key
= true;
4083 v_state
->success
= false;
4084 return 1; /* terminate. */
4087 static void validate_panic(const char *const why
)
4089 DEBUG(0,("validating cache: would panic %s\n", why
));
4090 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4094 static int wbcache_update_centry_fn(TDB_CONTEXT
*tdb
,
4102 if (is_non_centry_key(key
)) {
4106 if (data
.dptr
== NULL
|| data
.dsize
== 0) {
4107 if (tdb_delete(tdb
, key
) < 0) {
4108 DEBUG(0, ("tdb_delete for [%s] failed!\n",
4114 /* add timeout to blob (uint64_t) */
4115 blob
.dsize
= data
.dsize
+ 8;
4117 blob
.dptr
= SMB_XMALLOC_ARRAY(uint8_t, blob
.dsize
);
4118 if (blob
.dptr
== NULL
) {
4121 memset(blob
.dptr
, 0, blob
.dsize
);
4123 /* copy status and seqnum */
4124 memcpy(blob
.dptr
, data
.dptr
, 8);
4127 ctimeout
= lp_winbind_cache_time() + time(NULL
);
4128 SBVAL(blob
.dptr
, 8, ctimeout
);
4131 memcpy(blob
.dptr
+ 16, data
.dptr
+ 8, data
.dsize
- 8);
4133 if (tdb_store(tdb
, key
, blob
, TDB_REPLACE
) < 0) {
4134 DEBUG(0, ("tdb_store to update [%s] failed!\n",
4136 SAFE_FREE(blob
.dptr
);
4140 SAFE_FREE(blob
.dptr
);
4144 static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT
*tdb
)
4148 DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
4150 rc
= tdb_traverse(tdb
, wbcache_update_centry_fn
, NULL
);
4158 /***********************************************************************
4159 Try and validate every entry in the winbindd cache. If we fail here,
4160 delete the cache tdb and return non-zero.
4161 ***********************************************************************/
4163 int winbindd_validate_cache(void)
4166 const char *tdb_path
= state_path("winbindd_cache.tdb");
4167 TDB_CONTEXT
*tdb
= NULL
;
4171 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4172 smb_panic_fn
= validate_panic
;
4174 tdb
= tdb_open_log(tdb_path
,
4175 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
4176 TDB_INCOMPATIBLE_HASH
|
4177 ( lp_winbind_offline_logon()
4179 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
4183 DEBUG(0, ("winbindd_validate_cache: "
4184 "error opening/initializing tdb\n"));
4188 /* Version check and upgrade code. */
4189 if (!tdb_fetch_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers_id
)) {
4190 DEBUG(10, ("Fresh database\n"));
4191 tdb_store_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
);
4192 vers_id
= WINBINDD_CACHE_VERSION
;
4195 if (vers_id
!= WINBINDD_CACHE_VERSION
) {
4196 if (vers_id
== WINBINDD_CACHE_VER1
) {
4197 ok
= wbcache_upgrade_v1_to_v2(tdb
);
4199 DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
4204 tdb_store_uint32(tdb
,
4205 WINBINDD_CACHE_VERSION_KEYSTR
,
4206 WINBINDD_CACHE_VERSION
);
4207 vers_id
= WINBINDD_CACHE_VER2
;
4213 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
4216 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4217 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
4222 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4223 smb_panic_fn
= smb_panic
;
4227 /***********************************************************************
4228 Try and validate every entry in the winbindd cache.
4229 ***********************************************************************/
4231 int winbindd_validate_cache_nobackup(void)
4234 const char *tdb_path
= state_path("winbindd_cache.tdb");
4236 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4237 smb_panic_fn
= validate_panic
;
4240 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
4241 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
4243 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
4247 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4251 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4253 smb_panic_fn
= smb_panic
;
4257 bool winbindd_cache_validate_and_initialize(void)
4259 close_winbindd_cache();
4261 if (lp_winbind_offline_logon()) {
4262 if (winbindd_validate_cache() < 0) {
4263 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4264 "could be restored.\n"));
4268 return initialize_winbindd_cache();
4271 /*********************************************************************
4272 ********************************************************************/
4274 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
4275 struct winbindd_tdc_domain
**domains
,
4276 size_t *num_domains
)
4278 struct winbindd_tdc_domain
*list
= NULL
;
4281 bool set_only
= false;
4283 /* don't allow duplicates */
4288 for ( i
=0; i
< (*num_domains
); i
++ ) {
4289 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
4290 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4301 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, 1 );
4304 list
= talloc_realloc( *domains
, *domains
,
4305 struct winbindd_tdc_domain
,
4310 ZERO_STRUCT( list
[idx
] );
4316 list
[idx
].domain_name
= talloc_strdup( list
, new_dom
->name
);
4317 list
[idx
].dns_name
= talloc_strdup( list
, new_dom
->alt_name
);
4319 if ( !is_null_sid( &new_dom
->sid
) ) {
4320 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
4322 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
4325 if ( new_dom
->domain_flags
!= 0x0 )
4326 list
[idx
].trust_flags
= new_dom
->domain_flags
;
4328 if ( new_dom
->domain_type
!= 0x0 )
4329 list
[idx
].trust_type
= new_dom
->domain_type
;
4331 if ( new_dom
->domain_trust_attribs
!= 0x0 )
4332 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
4336 *num_domains
= idx
+ 1;
4342 /*********************************************************************
4343 ********************************************************************/
4345 static TDB_DATA
make_tdc_key( const char *domain_name
)
4347 char *keystr
= NULL
;
4348 TDB_DATA key
= { NULL
, 0 };
4350 if ( !domain_name
) {
4351 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4355 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
4358 key
= string_term_tdb_data(keystr
);
4363 /*********************************************************************
4364 ********************************************************************/
4366 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
4368 unsigned char **buf
)
4370 unsigned char *buffer
= NULL
;
4375 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4383 /* Store the number of array items first */
4384 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
4387 /* now pack each domain trust record */
4388 for ( i
=0; i
<num_domains
; i
++ ) {
4393 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4394 domains
[i
].domain_name
,
4395 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
4398 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
4399 domains
[i
].domain_name
,
4400 domains
[i
].dns_name
,
4401 sid_to_fstring(tmp
, &domains
[i
].sid
),
4402 domains
[i
].trust_flags
,
4403 domains
[i
].trust_attribs
,
4404 domains
[i
].trust_type
);
4407 if ( buflen
< len
) {
4409 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
4410 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4424 /*********************************************************************
4425 ********************************************************************/
4427 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
4428 struct winbindd_tdc_domain
**domains
)
4430 fstring domain_name
, dns_name
, sid_string
;
4431 uint32 type
, attribs
, flags
;
4435 struct winbindd_tdc_domain
*list
= NULL
;
4437 /* get the number of domains */
4438 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
4440 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4444 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, num_domains
);
4446 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4450 for ( i
=0; i
<num_domains
; i
++ ) {
4451 len
+= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
4460 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4461 TALLOC_FREE( list
);
4465 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4466 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4467 domain_name
, dns_name
, sid_string
,
4468 flags
, attribs
, type
));
4470 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
4471 list
[i
].dns_name
= talloc_strdup( list
, dns_name
);
4472 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
4473 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4476 list
[i
].trust_flags
= flags
;
4477 list
[i
].trust_attribs
= attribs
;
4478 list
[i
].trust_type
= type
;
4486 /*********************************************************************
4487 ********************************************************************/
4489 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
4491 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4492 TDB_DATA data
= { NULL
, 0 };
4498 /* See if we were asked to delete the cache entry */
4501 ret
= tdb_delete( wcache
->tdb
, key
);
4505 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4512 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4515 SAFE_FREE( data
.dptr
);
4516 SAFE_FREE( key
.dptr
);
4518 return ( ret
== 0 );
4521 /*********************************************************************
4522 ********************************************************************/
4524 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4526 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4527 TDB_DATA data
= { NULL
, 0 };
4535 data
= tdb_fetch_compat( wcache
->tdb
, key
);
4537 SAFE_FREE( key
.dptr
);
4542 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4544 SAFE_FREE( data
.dptr
);
4552 /*********************************************************************
4553 ********************************************************************/
4555 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4557 struct winbindd_tdc_domain
*dom_list
= NULL
;
4558 size_t num_domains
= 0;
4561 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4562 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4563 domain
->name
, domain
->alt_name
,
4564 sid_string_dbg(&domain
->sid
),
4565 domain
->domain_flags
,
4566 domain
->domain_trust_attribs
,
4567 domain
->domain_type
));
4569 if ( !init_wcache() ) {
4573 /* fetch the list */
4575 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4577 /* add the new domain */
4579 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4583 /* pack the domain */
4585 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4593 TALLOC_FREE( dom_list
);
4598 /*********************************************************************
4599 ********************************************************************/
4601 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4603 struct winbindd_tdc_domain
*dom_list
= NULL
;
4604 size_t num_domains
= 0;
4606 struct winbindd_tdc_domain
*d
= NULL
;
4608 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4610 if ( !init_wcache() ) {
4614 /* fetch the list */
4616 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4618 for ( i
=0; i
<num_domains
; i
++ ) {
4619 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4620 strequal(name
, dom_list
[i
].dns_name
) )
4622 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4625 d
= talloc( ctx
, struct winbindd_tdc_domain
);
4629 d
->domain_name
= talloc_strdup( d
, dom_list
[i
].domain_name
);
4630 d
->dns_name
= talloc_strdup( d
, dom_list
[i
].dns_name
);
4631 sid_copy( &d
->sid
, &dom_list
[i
].sid
);
4632 d
->trust_flags
= dom_list
[i
].trust_flags
;
4633 d
->trust_type
= dom_list
[i
].trust_type
;
4634 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
4640 TALLOC_FREE( dom_list
);
4645 /*********************************************************************
4646 ********************************************************************/
4648 struct winbindd_tdc_domain
*
4649 wcache_tdc_fetch_domainbysid(TALLOC_CTX
*ctx
,
4650 const struct dom_sid
*sid
)
4652 struct winbindd_tdc_domain
*dom_list
= NULL
;
4653 size_t num_domains
= 0;
4655 struct winbindd_tdc_domain
*d
= NULL
;
4657 DEBUG(10,("wcache_tdc_fetch_domainbysid: Searching for domain %s\n",
4658 sid_string_dbg(sid
)));
4660 if (!init_wcache()) {
4664 /* fetch the list */
4666 wcache_tdc_fetch_list(&dom_list
, &num_domains
);
4668 for (i
= 0; i
<num_domains
; i
++) {
4669 if (dom_sid_equal(sid
, &(dom_list
[i
].sid
))) {
4670 DEBUG(10, ("wcache_tdc_fetch_domainbysid: "
4671 "Found domain %s for SID %s\n",
4672 dom_list
[i
].domain_name
,
4673 sid_string_dbg(sid
)));
4675 d
= talloc(ctx
, struct winbindd_tdc_domain
);
4679 d
->domain_name
= talloc_strdup(d
,
4680 dom_list
[i
].domain_name
);
4682 d
->dns_name
= talloc_strdup(d
, dom_list
[i
].dns_name
);
4683 sid_copy(&d
->sid
, &dom_list
[i
].sid
);
4684 d
->trust_flags
= dom_list
[i
].trust_flags
;
4685 d
->trust_type
= dom_list
[i
].trust_type
;
4686 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
4692 TALLOC_FREE(dom_list
);
4698 /*********************************************************************
4699 ********************************************************************/
4701 void wcache_tdc_clear( void )
4703 if ( !init_wcache() )
4706 wcache_tdc_store_list( NULL
, 0 );
4712 /*********************************************************************
4713 ********************************************************************/
4715 static void wcache_save_user_pwinfo(struct winbindd_domain
*domain
,
4717 const struct dom_sid
*user_sid
,
4718 const char *homedir
,
4723 struct cache_entry
*centry
;
4726 if ( (centry
= centry_start(domain
, status
)) == NULL
)
4729 centry_put_string( centry
, homedir
);
4730 centry_put_string( centry
, shell
);
4731 centry_put_string( centry
, gecos
);
4732 centry_put_uint32( centry
, gid
);
4734 centry_end(centry
, "NSS/PWINFO/%s", sid_to_fstring(tmp
, user_sid
) );
4736 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid
) ));
4738 centry_free(centry
);
4743 NTSTATUS
nss_get_info_cached( struct winbindd_domain
*domain
,
4744 const struct dom_sid
*user_sid
,
4746 const char **homedir
, const char **shell
,
4747 const char **gecos
, gid_t
*p_gid
)
4749 struct winbind_cache
*cache
= get_cache(domain
);
4750 struct cache_entry
*centry
= NULL
;
4757 centry
= wcache_fetch(cache
, domain
, "NSS/PWINFO/%s",
4758 sid_to_fstring(tmp
, user_sid
));
4763 *homedir
= centry_string( centry
, ctx
);
4764 *shell
= centry_string( centry
, ctx
);
4765 *gecos
= centry_string( centry
, ctx
);
4766 *p_gid
= centry_uint32( centry
);
4768 centry_free(centry
);
4770 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4771 sid_string_dbg(user_sid
)));
4773 return NT_STATUS_OK
;
4777 nt_status
= nss_get_info( domain
->name
, user_sid
, ctx
,
4778 homedir
, shell
, gecos
, p_gid
);
4780 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status
)));
4782 if ( NT_STATUS_IS_OK(nt_status
) ) {
4783 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir
));
4784 DEBUGADD(10, ("\tshell = '%s'\n", *shell
));
4785 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos
));
4786 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid
));
4788 wcache_save_user_pwinfo( domain
, nt_status
, user_sid
,
4789 *homedir
, *shell
, *gecos
, *p_gid
);
4792 if ( NT_STATUS_EQUAL( nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
4793 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4795 set_domain_offline( domain
);
4803 /* the cache backend methods are exposed via this structure */
4804 struct winbindd_methods cache_methods
= {
4822 static bool wcache_ndr_key(TALLOC_CTX
*mem_ctx
, char *domain_name
,
4823 uint32_t opnum
, const DATA_BLOB
*req
,
4829 key
= talloc_asprintf(mem_ctx
, "NDR/%s/%d/", domain_name
, (int)opnum
);
4833 keylen
= talloc_get_size(key
) - 1;
4835 key
= talloc_realloc(mem_ctx
, key
, char, keylen
+ req
->length
);
4839 memcpy(key
+ keylen
, req
->data
, req
->length
);
4841 pkey
->dptr
= (uint8_t *)key
;
4842 pkey
->dsize
= talloc_get_size(key
);
4846 static bool wcache_opnum_cacheable(uint32_t opnum
)
4849 case NDR_WBINT_PING
:
4850 case NDR_WBINT_QUERYSEQUENCENUMBER
:
4851 case NDR_WBINT_ALLOCATEUID
:
4852 case NDR_WBINT_ALLOCATEGID
:
4853 case NDR_WBINT_CHECKMACHINEACCOUNT
:
4854 case NDR_WBINT_CHANGEMACHINEACCOUNT
:
4855 case NDR_WBINT_PINGDC
:
4861 bool wcache_fetch_ndr(TALLOC_CTX
*mem_ctx
, struct winbindd_domain
*domain
,
4862 uint32_t opnum
, const DATA_BLOB
*req
, DATA_BLOB
*resp
)
4867 if (!wcache_opnum_cacheable(opnum
) ||
4868 is_my_own_sam_domain(domain
) ||
4869 is_builtin_domain(domain
)) {
4873 if (wcache
->tdb
== NULL
) {
4877 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4880 data
= tdb_fetch_compat(wcache
->tdb
, key
);
4881 TALLOC_FREE(key
.dptr
);
4883 if (data
.dptr
== NULL
) {
4886 if (data
.dsize
< 12) {
4890 if (!is_domain_offline(domain
)) {
4891 uint32_t entry_seqnum
, dom_seqnum
, last_check
;
4892 uint64_t entry_timeout
;
4894 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
,
4898 entry_seqnum
= IVAL(data
.dptr
, 0);
4899 if (entry_seqnum
!= dom_seqnum
) {
4900 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4901 (int)entry_seqnum
));
4904 entry_timeout
= BVAL(data
.dptr
, 4);
4905 if (time(NULL
) > entry_timeout
) {
4906 DEBUG(10, ("Entry has timed out\n"));
4911 resp
->data
= (uint8_t *)talloc_memdup(mem_ctx
, data
.dptr
+ 12,
4913 if (resp
->data
== NULL
) {
4914 DEBUG(10, ("talloc failed\n"));
4917 resp
->length
= data
.dsize
- 12;
4921 SAFE_FREE(data
.dptr
);
4925 void wcache_store_ndr(struct winbindd_domain
*domain
, uint32_t opnum
,
4926 const DATA_BLOB
*req
, const DATA_BLOB
*resp
)
4929 uint32_t dom_seqnum
, last_check
;
4932 if (!wcache_opnum_cacheable(opnum
) ||
4933 is_my_own_sam_domain(domain
) ||
4934 is_builtin_domain(domain
)) {
4938 if (wcache
->tdb
== NULL
) {
4942 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
, &last_check
)) {
4943 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4948 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4952 timeout
= time(NULL
) + lp_winbind_cache_time();
4954 data
.dsize
= resp
->length
+ 12;
4955 data
.dptr
= talloc_array(key
.dptr
, uint8_t, data
.dsize
);
4956 if (data
.dptr
== NULL
) {
4960 SIVAL(data
.dptr
, 0, dom_seqnum
);
4961 SBVAL(data
.dptr
, 4, timeout
);
4962 memcpy(data
.dptr
+ 12, resp
->data
, resp
->length
);
4964 tdb_store(wcache
->tdb
, key
, data
, 0);
4967 TALLOC_FREE(key
.dptr
);