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 upper_name
= talloc_strdup(mem_ctx
, name
);
1115 if (upper_name
== NULL
) {
1116 return NT_STATUS_NO_MEMORY
;
1118 if (!strupper_m(upper_name
)) {
1119 talloc_free(upper_name
);
1120 return NT_STATUS_INVALID_PARAMETER
;
1123 centry
= wcache_fetch(cache
, domain
, "NSS/NA/%s", upper_name
);
1125 talloc_free(upper_name
);
1130 status
= centry
->status
;
1132 if (!NT_STATUS_IS_OK(status
)) {
1133 centry_free(centry
);
1137 *alias
= centry_string( centry
, mem_ctx
);
1139 centry_free(centry
);
1141 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1142 name
, *alias
? *alias
: "(none)"));
1144 return (*alias
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1148 /* If its not in cache and we are offline, then fail */
1150 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1151 DEBUG(8,("resolve_username_to_alias: rejecting query "
1152 "in offline mode\n"));
1153 return NT_STATUS_NOT_FOUND
;
1156 status
= nss_map_to_alias( mem_ctx
, domain
->name
, name
, alias
);
1158 if ( NT_STATUS_IS_OK( status
) ) {
1159 wcache_save_username_alias(domain
, status
, name
, *alias
);
1162 if ( NT_STATUS_EQUAL( status
, NT_STATUS_NONE_MAPPED
) ) {
1163 wcache_save_username_alias(domain
, status
, name
, "(NULL)");
1166 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1167 nt_errstr(status
)));
1169 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1170 set_domain_offline( domain
);
1176 /***************************************************************************
1177 ***************************************************************************/
1179 NTSTATUS
resolve_alias_to_username( TALLOC_CTX
*mem_ctx
,
1180 struct winbindd_domain
*domain
,
1181 const char *alias
, char **name
)
1183 struct winbind_cache
*cache
= get_cache(domain
);
1184 struct cache_entry
*centry
= NULL
;
1188 if ( domain
->internal
)
1189 return NT_STATUS_NOT_SUPPORTED
;
1194 upper_name
= talloc_strdup(mem_ctx
, alias
);
1195 if (upper_name
== NULL
) {
1196 return NT_STATUS_NO_MEMORY
;
1198 if (!strupper_m(upper_name
)) {
1199 talloc_free(upper_name
);
1200 return NT_STATUS_INVALID_PARAMETER
;
1203 centry
= wcache_fetch(cache
, domain
, "NSS/AN/%s", upper_name
);
1205 talloc_free(upper_name
);
1210 status
= centry
->status
;
1212 if (!NT_STATUS_IS_OK(status
)) {
1213 centry_free(centry
);
1217 *name
= centry_string( centry
, mem_ctx
);
1219 centry_free(centry
);
1221 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1222 alias
, *name
? *name
: "(none)"));
1224 return (*name
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1228 /* If its not in cache and we are offline, then fail */
1230 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1231 DEBUG(8,("resolve_alias_to_username: rejecting query "
1232 "in offline mode\n"));
1233 return NT_STATUS_NOT_FOUND
;
1236 /* an alias cannot contain a domain prefix or '@' */
1238 if (strchr(alias
, '\\') || strchr(alias
, '@')) {
1239 DEBUG(10,("resolve_alias_to_username: skipping fully "
1240 "qualified name %s\n", alias
));
1241 return NT_STATUS_OBJECT_NAME_INVALID
;
1244 status
= nss_map_from_alias( mem_ctx
, domain
->name
, alias
, name
);
1246 if ( NT_STATUS_IS_OK( status
) ) {
1247 wcache_save_alias_username( domain
, status
, alias
, *name
);
1250 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1251 wcache_save_alias_username(domain
, status
, alias
, "(NULL)");
1254 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1255 nt_errstr(status
)));
1257 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1258 set_domain_offline( domain
);
1264 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
1266 struct winbind_cache
*cache
= get_cache(domain
);
1268 fstring key_str
, tmp
;
1272 return NT_STATUS_INTERNAL_DB_ERROR
;
1275 if (is_null_sid(sid
)) {
1276 return NT_STATUS_INVALID_SID
;
1279 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1280 return NT_STATUS_INVALID_SID
;
1283 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
1285 data
= tdb_fetch_compat(cache
->tdb
, string_tdb_data(key_str
));
1287 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1290 SAFE_FREE(data
.dptr
);
1291 return NT_STATUS_OK
;
1294 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1295 as new salted ones. */
1297 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
1298 TALLOC_CTX
*mem_ctx
,
1299 const struct dom_sid
*sid
,
1300 const uint8
**cached_nt_pass
,
1301 const uint8
**cached_salt
)
1303 struct winbind_cache
*cache
= get_cache(domain
);
1304 struct cache_entry
*centry
= NULL
;
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
;
1333 * We don't use the time element at this moment,
1334 * but we have to consume it, so that we don't
1335 * neet to change the disk format of the cache.
1337 (void)centry_time(centry
);
1339 /* In the salted case this isn't actually the nt_hash itself,
1340 but the MD5 of the salt + nt_hash. Let the caller
1341 sort this out. It can tell as we only return the cached_salt
1342 if we are returning a salted cred. */
1344 *cached_nt_pass
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1345 if (*cached_nt_pass
== NULL
) {
1348 sid_to_fstring(sidstr
, sid
);
1350 /* Bad (old) cred cache. Delete and pretend we
1352 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1354 wcache_delete("CRED/%s", sidstr
);
1355 centry_free(centry
);
1356 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1359 /* We only have 17 bytes more data in the salted cred case. */
1360 if (centry
->len
- centry
->ofs
== 17) {
1361 *cached_salt
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1363 *cached_salt
= NULL
;
1366 dump_data_pw("cached_nt_pass", *cached_nt_pass
, NT_HASH_LEN
);
1368 dump_data_pw("cached_salt", *cached_salt
, NT_HASH_LEN
);
1371 status
= centry
->status
;
1373 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1374 sid_string_dbg(sid
), nt_errstr(status
) ));
1376 centry_free(centry
);
1380 /* Store creds for a SID - only writes out new salted ones. */
1382 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1383 const struct dom_sid
*sid
,
1384 const uint8 nt_pass
[NT_HASH_LEN
])
1386 struct cache_entry
*centry
;
1389 uint8 cred_salt
[NT_HASH_LEN
];
1390 uint8 salted_hash
[NT_HASH_LEN
];
1392 if (is_null_sid(sid
)) {
1393 return NT_STATUS_INVALID_SID
;
1396 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1397 return NT_STATUS_INVALID_SID
;
1400 centry
= centry_start(domain
, NT_STATUS_OK
);
1402 return NT_STATUS_INTERNAL_DB_ERROR
;
1405 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1407 centry_put_time(centry
, time(NULL
));
1409 /* Create a salt and then salt the hash. */
1410 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1411 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1413 centry_put_hash16(centry
, salted_hash
);
1414 centry_put_hash16(centry
, cred_salt
);
1415 centry_end(centry
, "CRED/%s", sid_to_fstring(sid_string
, sid
));
1417 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1419 centry_free(centry
);
1421 return NT_STATUS_OK
;
1425 /* Query display info. This is the basic user list fn */
1426 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
1427 TALLOC_CTX
*mem_ctx
,
1428 uint32
*num_entries
,
1429 struct wbint_userinfo
**info
)
1431 struct winbind_cache
*cache
= get_cache(domain
);
1432 struct cache_entry
*centry
= NULL
;
1434 unsigned int i
, retry
;
1435 bool old_status
= domain
->online
;
1440 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1445 *num_entries
= centry_uint32(centry
);
1447 if (*num_entries
== 0)
1450 (*info
) = talloc_array(mem_ctx
, struct wbint_userinfo
, *num_entries
);
1452 smb_panic_fn("query_user_list out of memory");
1454 for (i
=0; i
<(*num_entries
); i
++) {
1455 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
1456 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
1457 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
1458 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
1459 centry_sid(centry
, &(*info
)[i
].user_sid
);
1460 centry_sid(centry
, &(*info
)[i
].group_sid
);
1464 status
= centry
->status
;
1466 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1467 domain
->name
, nt_errstr(status
) ));
1469 centry_free(centry
);
1476 /* Return status value returned by seq number check */
1478 if (!NT_STATUS_IS_OK(domain
->last_status
))
1479 return domain
->last_status
;
1481 /* Put the query_user_list() in a retry loop. There appears to be
1482 * some bug either with Windows 2000 or Samba's handling of large
1483 * rpc replies. This manifests itself as sudden disconnection
1484 * at a random point in the enumeration of a large (60k) user list.
1485 * The retry loop simply tries the operation again. )-: It's not
1486 * pretty but an acceptable workaround until we work out what the
1487 * real problem is. */
1492 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1495 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
1496 if (!NT_STATUS_IS_OK(status
)) {
1497 DEBUG(3, ("query_user_list: returned 0x%08x, "
1498 "retrying\n", NT_STATUS_V(status
)));
1500 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1501 DEBUG(3, ("query_user_list: flushing "
1502 "connection cache\n"));
1503 invalidate_cm_connection(&domain
->conn
);
1505 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1506 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1507 if (!domain
->internal
&& old_status
) {
1508 set_domain_offline(domain
);
1510 /* store partial response. */
1511 if (*num_entries
> 0) {
1513 * humm, what about the status used for cache?
1514 * Should it be NT_STATUS_OK?
1519 * domain is offline now, and there is no user entries,
1520 * try to fetch from cache again.
1522 if (cache
->tdb
&& !domain
->online
&& !domain
->internal
&& old_status
) {
1523 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1524 /* partial response... */
1528 goto do_fetch_cache
;
1535 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1539 refresh_sequence_number(domain
, false);
1540 if (!NT_STATUS_IS_OK(status
)) {
1543 centry
= centry_start(domain
, status
);
1546 centry_put_uint32(centry
, *num_entries
);
1547 for (i
=0; i
<(*num_entries
); i
++) {
1548 centry_put_string(centry
, (*info
)[i
].acct_name
);
1549 centry_put_string(centry
, (*info
)[i
].full_name
);
1550 centry_put_string(centry
, (*info
)[i
].homedir
);
1551 centry_put_string(centry
, (*info
)[i
].shell
);
1552 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1553 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1554 if (domain
->backend
&& domain
->backend
->consistent
) {
1555 /* when the backend is consistent we can pre-prime some mappings */
1556 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1558 (*info
)[i
].acct_name
,
1559 &(*info
)[i
].user_sid
,
1561 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1562 &(*info
)[i
].user_sid
,
1564 (*info
)[i
].acct_name
,
1566 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1569 centry_end(centry
, "UL/%s", domain
->name
);
1570 centry_free(centry
);
1576 /* list all domain groups */
1577 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
1578 TALLOC_CTX
*mem_ctx
,
1579 uint32
*num_entries
,
1580 struct wb_acct_info
**info
)
1582 struct winbind_cache
*cache
= get_cache(domain
);
1583 struct cache_entry
*centry
= NULL
;
1588 old_status
= domain
->online
;
1592 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1597 *num_entries
= centry_uint32(centry
);
1599 if (*num_entries
== 0)
1602 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1604 smb_panic_fn("enum_dom_groups out of memory");
1606 for (i
=0; i
<(*num_entries
); i
++) {
1607 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1608 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1609 (*info
)[i
].rid
= centry_uint32(centry
);
1613 status
= centry
->status
;
1615 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1616 domain
->name
, nt_errstr(status
) ));
1618 centry_free(centry
);
1625 /* Return status value returned by seq number check */
1627 if (!NT_STATUS_IS_OK(domain
->last_status
))
1628 return domain
->last_status
;
1630 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1633 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1635 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1636 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1637 if (!domain
->internal
&& old_status
) {
1638 set_domain_offline(domain
);
1642 !domain
->internal
&&
1644 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1646 goto do_fetch_cache
;
1651 refresh_sequence_number(domain
, false);
1652 if (!NT_STATUS_IS_OK(status
)) {
1655 centry
= centry_start(domain
, status
);
1658 centry_put_uint32(centry
, *num_entries
);
1659 for (i
=0; i
<(*num_entries
); i
++) {
1660 centry_put_string(centry
, (*info
)[i
].acct_name
);
1661 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1662 centry_put_uint32(centry
, (*info
)[i
].rid
);
1664 centry_end(centry
, "GL/%s/domain", domain
->name
);
1665 centry_free(centry
);
1671 /* list all domain groups */
1672 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
1673 TALLOC_CTX
*mem_ctx
,
1674 uint32
*num_entries
,
1675 struct wb_acct_info
**info
)
1677 struct winbind_cache
*cache
= get_cache(domain
);
1678 struct cache_entry
*centry
= NULL
;
1683 old_status
= domain
->online
;
1687 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1692 *num_entries
= centry_uint32(centry
);
1694 if (*num_entries
== 0)
1697 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1699 smb_panic_fn("enum_dom_groups out of memory");
1701 for (i
=0; i
<(*num_entries
); i
++) {
1702 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1703 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1704 (*info
)[i
].rid
= centry_uint32(centry
);
1709 /* If we are returning cached data and the domain controller
1710 is down then we don't know whether the data is up to date
1711 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1714 if (wcache_server_down(domain
)) {
1715 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1716 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1718 status
= centry
->status
;
1720 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1721 domain
->name
, nt_errstr(status
) ));
1723 centry_free(centry
);
1730 /* Return status value returned by seq number check */
1732 if (!NT_STATUS_IS_OK(domain
->last_status
))
1733 return domain
->last_status
;
1735 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1738 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1740 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1741 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1742 if (!domain
->internal
&& old_status
) {
1743 set_domain_offline(domain
);
1746 !domain
->internal
&&
1749 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1751 goto do_fetch_cache
;
1756 refresh_sequence_number(domain
, false);
1757 if (!NT_STATUS_IS_OK(status
)) {
1760 centry
= centry_start(domain
, status
);
1763 centry_put_uint32(centry
, *num_entries
);
1764 for (i
=0; i
<(*num_entries
); i
++) {
1765 centry_put_string(centry
, (*info
)[i
].acct_name
);
1766 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1767 centry_put_uint32(centry
, (*info
)[i
].rid
);
1769 centry_end(centry
, "GL/%s/local", domain
->name
);
1770 centry_free(centry
);
1776 NTSTATUS
wcache_name_to_sid(struct winbindd_domain
*domain
,
1777 const char *domain_name
,
1779 struct dom_sid
*sid
,
1780 enum lsa_SidType
*type
)
1782 struct winbind_cache
*cache
= get_cache(domain
);
1783 struct cache_entry
*centry
;
1787 if (cache
->tdb
== NULL
) {
1788 return NT_STATUS_NOT_FOUND
;
1791 uname
= talloc_strdup_upper(talloc_tos(), name
);
1792 if (uname
== NULL
) {
1793 return NT_STATUS_NO_MEMORY
;
1796 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1798 if (centry
== NULL
) {
1799 return NT_STATUS_NOT_FOUND
;
1802 status
= centry
->status
;
1803 if (NT_STATUS_IS_OK(status
)) {
1804 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1805 centry_sid(centry
, sid
);
1808 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1809 "%s\n", domain
->name
, nt_errstr(status
) ));
1811 centry_free(centry
);
1815 /* convert a single name to a sid in a domain */
1816 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
1817 TALLOC_CTX
*mem_ctx
,
1818 const char *domain_name
,
1821 struct dom_sid
*sid
,
1822 enum lsa_SidType
*type
)
1827 old_status
= domain
->online
;
1829 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1830 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1836 /* If the seq number check indicated that there is a problem
1837 * with this DC, then return that status... except for
1838 * access_denied. This is special because the dc may be in
1839 * "restrict anonymous = 1" mode, in which case it will deny
1840 * most unauthenticated operations, but *will* allow the LSA
1841 * name-to-sid that we try as a fallback. */
1843 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1844 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1845 return domain
->last_status
;
1847 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1850 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
,
1851 name
, flags
, sid
, type
);
1853 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1854 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1855 if (!domain
->internal
&& old_status
) {
1856 set_domain_offline(domain
);
1858 if (!domain
->internal
&&
1861 NTSTATUS cache_status
;
1862 cache_status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1863 return cache_status
;
1867 refresh_sequence_number(domain
, false);
1869 if (domain
->online
&&
1870 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1871 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1873 /* Only save the reverse mapping if this was not a UPN */
1874 if (!strchr(name
, '@')) {
1875 if (!strupper_m(discard_const_p(char, domain_name
))) {
1876 return NT_STATUS_INVALID_PARAMETER
;
1878 (void)strlower_m(discard_const_p(char, name
));
1879 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1886 NTSTATUS
wcache_sid_to_name(struct winbindd_domain
*domain
,
1887 const struct dom_sid
*sid
,
1888 TALLOC_CTX
*mem_ctx
,
1891 enum lsa_SidType
*type
)
1893 struct winbind_cache
*cache
= get_cache(domain
);
1894 struct cache_entry
*centry
;
1898 if (cache
->tdb
== NULL
) {
1899 return NT_STATUS_NOT_FOUND
;
1902 sid_string
= sid_string_tos(sid
);
1903 if (sid_string
== NULL
) {
1904 return NT_STATUS_NO_MEMORY
;
1907 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_string
);
1908 TALLOC_FREE(sid_string
);
1909 if (centry
== NULL
) {
1910 return NT_STATUS_NOT_FOUND
;
1913 if (NT_STATUS_IS_OK(centry
->status
)) {
1914 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1915 *domain_name
= centry_string(centry
, mem_ctx
);
1916 *name
= centry_string(centry
, mem_ctx
);
1919 status
= centry
->status
;
1920 centry_free(centry
);
1922 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1923 "%s\n", domain
->name
, nt_errstr(status
) ));
1928 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1930 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1931 TALLOC_CTX
*mem_ctx
,
1932 const struct dom_sid
*sid
,
1935 enum lsa_SidType
*type
)
1940 old_status
= domain
->online
;
1941 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
1943 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1948 *domain_name
= NULL
;
1950 /* If the seq number check indicated that there is a problem
1951 * with this DC, then return that status... except for
1952 * access_denied. This is special because the dc may be in
1953 * "restrict anonymous = 1" mode, in which case it will deny
1954 * most unauthenticated operations, but *will* allow the LSA
1955 * sid-to-name that we try as a fallback. */
1957 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1958 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1959 return domain
->last_status
;
1961 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1964 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1966 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1967 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1968 if (!domain
->internal
&& old_status
) {
1969 set_domain_offline(domain
);
1971 if (!domain
->internal
&&
1974 NTSTATUS cache_status
;
1975 cache_status
= wcache_sid_to_name(domain
, sid
, mem_ctx
,
1976 domain_name
, name
, type
);
1977 return cache_status
;
1981 refresh_sequence_number(domain
, false);
1982 if (!NT_STATUS_IS_OK(status
)) {
1985 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
1987 /* We can't save the name to sid mapping here, as with sid history a
1988 * later name2sid would give the wrong sid. */
1993 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
1994 TALLOC_CTX
*mem_ctx
,
1995 const struct dom_sid
*domain_sid
,
2000 enum lsa_SidType
**types
)
2002 struct winbind_cache
*cache
= get_cache(domain
);
2004 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
2009 old_status
= domain
->online
;
2010 *domain_name
= NULL
;
2018 if (num_rids
== 0) {
2019 return NT_STATUS_OK
;
2022 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2023 *types
= talloc_array(mem_ctx
, enum lsa_SidType
, num_rids
);
2025 if ((*names
== NULL
) || (*types
== NULL
)) {
2026 result
= NT_STATUS_NO_MEMORY
;
2030 have_mapped
= have_unmapped
= false;
2032 for (i
=0; i
<num_rids
; i
++) {
2034 struct cache_entry
*centry
;
2037 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2038 result
= NT_STATUS_INTERNAL_ERROR
;
2042 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2043 sid_to_fstring(tmp
, &sid
));
2048 (*types
)[i
] = SID_NAME_UNKNOWN
;
2049 (*names
)[i
] = talloc_strdup(*names
, "");
2051 if (NT_STATUS_IS_OK(centry
->status
)) {
2054 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2056 dom
= centry_string(centry
, mem_ctx
);
2057 if (*domain_name
== NULL
) {
2063 (*names
)[i
] = centry_string(centry
, *names
);
2065 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)
2066 || NT_STATUS_EQUAL(centry
->status
, STATUS_SOME_UNMAPPED
)) {
2067 have_unmapped
= true;
2070 /* something's definitely wrong */
2071 result
= centry
->status
;
2075 centry_free(centry
);
2079 return NT_STATUS_NONE_MAPPED
;
2081 if (!have_unmapped
) {
2082 return NT_STATUS_OK
;
2084 return STATUS_SOME_UNMAPPED
;
2088 TALLOC_FREE(*names
);
2089 TALLOC_FREE(*types
);
2091 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
2092 rids
, num_rids
, domain_name
,
2095 if (NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
2096 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2097 if (!domain
->internal
&& old_status
) {
2098 set_domain_offline(domain
);
2101 !domain
->internal
&&
2104 have_mapped
= have_unmapped
= false;
2106 for (i
=0; i
<num_rids
; i
++) {
2108 struct cache_entry
*centry
;
2111 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2112 result
= NT_STATUS_INTERNAL_ERROR
;
2116 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2117 sid_to_fstring(tmp
, &sid
));
2119 (*types
)[i
] = SID_NAME_UNKNOWN
;
2120 (*names
)[i
] = talloc_strdup(*names
, "");
2124 (*types
)[i
] = SID_NAME_UNKNOWN
;
2125 (*names
)[i
] = talloc_strdup(*names
, "");
2127 if (NT_STATUS_IS_OK(centry
->status
)) {
2130 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2132 dom
= centry_string(centry
, mem_ctx
);
2133 if (*domain_name
== NULL
) {
2139 (*names
)[i
] = centry_string(centry
, *names
);
2141 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)) {
2142 have_unmapped
= true;
2145 /* something's definitely wrong */
2146 result
= centry
->status
;
2150 centry_free(centry
);
2154 return NT_STATUS_NONE_MAPPED
;
2156 if (!have_unmapped
) {
2157 return NT_STATUS_OK
;
2159 return STATUS_SOME_UNMAPPED
;
2163 None of the queried rids has been found so save all negative entries
2165 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
2166 for (i
= 0; i
< num_rids
; i
++) {
2168 const char *name
= "";
2169 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
2170 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
2172 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2173 return NT_STATUS_INTERNAL_ERROR
;
2176 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2184 Some or all of the queried rids have been found.
2186 if (!NT_STATUS_IS_OK(result
) &&
2187 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
2191 refresh_sequence_number(domain
, false);
2193 for (i
=0; i
<num_rids
; i
++) {
2197 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2198 result
= NT_STATUS_INTERNAL_ERROR
;
2202 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
2203 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
2205 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2206 (*names
)[i
], (*types
)[i
]);
2212 TALLOC_FREE(*names
);
2213 TALLOC_FREE(*types
);
2217 NTSTATUS
wcache_query_user(struct winbindd_domain
*domain
,
2218 TALLOC_CTX
*mem_ctx
,
2219 const struct dom_sid
*user_sid
,
2220 struct wbint_userinfo
*info
)
2222 struct winbind_cache
*cache
= get_cache(domain
);
2223 struct cache_entry
*centry
= NULL
;
2227 if (cache
->tdb
== NULL
) {
2228 return NT_STATUS_NOT_FOUND
;
2231 sid_string
= sid_string_tos(user_sid
);
2232 if (sid_string
== NULL
) {
2233 return NT_STATUS_NO_MEMORY
;
2236 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string
);
2237 TALLOC_FREE(sid_string
);
2238 if (centry
== NULL
) {
2239 return NT_STATUS_NOT_FOUND
;
2243 * If we have an access denied cache entry and a cached info3
2244 * in the samlogon cache then do a query. This will force the
2245 * rpc back end to return the info3 data.
2248 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
) &&
2249 netsamlogon_cache_have(user_sid
)) {
2250 DEBUG(10, ("query_user: cached access denied and have cached "
2252 domain
->last_status
= NT_STATUS_OK
;
2253 centry_free(centry
);
2254 return NT_STATUS_NOT_FOUND
;
2257 /* if status is not ok then this is a negative hit
2258 and the rest of the data doesn't matter */
2259 status
= centry
->status
;
2260 if (NT_STATUS_IS_OK(status
)) {
2261 info
->acct_name
= centry_string(centry
, mem_ctx
);
2262 info
->full_name
= centry_string(centry
, mem_ctx
);
2263 info
->homedir
= centry_string(centry
, mem_ctx
);
2264 info
->shell
= centry_string(centry
, mem_ctx
);
2265 info
->primary_gid
= centry_uint32(centry
);
2266 centry_sid(centry
, &info
->user_sid
);
2267 centry_sid(centry
, &info
->group_sid
);
2270 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2271 "%s\n", domain
->name
, nt_errstr(status
) ));
2273 centry_free(centry
);
2277 /* Lookup user information from a rid */
2278 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
2279 TALLOC_CTX
*mem_ctx
,
2280 const struct dom_sid
*user_sid
,
2281 struct wbint_userinfo
*info
)
2286 old_status
= domain
->online
;
2287 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2288 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2294 /* Return status value returned by seq number check */
2296 if (!NT_STATUS_IS_OK(domain
->last_status
))
2297 return domain
->last_status
;
2299 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2302 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
2304 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2305 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2306 if (!domain
->internal
&& old_status
) {
2307 set_domain_offline(domain
);
2309 if (!domain
->internal
&&
2312 NTSTATUS cache_status
;
2313 cache_status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2314 return cache_status
;
2318 refresh_sequence_number(domain
, false);
2319 if (!NT_STATUS_IS_OK(status
)) {
2322 wcache_save_user(domain
, status
, info
);
2327 NTSTATUS
wcache_lookup_usergroups(struct winbindd_domain
*domain
,
2328 TALLOC_CTX
*mem_ctx
,
2329 const struct dom_sid
*user_sid
,
2330 uint32_t *pnum_sids
,
2331 struct dom_sid
**psids
)
2333 struct winbind_cache
*cache
= get_cache(domain
);
2334 struct cache_entry
*centry
= NULL
;
2336 uint32_t i
, num_sids
;
2337 struct dom_sid
*sids
;
2340 if (cache
->tdb
== NULL
) {
2341 return NT_STATUS_NOT_FOUND
;
2344 centry
= wcache_fetch(cache
, domain
, "UG/%s",
2345 sid_to_fstring(sid_string
, user_sid
));
2346 if (centry
== NULL
) {
2347 return NT_STATUS_NOT_FOUND
;
2350 /* If we have an access denied cache entry and a cached info3 in the
2351 samlogon cache then do a query. This will force the rpc back end
2352 to return the info3 data. */
2354 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)
2355 && netsamlogon_cache_have(user_sid
)) {
2356 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2358 domain
->last_status
= NT_STATUS_OK
;
2359 centry_free(centry
);
2360 return NT_STATUS_NOT_FOUND
;
2363 num_sids
= centry_uint32(centry
);
2364 sids
= talloc_array(mem_ctx
, struct dom_sid
, num_sids
);
2366 centry_free(centry
);
2367 return NT_STATUS_NO_MEMORY
;
2370 for (i
=0; i
<num_sids
; i
++) {
2371 centry_sid(centry
, &sids
[i
]);
2374 status
= centry
->status
;
2376 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2377 "status: %s\n", domain
->name
, nt_errstr(status
)));
2379 centry_free(centry
);
2381 *pnum_sids
= num_sids
;
2386 /* Lookup groups a user is a member of. */
2387 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
2388 TALLOC_CTX
*mem_ctx
,
2389 const struct dom_sid
*user_sid
,
2390 uint32
*num_groups
, struct dom_sid
**user_gids
)
2392 struct cache_entry
*centry
= NULL
;
2398 old_status
= domain
->online
;
2399 status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2400 num_groups
, user_gids
);
2401 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2406 (*user_gids
) = NULL
;
2408 /* Return status value returned by seq number check */
2410 if (!NT_STATUS_IS_OK(domain
->last_status
))
2411 return domain
->last_status
;
2413 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2416 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
2418 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2419 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2420 if (!domain
->internal
&& old_status
) {
2421 set_domain_offline(domain
);
2423 if (!domain
->internal
&&
2426 NTSTATUS cache_status
;
2427 cache_status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2428 num_groups
, user_gids
);
2429 return cache_status
;
2432 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
2436 refresh_sequence_number(domain
, false);
2437 if (!NT_STATUS_IS_OK(status
)) {
2440 centry
= centry_start(domain
, status
);
2444 centry_put_uint32(centry
, *num_groups
);
2445 for (i
=0; i
<(*num_groups
); i
++) {
2446 centry_put_sid(centry
, &(*user_gids
)[i
]);
2449 centry_end(centry
, "UG/%s", sid_to_fstring(sid_string
, user_sid
));
2450 centry_free(centry
);
2456 static char *wcache_make_sidlist(TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2457 const struct dom_sid
*sids
)
2462 sidlist
= talloc_strdup(mem_ctx
, "");
2463 if (sidlist
== NULL
) {
2466 for (i
=0; i
<num_sids
; i
++) {
2468 sidlist
= talloc_asprintf_append_buffer(
2469 sidlist
, "/%s", sid_to_fstring(tmp
, &sids
[i
]));
2470 if (sidlist
== NULL
) {
2477 NTSTATUS
wcache_lookup_useraliases(struct winbindd_domain
*domain
,
2478 TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2479 const struct dom_sid
*sids
,
2480 uint32_t *pnum_aliases
, uint32_t **paliases
)
2482 struct winbind_cache
*cache
= get_cache(domain
);
2483 struct cache_entry
*centry
= NULL
;
2484 uint32_t num_aliases
;
2490 if (cache
->tdb
== NULL
) {
2491 return NT_STATUS_NOT_FOUND
;
2494 if (num_sids
== 0) {
2497 return NT_STATUS_OK
;
2500 /* We need to cache indexed by the whole list of SIDs, the aliases
2501 * resulting might come from any of the SIDs. */
2503 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2504 if (sidlist
== NULL
) {
2505 return NT_STATUS_NO_MEMORY
;
2508 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2509 TALLOC_FREE(sidlist
);
2510 if (centry
== NULL
) {
2511 return NT_STATUS_NOT_FOUND
;
2514 num_aliases
= centry_uint32(centry
);
2515 aliases
= talloc_array(mem_ctx
, uint32_t, num_aliases
);
2516 if (aliases
== NULL
) {
2517 centry_free(centry
);
2518 return NT_STATUS_NO_MEMORY
;
2521 for (i
=0; i
<num_aliases
; i
++) {
2522 aliases
[i
] = centry_uint32(centry
);
2525 status
= centry
->status
;
2527 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2528 "status %s\n", domain
->name
, nt_errstr(status
)));
2530 centry_free(centry
);
2532 *pnum_aliases
= num_aliases
;
2533 *paliases
= aliases
;
2538 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
2539 TALLOC_CTX
*mem_ctx
,
2540 uint32 num_sids
, const struct dom_sid
*sids
,
2541 uint32
*num_aliases
, uint32
**alias_rids
)
2543 struct cache_entry
*centry
= NULL
;
2549 old_status
= domain
->online
;
2550 status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
2551 num_aliases
, alias_rids
);
2552 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2557 (*alias_rids
) = NULL
;
2559 if (!NT_STATUS_IS_OK(domain
->last_status
))
2560 return domain
->last_status
;
2562 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2563 "for domain %s\n", domain
->name
));
2565 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2566 if (sidlist
== NULL
) {
2567 return NT_STATUS_NO_MEMORY
;
2570 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2572 num_aliases
, alias_rids
);
2574 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2575 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2576 if (!domain
->internal
&& old_status
) {
2577 set_domain_offline(domain
);
2579 if (!domain
->internal
&&
2582 NTSTATUS cache_status
;
2583 cache_status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
,
2584 sids
, num_aliases
, alias_rids
);
2585 return cache_status
;
2589 refresh_sequence_number(domain
, false);
2590 if (!NT_STATUS_IS_OK(status
)) {
2593 centry
= centry_start(domain
, status
);
2596 centry_put_uint32(centry
, *num_aliases
);
2597 for (i
=0; i
<(*num_aliases
); i
++)
2598 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2599 centry_end(centry
, "UA%s", sidlist
);
2600 centry_free(centry
);
2606 NTSTATUS
wcache_lookup_groupmem(struct winbindd_domain
*domain
,
2607 TALLOC_CTX
*mem_ctx
,
2608 const struct dom_sid
*group_sid
,
2609 uint32_t *num_names
,
2610 struct dom_sid
**sid_mem
, char ***names
,
2611 uint32_t **name_types
)
2613 struct winbind_cache
*cache
= get_cache(domain
);
2614 struct cache_entry
*centry
= NULL
;
2619 if (cache
->tdb
== NULL
) {
2620 return NT_STATUS_NOT_FOUND
;
2623 sid_string
= sid_string_tos(group_sid
);
2624 if (sid_string
== NULL
) {
2625 return NT_STATUS_NO_MEMORY
;
2628 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_string
);
2629 TALLOC_FREE(sid_string
);
2630 if (centry
== NULL
) {
2631 return NT_STATUS_NOT_FOUND
;
2638 *num_names
= centry_uint32(centry
);
2639 if (*num_names
== 0) {
2640 centry_free(centry
);
2641 return NT_STATUS_OK
;
2644 *sid_mem
= talloc_array(mem_ctx
, struct dom_sid
, *num_names
);
2645 *names
= talloc_array(mem_ctx
, char *, *num_names
);
2646 *name_types
= talloc_array(mem_ctx
, uint32
, *num_names
);
2648 if ((*sid_mem
== NULL
) || (*names
== NULL
) || (*name_types
== NULL
)) {
2649 TALLOC_FREE(*sid_mem
);
2650 TALLOC_FREE(*names
);
2651 TALLOC_FREE(*name_types
);
2652 centry_free(centry
);
2653 return NT_STATUS_NO_MEMORY
;
2656 for (i
=0; i
<(*num_names
); i
++) {
2657 centry_sid(centry
, &(*sid_mem
)[i
]);
2658 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2659 (*name_types
)[i
] = centry_uint32(centry
);
2662 status
= centry
->status
;
2664 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2665 "status: %s\n", domain
->name
, nt_errstr(status
)));
2667 centry_free(centry
);
2671 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
2672 TALLOC_CTX
*mem_ctx
,
2673 const struct dom_sid
*group_sid
,
2674 enum lsa_SidType type
,
2676 struct dom_sid
**sid_mem
, char ***names
,
2677 uint32
**name_types
)
2679 struct cache_entry
*centry
= NULL
;
2685 old_status
= domain
->online
;
2686 status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2687 sid_mem
, names
, name_types
);
2688 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2695 (*name_types
) = NULL
;
2697 /* Return status value returned by seq number check */
2699 if (!NT_STATUS_IS_OK(domain
->last_status
))
2700 return domain
->last_status
;
2702 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2705 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
,
2707 sid_mem
, names
, name_types
);
2709 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2710 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2711 if (!domain
->internal
&& old_status
) {
2712 set_domain_offline(domain
);
2714 if (!domain
->internal
&&
2717 NTSTATUS cache_status
;
2718 cache_status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
,
2719 num_names
, sid_mem
, names
,
2721 return cache_status
;
2725 refresh_sequence_number(domain
, false);
2726 if (!NT_STATUS_IS_OK(status
)) {
2729 centry
= centry_start(domain
, status
);
2732 centry_put_uint32(centry
, *num_names
);
2733 for (i
=0; i
<(*num_names
); i
++) {
2734 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2735 centry_put_string(centry
, (*names
)[i
]);
2736 centry_put_uint32(centry
, (*name_types
)[i
]);
2738 centry_end(centry
, "GM/%s", sid_to_fstring(sid_string
, group_sid
));
2739 centry_free(centry
);
2745 /* find the sequence number for a domain */
2746 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
2748 refresh_sequence_number(domain
, false);
2750 *seq
= domain
->sequence_number
;
2752 return NT_STATUS_OK
;
2755 /* enumerate trusted domains
2756 * (we need to have the list of trustdoms in the cache when we go offline) -
2758 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
2759 TALLOC_CTX
*mem_ctx
,
2760 struct netr_DomainTrustList
*trusts
)
2763 struct winbind_cache
*cache
;
2764 struct winbindd_tdc_domain
*dom_list
= NULL
;
2765 size_t num_domains
= 0;
2766 bool retval
= false;
2770 old_status
= domain
->online
;
2772 trusts
->array
= NULL
;
2774 cache
= get_cache(domain
);
2775 if (!cache
|| !cache
->tdb
) {
2779 if (domain
->online
) {
2783 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2784 if (!retval
|| !num_domains
|| !dom_list
) {
2785 TALLOC_FREE(dom_list
);
2790 trusts
->array
= talloc_zero_array(mem_ctx
, struct netr_DomainTrust
, num_domains
);
2791 if (!trusts
->array
) {
2792 TALLOC_FREE(dom_list
);
2793 return NT_STATUS_NO_MEMORY
;
2796 for (i
= 0; i
< num_domains
; i
++) {
2797 struct netr_DomainTrust
*trust
;
2798 struct dom_sid
*sid
;
2799 struct winbindd_domain
*dom
;
2801 dom
= find_domain_from_name_noinit(dom_list
[i
].domain_name
);
2802 if (dom
&& dom
->internal
) {
2806 trust
= &trusts
->array
[trusts
->count
];
2807 trust
->netbios_name
= talloc_strdup(trusts
->array
, dom_list
[i
].domain_name
);
2808 trust
->dns_name
= talloc_strdup(trusts
->array
, dom_list
[i
].dns_name
);
2809 sid
= talloc(trusts
->array
, struct dom_sid
);
2810 if (!trust
->netbios_name
|| !trust
->dns_name
||
2812 TALLOC_FREE(dom_list
);
2813 TALLOC_FREE(trusts
->array
);
2814 return NT_STATUS_NO_MEMORY
;
2817 trust
->trust_flags
= dom_list
[i
].trust_flags
;
2818 trust
->trust_attributes
= dom_list
[i
].trust_attribs
;
2819 trust
->trust_type
= dom_list
[i
].trust_type
;
2820 sid_copy(sid
, &dom_list
[i
].sid
);
2825 TALLOC_FREE(dom_list
);
2826 return NT_STATUS_OK
;
2829 /* Return status value returned by seq number check */
2831 if (!NT_STATUS_IS_OK(domain
->last_status
))
2832 return domain
->last_status
;
2834 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2837 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, trusts
);
2839 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2840 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2841 if (!domain
->internal
&& old_status
) {
2842 set_domain_offline(domain
);
2844 if (!domain
->internal
&&
2847 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2848 if (retval
&& num_domains
&& dom_list
) {
2849 TALLOC_FREE(trusts
->array
);
2851 goto do_fetch_cache
;
2855 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2856 * so that the generic centry handling still applies correctly -
2859 if (!NT_STATUS_IS_ERR(status
)) {
2860 status
= NT_STATUS_OK
;
2865 /* get lockout policy */
2866 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
2867 TALLOC_CTX
*mem_ctx
,
2868 struct samr_DomInfo12
*policy
)
2870 struct winbind_cache
*cache
= get_cache(domain
);
2871 struct cache_entry
*centry
= NULL
;
2875 old_status
= domain
->online
;
2879 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2885 policy
->lockout_duration
= centry_nttime(centry
);
2886 policy
->lockout_window
= centry_nttime(centry
);
2887 policy
->lockout_threshold
= centry_uint16(centry
);
2889 status
= centry
->status
;
2891 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2892 domain
->name
, nt_errstr(status
) ));
2894 centry_free(centry
);
2898 ZERO_STRUCTP(policy
);
2900 /* Return status value returned by seq number check */
2902 if (!NT_STATUS_IS_OK(domain
->last_status
))
2903 return domain
->last_status
;
2905 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2908 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2910 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2911 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2912 if (!domain
->internal
&& old_status
) {
2913 set_domain_offline(domain
);
2916 !domain
->internal
&&
2919 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2921 goto do_fetch_cache
;
2926 refresh_sequence_number(domain
, false);
2927 if (!NT_STATUS_IS_OK(status
)) {
2930 wcache_save_lockout_policy(domain
, status
, policy
);
2935 /* get password policy */
2936 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
2937 TALLOC_CTX
*mem_ctx
,
2938 struct samr_DomInfo1
*policy
)
2940 struct winbind_cache
*cache
= get_cache(domain
);
2941 struct cache_entry
*centry
= NULL
;
2945 old_status
= domain
->online
;
2949 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2955 policy
->min_password_length
= centry_uint16(centry
);
2956 policy
->password_history_length
= centry_uint16(centry
);
2957 policy
->password_properties
= centry_uint32(centry
);
2958 policy
->max_password_age
= centry_nttime(centry
);
2959 policy
->min_password_age
= centry_nttime(centry
);
2961 status
= centry
->status
;
2963 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2964 domain
->name
, nt_errstr(status
) ));
2966 centry_free(centry
);
2970 ZERO_STRUCTP(policy
);
2972 /* Return status value returned by seq number check */
2974 if (!NT_STATUS_IS_OK(domain
->last_status
))
2975 return domain
->last_status
;
2977 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2980 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
2982 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2983 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2984 if (!domain
->internal
&& old_status
) {
2985 set_domain_offline(domain
);
2988 !domain
->internal
&&
2991 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2993 goto do_fetch_cache
;
2998 refresh_sequence_number(domain
, false);
2999 if (!NT_STATUS_IS_OK(status
)) {
3002 wcache_save_password_policy(domain
, status
, policy
);
3008 /* Invalidate cached user and group lists coherently */
3010 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3013 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
3014 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
3015 tdb_delete(the_tdb
, kbuf
);
3020 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3022 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
3023 const struct dom_sid
*sid
)
3025 fstring key_str
, sid_string
;
3026 struct winbind_cache
*cache
;
3028 /* dont clear cached U/SID and UG/SID entries when we want to logon
3031 if (lp_winbind_offline_logon()) {
3038 cache
= get_cache(domain
);
3044 /* Clear U/SID cache entry */
3045 fstr_sprintf(key_str
, "U/%s", sid_to_fstring(sid_string
, sid
));
3046 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3047 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3049 /* Clear UG/SID cache entry */
3050 fstr_sprintf(key_str
, "UG/%s", sid_to_fstring(sid_string
, sid
));
3051 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3052 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3054 /* Samba/winbindd never needs this. */
3055 netsamlogon_clear_cached_user(sid
);
3058 bool wcache_invalidate_cache(void)
3060 struct winbindd_domain
*domain
;
3062 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3063 struct winbind_cache
*cache
= get_cache(domain
);
3065 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3066 "entries for %s\n", domain
->name
));
3069 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3078 bool wcache_invalidate_cache_noinit(void)
3080 struct winbindd_domain
*domain
;
3082 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3083 struct winbind_cache
*cache
;
3085 /* Skip uninitialized domains. */
3086 if (!domain
->initialized
&& !domain
->internal
) {
3090 cache
= get_cache(domain
);
3092 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3093 "entries for %s\n", domain
->name
));
3096 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3098 * Flushing cache has nothing to with domains.
3099 * return here if we successfully flushed once.
3100 * To avoid unnecessary traversing the cache.
3111 bool init_wcache(void)
3113 if (wcache
== NULL
) {
3114 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
3115 ZERO_STRUCTP(wcache
);
3118 if (wcache
->tdb
!= NULL
)
3121 /* when working offline we must not clear the cache on restart */
3122 wcache
->tdb
= tdb_open_log(state_path("winbindd_cache.tdb"),
3123 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3124 TDB_INCOMPATIBLE_HASH
|
3125 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3126 O_RDWR
|O_CREAT
, 0600);
3128 if (wcache
->tdb
== NULL
) {
3129 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3136 /************************************************************************
3137 This is called by the parent to initialize the cache file.
3138 We don't need sophisticated locking here as we know we're the
3140 ************************************************************************/
3142 bool initialize_winbindd_cache(void)
3144 bool cache_bad
= true;
3147 if (!init_wcache()) {
3148 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3152 /* Check version number. */
3153 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
3154 vers
== WINBINDD_CACHE_VERSION
) {
3159 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3160 "and re-creating with version number %d\n",
3161 WINBINDD_CACHE_VERSION
));
3163 tdb_close(wcache
->tdb
);
3166 if (unlink(state_path("winbindd_cache.tdb")) == -1) {
3167 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3168 state_path("winbindd_cache.tdb"),
3172 if (!init_wcache()) {
3173 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3174 "init_wcache failed.\n"));
3178 /* Write the version. */
3179 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
3180 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3181 tdb_errorstr_compat(wcache
->tdb
) ));
3186 tdb_close(wcache
->tdb
);
3191 void close_winbindd_cache(void)
3197 tdb_close(wcache
->tdb
);
3202 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*sid
,
3203 char **domain_name
, char **name
,
3204 enum lsa_SidType
*type
)
3206 struct winbindd_domain
*domain
;
3209 domain
= find_lookup_domain_from_sid(sid
);
3210 if (domain
== NULL
) {
3213 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
3215 return NT_STATUS_IS_OK(status
);
3218 bool lookup_cached_name(const char *domain_name
,
3220 struct dom_sid
*sid
,
3221 enum lsa_SidType
*type
)
3223 struct winbindd_domain
*domain
;
3225 bool original_online_state
;
3227 domain
= find_lookup_domain_from_name(domain_name
);
3228 if (domain
== NULL
) {
3232 /* If we are doing a cached logon, temporarily set the domain
3233 offline so the cache won't expire the entry */
3235 original_online_state
= domain
->online
;
3236 domain
->online
= false;
3237 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
3238 domain
->online
= original_online_state
;
3240 return NT_STATUS_IS_OK(status
);
3243 void cache_name2sid(struct winbindd_domain
*domain
,
3244 const char *domain_name
, const char *name
,
3245 enum lsa_SidType type
, const struct dom_sid
*sid
)
3247 refresh_sequence_number(domain
, false);
3248 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
3253 * The original idea that this cache only contains centries has
3254 * been blurred - now other stuff gets put in here. Ensure we
3255 * ignore these things on cleanup.
3258 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
3259 TDB_DATA dbuf
, void *state
)
3261 struct cache_entry
*centry
;
3263 if (is_non_centry_key(kbuf
)) {
3267 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
3272 if (!NT_STATUS_IS_OK(centry
->status
)) {
3273 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
3274 tdb_delete(the_tdb
, kbuf
);
3277 centry_free(centry
);
3281 /* flush the cache */
3282 void wcache_flush_cache(void)
3287 tdb_close(wcache
->tdb
);
3290 if (!winbindd_use_cache()) {
3294 /* when working offline we must not clear the cache on restart */
3295 wcache
->tdb
= tdb_open_log(state_path("winbindd_cache.tdb"),
3296 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3297 TDB_INCOMPATIBLE_HASH
|
3298 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3299 O_RDWR
|O_CREAT
, 0600);
3302 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3306 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
3308 DEBUG(10,("wcache_flush_cache success\n"));
3311 /* Count cached creds */
3313 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3316 int *cred_count
= (int*)state
;
3318 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3324 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
3326 struct winbind_cache
*cache
= get_cache(domain
);
3331 return NT_STATUS_INTERNAL_DB_ERROR
;
3334 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
3336 return NT_STATUS_OK
;
3340 struct cred_list
*prev
, *next
;
3345 static struct cred_list
*wcache_cred_list
;
3347 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3350 struct cred_list
*cred
;
3352 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3354 cred
= SMB_MALLOC_P(struct cred_list
);
3356 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3362 /* save a copy of the key */
3364 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
3365 DLIST_ADD(wcache_cred_list
, cred
);
3371 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
3373 struct winbind_cache
*cache
= get_cache(domain
);
3376 struct cred_list
*cred
, *oldest
= NULL
;
3379 return NT_STATUS_INTERNAL_DB_ERROR
;
3382 /* we possibly already have an entry */
3383 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
3385 fstring key_str
, tmp
;
3387 DEBUG(11,("we already have an entry, deleting that\n"));
3389 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
3391 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3393 return NT_STATUS_OK
;
3396 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
3398 return NT_STATUS_OK
;
3399 } else if ((ret
< 0) || (wcache_cred_list
== NULL
)) {
3400 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3403 ZERO_STRUCTP(oldest
);
3405 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
3410 data
= tdb_fetch_compat(cache
->tdb
, string_tdb_data(cred
->name
));
3412 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3414 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3418 t
= IVAL(data
.dptr
, 0);
3419 SAFE_FREE(data
.dptr
);
3422 oldest
= SMB_MALLOC_P(struct cred_list
);
3423 if (oldest
== NULL
) {
3424 status
= NT_STATUS_NO_MEMORY
;
3428 fstrcpy(oldest
->name
, cred
->name
);
3429 oldest
->created
= t
;
3433 if (t
< oldest
->created
) {
3434 fstrcpy(oldest
->name
, cred
->name
);
3435 oldest
->created
= t
;
3439 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3440 status
= NT_STATUS_OK
;
3442 status
= NT_STATUS_UNSUCCESSFUL
;
3445 SAFE_FREE(wcache_cred_list
);
3451 /* Change the global online/offline state. */
3452 bool set_global_winbindd_state_offline(void)
3456 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3458 /* Only go offline if someone has created
3459 the key "WINBINDD_OFFLINE" in the cache tdb. */
3461 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3462 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3466 if (!lp_winbind_offline_logon()) {
3467 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3471 if (global_winbindd_offline_state
) {
3472 /* Already offline. */
3476 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
3478 if (!data
.dptr
|| data
.dsize
!= 4) {
3479 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3480 SAFE_FREE(data
.dptr
);
3483 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3484 global_winbindd_offline_state
= true;
3485 SAFE_FREE(data
.dptr
);
3490 void set_global_winbindd_state_online(void)
3492 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3494 if (!lp_winbind_offline_logon()) {
3495 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3499 if (!global_winbindd_offline_state
) {
3500 /* Already online. */
3503 global_winbindd_offline_state
= false;
3509 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3510 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3513 bool get_global_winbindd_state_offline(void)
3515 return global_winbindd_offline_state
;
3518 /***********************************************************************
3519 Validate functions for all possible cache tdb keys.
3520 ***********************************************************************/
3522 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3523 struct tdb_validation_status
*state
)
3525 struct cache_entry
*centry
;
3527 centry
= SMB_XMALLOC_P(struct cache_entry
);
3528 centry
->data
= (unsigned char *)memdup(data
.dptr
, data
.dsize
);
3529 if (!centry
->data
) {
3533 centry
->len
= data
.dsize
;
3536 if (centry
->len
< 16) {
3537 /* huh? corrupt cache? */
3538 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3539 "(len < 16) ?\n", kstr
));
3540 centry_free(centry
);
3541 state
->bad_entry
= true;
3542 state
->success
= false;
3546 centry
->status
= NT_STATUS(centry_uint32(centry
));
3547 centry
->sequence_number
= centry_uint32(centry
);
3548 centry
->timeout
= centry_uint64_t(centry
);
3552 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3553 struct tdb_validation_status
*state
)
3555 if (dbuf
.dsize
!= 8) {
3556 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3557 keystr
, (unsigned int)dbuf
.dsize
));
3558 state
->bad_entry
= true;
3564 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3565 struct tdb_validation_status
*state
)
3567 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3572 (void)centry_uint32(centry
);
3573 if (NT_STATUS_IS_OK(centry
->status
)) {
3575 (void)centry_sid(centry
, &sid
);
3578 centry_free(centry
);
3580 if (!(state
->success
)) {
3583 DEBUG(10,("validate_ns: %s ok\n", keystr
));
3587 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3588 struct tdb_validation_status
*state
)
3590 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3595 if (NT_STATUS_IS_OK(centry
->status
)) {
3596 (void)centry_uint32(centry
);
3597 (void)centry_string(centry
, mem_ctx
);
3598 (void)centry_string(centry
, mem_ctx
);
3601 centry_free(centry
);
3603 if (!(state
->success
)) {
3606 DEBUG(10,("validate_sn: %s ok\n", keystr
));
3610 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3611 struct tdb_validation_status
*state
)
3613 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3620 (void)centry_string(centry
, mem_ctx
);
3621 (void)centry_string(centry
, mem_ctx
);
3622 (void)centry_string(centry
, mem_ctx
);
3623 (void)centry_string(centry
, mem_ctx
);
3624 (void)centry_uint32(centry
);
3625 (void)centry_sid(centry
, &sid
);
3626 (void)centry_sid(centry
, &sid
);
3628 centry_free(centry
);
3630 if (!(state
->success
)) {
3633 DEBUG(10,("validate_u: %s ok\n", keystr
));
3637 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3638 struct tdb_validation_status
*state
)
3640 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3646 (void)centry_nttime(centry
);
3647 (void)centry_nttime(centry
);
3648 (void)centry_uint16(centry
);
3650 centry_free(centry
);
3652 if (!(state
->success
)) {
3655 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3659 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3660 struct tdb_validation_status
*state
)
3662 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3668 (void)centry_uint16(centry
);
3669 (void)centry_uint16(centry
);
3670 (void)centry_uint32(centry
);
3671 (void)centry_nttime(centry
);
3672 (void)centry_nttime(centry
);
3674 centry_free(centry
);
3676 if (!(state
->success
)) {
3679 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3683 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3684 struct tdb_validation_status
*state
)
3686 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3692 (void)centry_time(centry
);
3693 (void)centry_hash16(centry
, mem_ctx
);
3695 /* We only have 17 bytes more data in the salted cred case. */
3696 if (centry
->len
- centry
->ofs
== 17) {
3697 (void)centry_hash16(centry
, mem_ctx
);
3700 centry_free(centry
);
3702 if (!(state
->success
)) {
3705 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3709 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3710 struct tdb_validation_status
*state
)
3712 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3713 int32 num_entries
, i
;
3719 num_entries
= (int32
)centry_uint32(centry
);
3721 for (i
=0; i
< num_entries
; i
++) {
3723 (void)centry_string(centry
, mem_ctx
);
3724 (void)centry_string(centry
, mem_ctx
);
3725 (void)centry_string(centry
, mem_ctx
);
3726 (void)centry_string(centry
, mem_ctx
);
3727 (void)centry_sid(centry
, &sid
);
3728 (void)centry_sid(centry
, &sid
);
3731 centry_free(centry
);
3733 if (!(state
->success
)) {
3736 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3740 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3741 struct tdb_validation_status
*state
)
3743 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3744 int32 num_entries
, i
;
3750 num_entries
= centry_uint32(centry
);
3752 for (i
=0; i
< num_entries
; i
++) {
3753 (void)centry_string(centry
, mem_ctx
);
3754 (void)centry_string(centry
, mem_ctx
);
3755 (void)centry_uint32(centry
);
3758 centry_free(centry
);
3760 if (!(state
->success
)) {
3763 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3767 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3768 struct tdb_validation_status
*state
)
3770 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3771 int32 num_groups
, i
;
3777 num_groups
= centry_uint32(centry
);
3779 for (i
=0; i
< num_groups
; i
++) {
3781 centry_sid(centry
, &sid
);
3784 centry_free(centry
);
3786 if (!(state
->success
)) {
3789 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3793 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3794 struct tdb_validation_status
*state
)
3796 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3797 int32 num_aliases
, i
;
3803 num_aliases
= centry_uint32(centry
);
3805 for (i
=0; i
< num_aliases
; i
++) {
3806 (void)centry_uint32(centry
);
3809 centry_free(centry
);
3811 if (!(state
->success
)) {
3814 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3818 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3819 struct tdb_validation_status
*state
)
3821 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3828 num_names
= centry_uint32(centry
);
3830 for (i
=0; i
< num_names
; i
++) {
3832 centry_sid(centry
, &sid
);
3833 (void)centry_string(centry
, mem_ctx
);
3834 (void)centry_uint32(centry
);
3837 centry_free(centry
);
3839 if (!(state
->success
)) {
3842 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3846 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3847 struct tdb_validation_status
*state
)
3849 /* Can't say anything about this other than must be nonzero. */
3850 if (dbuf
.dsize
== 0) {
3851 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3853 state
->bad_entry
= true;
3854 state
->success
= false;
3858 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3862 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3863 struct tdb_validation_status
*state
)
3865 /* Can't say anything about this other than must be nonzero. */
3866 if (dbuf
.dsize
== 0) {
3867 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3869 state
->bad_entry
= true;
3870 state
->success
= false;
3874 DEBUG(10,("validate_de: %s ok\n", keystr
));
3878 static int validate_pwinfo(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3879 TDB_DATA dbuf
, struct tdb_validation_status
*state
)
3881 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3887 (void)centry_string(centry
, mem_ctx
);
3888 (void)centry_string(centry
, mem_ctx
);
3889 (void)centry_string(centry
, mem_ctx
);
3890 (void)centry_uint32(centry
);
3892 centry_free(centry
);
3894 if (!(state
->success
)) {
3897 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3901 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3903 struct tdb_validation_status
*state
)
3905 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3911 (void)centry_string( centry
, mem_ctx
);
3913 centry_free(centry
);
3915 if (!(state
->success
)) {
3918 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3922 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3924 struct tdb_validation_status
*state
)
3926 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3932 (void)centry_string( centry
, mem_ctx
);
3934 centry_free(centry
);
3936 if (!(state
->success
)) {
3939 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3943 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3945 struct tdb_validation_status
*state
)
3947 if (dbuf
.dsize
== 0) {
3948 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3949 "key %s (len ==0) ?\n", keystr
));
3950 state
->bad_entry
= true;
3951 state
->success
= false;
3955 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3956 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3960 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3961 struct tdb_validation_status
*state
)
3963 if (dbuf
.dsize
!= 4) {
3964 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3965 keystr
, (unsigned int)dbuf
.dsize
));
3966 state
->bad_entry
= true;
3967 state
->success
= false;
3970 DEBUG(10,("validate_offline: %s ok\n", keystr
));
3974 static int validate_ndr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3975 struct tdb_validation_status
*state
)
3978 * Ignore validation for now. The proper way to do this is with a
3979 * checksum. Just pure parsing does not really catch much.
3984 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3985 struct tdb_validation_status
*state
)
3987 if (dbuf
.dsize
!= 4) {
3988 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3989 "key %s (len %u != 4) ?\n",
3990 keystr
, (unsigned int)dbuf
.dsize
));
3991 state
->bad_entry
= true;
3992 state
->success
= false;
3996 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
4000 /***********************************************************************
4001 A list of all possible cache tdb keys with associated validation
4003 ***********************************************************************/
4005 struct key_val_struct
{
4006 const char *keyname
;
4007 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
4009 {"SEQNUM/", validate_seqnum
},
4010 {"NS/", validate_ns
},
4011 {"SN/", validate_sn
},
4013 {"LOC_POL/", validate_loc_pol
},
4014 {"PWD_POL/", validate_pwd_pol
},
4015 {"CRED/", validate_cred
},
4016 {"UL/", validate_ul
},
4017 {"GL/", validate_gl
},
4018 {"UG/", validate_ug
},
4019 {"UA", validate_ua
},
4020 {"GM/", validate_gm
},
4021 {"DR/", validate_dr
},
4022 {"DE/", validate_de
},
4023 {"NSS/PWINFO/", validate_pwinfo
},
4024 {"TRUSTDOMCACHE/", validate_trustdomcache
},
4025 {"NSS/NA/", validate_nss_na
},
4026 {"NSS/AN/", validate_nss_an
},
4027 {"WINBINDD_OFFLINE", validate_offline
},
4028 {"NDR/", validate_ndr
},
4029 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
4033 /***********************************************************************
4034 Function to look at every entry in the tdb and validate it as far as
4036 ***********************************************************************/
4038 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
4041 unsigned int max_key_len
= 1024;
4042 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
4044 /* Paranoia check. */
4045 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0) {
4046 max_key_len
= 1024 * 1024;
4048 if (kbuf
.dsize
> max_key_len
) {
4049 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4051 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
4055 for (i
= 0; key_val
[i
].keyname
; i
++) {
4056 size_t namelen
= strlen(key_val
[i
].keyname
);
4057 if (kbuf
.dsize
>= namelen
&& (
4058 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
4059 TALLOC_CTX
*mem_ctx
;
4063 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
4067 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
4068 keystr
[kbuf
.dsize
] = '\0';
4070 mem_ctx
= talloc_init("validate_ctx");
4076 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
4080 talloc_destroy(mem_ctx
);
4085 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4086 dump_data(0, (uint8
*)kbuf
.dptr
, kbuf
.dsize
);
4087 DEBUG(0,("data :\n"));
4088 dump_data(0, (uint8
*)dbuf
.dptr
, dbuf
.dsize
);
4089 v_state
->unknown_key
= true;
4090 v_state
->success
= false;
4091 return 1; /* terminate. */
4094 static void validate_panic(const char *const why
)
4096 DEBUG(0,("validating cache: would panic %s\n", why
));
4097 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4101 static int wbcache_update_centry_fn(TDB_CONTEXT
*tdb
,
4109 if (is_non_centry_key(key
)) {
4113 if (data
.dptr
== NULL
|| data
.dsize
== 0) {
4114 if (tdb_delete(tdb
, key
) < 0) {
4115 DEBUG(0, ("tdb_delete for [%s] failed!\n",
4121 /* add timeout to blob (uint64_t) */
4122 blob
.dsize
= data
.dsize
+ 8;
4124 blob
.dptr
= SMB_XMALLOC_ARRAY(uint8_t, blob
.dsize
);
4125 if (blob
.dptr
== NULL
) {
4128 memset(blob
.dptr
, 0, blob
.dsize
);
4130 /* copy status and seqnum */
4131 memcpy(blob
.dptr
, data
.dptr
, 8);
4134 ctimeout
= lp_winbind_cache_time() + time(NULL
);
4135 SBVAL(blob
.dptr
, 8, ctimeout
);
4138 memcpy(blob
.dptr
+ 16, data
.dptr
+ 8, data
.dsize
- 8);
4140 if (tdb_store(tdb
, key
, blob
, TDB_REPLACE
) < 0) {
4141 DEBUG(0, ("tdb_store to update [%s] failed!\n",
4143 SAFE_FREE(blob
.dptr
);
4147 SAFE_FREE(blob
.dptr
);
4151 static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT
*tdb
)
4155 DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
4157 rc
= tdb_traverse(tdb
, wbcache_update_centry_fn
, NULL
);
4165 /***********************************************************************
4166 Try and validate every entry in the winbindd cache. If we fail here,
4167 delete the cache tdb and return non-zero.
4168 ***********************************************************************/
4170 int winbindd_validate_cache(void)
4173 const char *tdb_path
= state_path("winbindd_cache.tdb");
4174 TDB_CONTEXT
*tdb
= NULL
;
4178 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4179 smb_panic_fn
= validate_panic
;
4181 tdb
= tdb_open_log(tdb_path
,
4182 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
4183 TDB_INCOMPATIBLE_HASH
|
4184 ( lp_winbind_offline_logon()
4186 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
4190 DEBUG(0, ("winbindd_validate_cache: "
4191 "error opening/initializing tdb\n"));
4195 /* Version check and upgrade code. */
4196 if (!tdb_fetch_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers_id
)) {
4197 DEBUG(10, ("Fresh database\n"));
4198 tdb_store_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
);
4199 vers_id
= WINBINDD_CACHE_VERSION
;
4202 if (vers_id
!= WINBINDD_CACHE_VERSION
) {
4203 if (vers_id
== WINBINDD_CACHE_VER1
) {
4204 ok
= wbcache_upgrade_v1_to_v2(tdb
);
4206 DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
4211 tdb_store_uint32(tdb
,
4212 WINBINDD_CACHE_VERSION_KEYSTR
,
4213 WINBINDD_CACHE_VERSION
);
4214 vers_id
= WINBINDD_CACHE_VER2
;
4220 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
4223 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4224 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
4229 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4230 smb_panic_fn
= smb_panic
;
4234 /***********************************************************************
4235 Try and validate every entry in the winbindd cache.
4236 ***********************************************************************/
4238 int winbindd_validate_cache_nobackup(void)
4241 const char *tdb_path
= state_path("winbindd_cache.tdb");
4243 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4244 smb_panic_fn
= validate_panic
;
4247 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
4248 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
4250 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
4254 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4258 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4260 smb_panic_fn
= smb_panic
;
4264 bool winbindd_cache_validate_and_initialize(void)
4266 close_winbindd_cache();
4268 if (lp_winbind_offline_logon()) {
4269 if (winbindd_validate_cache() < 0) {
4270 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4271 "could be restored.\n"));
4275 return initialize_winbindd_cache();
4278 /*********************************************************************
4279 ********************************************************************/
4281 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
4282 struct winbindd_tdc_domain
**domains
,
4283 size_t *num_domains
)
4285 struct winbindd_tdc_domain
*list
= NULL
;
4288 bool set_only
= false;
4290 /* don't allow duplicates */
4295 for ( i
=0; i
< (*num_domains
); i
++ ) {
4296 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
4297 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4308 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, 1 );
4311 list
= talloc_realloc( *domains
, *domains
,
4312 struct winbindd_tdc_domain
,
4317 ZERO_STRUCT( list
[idx
] );
4323 list
[idx
].domain_name
= talloc_strdup( list
, new_dom
->name
);
4324 list
[idx
].dns_name
= talloc_strdup( list
, new_dom
->alt_name
);
4326 if ( !is_null_sid( &new_dom
->sid
) ) {
4327 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
4329 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
4332 if ( new_dom
->domain_flags
!= 0x0 )
4333 list
[idx
].trust_flags
= new_dom
->domain_flags
;
4335 if ( new_dom
->domain_type
!= 0x0 )
4336 list
[idx
].trust_type
= new_dom
->domain_type
;
4338 if ( new_dom
->domain_trust_attribs
!= 0x0 )
4339 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
4343 *num_domains
= idx
+ 1;
4349 /*********************************************************************
4350 ********************************************************************/
4352 static TDB_DATA
make_tdc_key( const char *domain_name
)
4354 char *keystr
= NULL
;
4355 TDB_DATA key
= { NULL
, 0 };
4357 if ( !domain_name
) {
4358 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4362 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
4365 key
= string_term_tdb_data(keystr
);
4370 /*********************************************************************
4371 ********************************************************************/
4373 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
4375 unsigned char **buf
)
4377 unsigned char *buffer
= NULL
;
4382 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4390 /* Store the number of array items first */
4391 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
4394 /* now pack each domain trust record */
4395 for ( i
=0; i
<num_domains
; i
++ ) {
4400 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4401 domains
[i
].domain_name
,
4402 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
4405 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
4406 domains
[i
].domain_name
,
4407 domains
[i
].dns_name
,
4408 sid_to_fstring(tmp
, &domains
[i
].sid
),
4409 domains
[i
].trust_flags
,
4410 domains
[i
].trust_attribs
,
4411 domains
[i
].trust_type
);
4414 if ( buflen
< len
) {
4416 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
4417 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4431 /*********************************************************************
4432 ********************************************************************/
4434 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
4435 struct winbindd_tdc_domain
**domains
)
4437 fstring domain_name
, dns_name
, sid_string
;
4438 uint32 type
, attribs
, flags
;
4442 struct winbindd_tdc_domain
*list
= NULL
;
4444 /* get the number of domains */
4445 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
4447 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4451 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, num_domains
);
4453 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4457 for ( i
=0; i
<num_domains
; i
++ ) {
4458 len
+= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
4467 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4468 TALLOC_FREE( list
);
4472 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4473 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4474 domain_name
, dns_name
, sid_string
,
4475 flags
, attribs
, type
));
4477 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
4478 list
[i
].dns_name
= talloc_strdup( list
, dns_name
);
4479 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
4480 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4483 list
[i
].trust_flags
= flags
;
4484 list
[i
].trust_attribs
= attribs
;
4485 list
[i
].trust_type
= type
;
4493 /*********************************************************************
4494 ********************************************************************/
4496 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
4498 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4499 TDB_DATA data
= { NULL
, 0 };
4505 /* See if we were asked to delete the cache entry */
4508 ret
= tdb_delete( wcache
->tdb
, key
);
4512 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4519 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4522 SAFE_FREE( data
.dptr
);
4523 SAFE_FREE( key
.dptr
);
4525 return ( ret
== 0 );
4528 /*********************************************************************
4529 ********************************************************************/
4531 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4533 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4534 TDB_DATA data
= { NULL
, 0 };
4542 data
= tdb_fetch_compat( wcache
->tdb
, key
);
4544 SAFE_FREE( key
.dptr
);
4549 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4551 SAFE_FREE( data
.dptr
);
4559 /*********************************************************************
4560 ********************************************************************/
4562 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4564 struct winbindd_tdc_domain
*dom_list
= NULL
;
4565 size_t num_domains
= 0;
4568 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4569 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4570 domain
->name
, domain
->alt_name
,
4571 sid_string_dbg(&domain
->sid
),
4572 domain
->domain_flags
,
4573 domain
->domain_trust_attribs
,
4574 domain
->domain_type
));
4576 if ( !init_wcache() ) {
4580 /* fetch the list */
4582 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4584 /* add the new domain */
4586 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4590 /* pack the domain */
4592 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4600 TALLOC_FREE( dom_list
);
4605 /*********************************************************************
4606 ********************************************************************/
4608 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4610 struct winbindd_tdc_domain
*dom_list
= NULL
;
4611 size_t num_domains
= 0;
4613 struct winbindd_tdc_domain
*d
= NULL
;
4615 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4617 if ( !init_wcache() ) {
4621 /* fetch the list */
4623 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4625 for ( i
=0; i
<num_domains
; i
++ ) {
4626 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4627 strequal(name
, dom_list
[i
].dns_name
) )
4629 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4632 d
= talloc( ctx
, struct winbindd_tdc_domain
);
4636 d
->domain_name
= talloc_strdup( d
, dom_list
[i
].domain_name
);
4637 d
->dns_name
= talloc_strdup( d
, dom_list
[i
].dns_name
);
4638 sid_copy( &d
->sid
, &dom_list
[i
].sid
);
4639 d
->trust_flags
= dom_list
[i
].trust_flags
;
4640 d
->trust_type
= dom_list
[i
].trust_type
;
4641 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
4647 TALLOC_FREE( dom_list
);
4652 /*********************************************************************
4653 ********************************************************************/
4655 struct winbindd_tdc_domain
*
4656 wcache_tdc_fetch_domainbysid(TALLOC_CTX
*ctx
,
4657 const struct dom_sid
*sid
)
4659 struct winbindd_tdc_domain
*dom_list
= NULL
;
4660 size_t num_domains
= 0;
4662 struct winbindd_tdc_domain
*d
= NULL
;
4664 DEBUG(10,("wcache_tdc_fetch_domainbysid: Searching for domain %s\n",
4665 sid_string_dbg(sid
)));
4667 if (!init_wcache()) {
4671 /* fetch the list */
4673 wcache_tdc_fetch_list(&dom_list
, &num_domains
);
4675 for (i
= 0; i
<num_domains
; i
++) {
4676 if (dom_sid_equal(sid
, &(dom_list
[i
].sid
))) {
4677 DEBUG(10, ("wcache_tdc_fetch_domainbysid: "
4678 "Found domain %s for SID %s\n",
4679 dom_list
[i
].domain_name
,
4680 sid_string_dbg(sid
)));
4682 d
= talloc(ctx
, struct winbindd_tdc_domain
);
4686 d
->domain_name
= talloc_strdup(d
,
4687 dom_list
[i
].domain_name
);
4689 d
->dns_name
= talloc_strdup(d
, dom_list
[i
].dns_name
);
4690 sid_copy(&d
->sid
, &dom_list
[i
].sid
);
4691 d
->trust_flags
= dom_list
[i
].trust_flags
;
4692 d
->trust_type
= dom_list
[i
].trust_type
;
4693 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
4699 TALLOC_FREE(dom_list
);
4705 /*********************************************************************
4706 ********************************************************************/
4708 void wcache_tdc_clear( void )
4710 if ( !init_wcache() )
4713 wcache_tdc_store_list( NULL
, 0 );
4719 /*********************************************************************
4720 ********************************************************************/
4722 static void wcache_save_user_pwinfo(struct winbindd_domain
*domain
,
4724 const struct dom_sid
*user_sid
,
4725 const char *homedir
,
4730 struct cache_entry
*centry
;
4733 if ( (centry
= centry_start(domain
, status
)) == NULL
)
4736 centry_put_string( centry
, homedir
);
4737 centry_put_string( centry
, shell
);
4738 centry_put_string( centry
, gecos
);
4739 centry_put_uint32( centry
, gid
);
4741 centry_end(centry
, "NSS/PWINFO/%s", sid_to_fstring(tmp
, user_sid
) );
4743 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid
) ));
4745 centry_free(centry
);
4750 NTSTATUS
nss_get_info_cached( struct winbindd_domain
*domain
,
4751 const struct dom_sid
*user_sid
,
4753 const char **homedir
, const char **shell
,
4754 const char **gecos
, gid_t
*p_gid
)
4756 struct winbind_cache
*cache
= get_cache(domain
);
4757 struct cache_entry
*centry
= NULL
;
4764 centry
= wcache_fetch(cache
, domain
, "NSS/PWINFO/%s",
4765 sid_to_fstring(tmp
, user_sid
));
4770 *homedir
= centry_string( centry
, ctx
);
4771 *shell
= centry_string( centry
, ctx
);
4772 *gecos
= centry_string( centry
, ctx
);
4773 *p_gid
= centry_uint32( centry
);
4775 centry_free(centry
);
4777 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4778 sid_string_dbg(user_sid
)));
4780 return NT_STATUS_OK
;
4784 nt_status
= nss_get_info( domain
->name
, user_sid
, ctx
,
4785 homedir
, shell
, gecos
, p_gid
);
4787 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status
)));
4789 if ( NT_STATUS_IS_OK(nt_status
) ) {
4790 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir
));
4791 DEBUGADD(10, ("\tshell = '%s'\n", *shell
));
4792 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos
));
4793 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid
));
4795 wcache_save_user_pwinfo( domain
, nt_status
, user_sid
,
4796 *homedir
, *shell
, *gecos
, *p_gid
);
4799 if ( NT_STATUS_EQUAL( nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
4800 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4802 set_domain_offline( domain
);
4810 /* the cache backend methods are exposed via this structure */
4811 struct winbindd_methods cache_methods
= {
4829 static bool wcache_ndr_key(TALLOC_CTX
*mem_ctx
, char *domain_name
,
4830 uint32_t opnum
, const DATA_BLOB
*req
,
4836 key
= talloc_asprintf(mem_ctx
, "NDR/%s/%d/", domain_name
, (int)opnum
);
4840 keylen
= talloc_get_size(key
) - 1;
4842 key
= talloc_realloc(mem_ctx
, key
, char, keylen
+ req
->length
);
4846 memcpy(key
+ keylen
, req
->data
, req
->length
);
4848 pkey
->dptr
= (uint8_t *)key
;
4849 pkey
->dsize
= talloc_get_size(key
);
4853 static bool wcache_opnum_cacheable(uint32_t opnum
)
4856 case NDR_WBINT_PING
:
4857 case NDR_WBINT_QUERYSEQUENCENUMBER
:
4858 case NDR_WBINT_ALLOCATEUID
:
4859 case NDR_WBINT_ALLOCATEGID
:
4860 case NDR_WBINT_CHECKMACHINEACCOUNT
:
4861 case NDR_WBINT_CHANGEMACHINEACCOUNT
:
4862 case NDR_WBINT_PINGDC
:
4868 bool wcache_fetch_ndr(TALLOC_CTX
*mem_ctx
, struct winbindd_domain
*domain
,
4869 uint32_t opnum
, const DATA_BLOB
*req
, DATA_BLOB
*resp
)
4874 if (!wcache_opnum_cacheable(opnum
) ||
4875 is_my_own_sam_domain(domain
) ||
4876 is_builtin_domain(domain
)) {
4880 if (wcache
->tdb
== NULL
) {
4884 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4887 data
= tdb_fetch_compat(wcache
->tdb
, key
);
4888 TALLOC_FREE(key
.dptr
);
4890 if (data
.dptr
== NULL
) {
4893 if (data
.dsize
< 12) {
4897 if (!is_domain_offline(domain
)) {
4898 uint32_t entry_seqnum
, dom_seqnum
, last_check
;
4899 uint64_t entry_timeout
;
4901 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
,
4905 entry_seqnum
= IVAL(data
.dptr
, 0);
4906 if (entry_seqnum
!= dom_seqnum
) {
4907 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4908 (int)entry_seqnum
));
4911 entry_timeout
= BVAL(data
.dptr
, 4);
4912 if (time(NULL
) > entry_timeout
) {
4913 DEBUG(10, ("Entry has timed out\n"));
4918 resp
->data
= (uint8_t *)talloc_memdup(mem_ctx
, data
.dptr
+ 12,
4920 if (resp
->data
== NULL
) {
4921 DEBUG(10, ("talloc failed\n"));
4924 resp
->length
= data
.dsize
- 12;
4928 SAFE_FREE(data
.dptr
);
4932 void wcache_store_ndr(struct winbindd_domain
*domain
, uint32_t opnum
,
4933 const DATA_BLOB
*req
, const DATA_BLOB
*resp
)
4936 uint32_t dom_seqnum
, last_check
;
4939 if (!wcache_opnum_cacheable(opnum
) ||
4940 is_my_own_sam_domain(domain
) ||
4941 is_builtin_domain(domain
)) {
4945 if (wcache
->tdb
== NULL
) {
4949 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
, &last_check
)) {
4950 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4955 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4959 timeout
= time(NULL
) + lp_winbind_cache_time();
4961 data
.dsize
= resp
->length
+ 12;
4962 data
.dptr
= talloc_array(key
.dptr
, uint8_t, data
.dsize
);
4963 if (data
.dptr
== NULL
) {
4967 SIVAL(data
.dptr
, 0, dom_seqnum
);
4968 SBVAL(data
.dptr
, 4, timeout
);
4969 memcpy(data
.dptr
+ 12, resp
->data
, resp
->length
);
4971 tdb_store(wcache
->tdb
, key
, data
, 0);
4974 TALLOC_FREE(key
.dptr
);