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
);
947 if ((domain_name
== NULL
) || (domain_name
[0] == '\0')) {
948 struct winbindd_domain
*mydomain
=
949 find_domain_from_sid_noinit(sid
);
950 if (mydomain
!= NULL
) {
951 domain_name
= mydomain
->name
;
955 centry_put_uint32(centry
, type
);
956 centry_put_sid(centry
, sid
);
957 fstrcpy(uname
, name
);
958 (void)strupper_m(uname
);
959 centry_end(centry
, "NS/%s/%s", domain_name
, uname
);
960 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name
,
961 uname
, sid_string_dbg(sid
), nt_errstr(status
)));
965 static void wcache_save_sid_to_name(struct winbindd_domain
*domain
, NTSTATUS status
,
966 const struct dom_sid
*sid
, const char *domain_name
, const char *name
, enum lsa_SidType type
)
968 struct cache_entry
*centry
;
971 centry
= centry_start(domain
, status
);
975 if ((domain_name
== NULL
) || (domain_name
[0] == '\0')) {
976 struct winbindd_domain
*mydomain
=
977 find_domain_from_sid_noinit(sid
);
978 if (mydomain
!= NULL
) {
979 domain_name
= mydomain
->name
;
983 if (NT_STATUS_IS_OK(status
)) {
984 centry_put_uint32(centry
, type
);
985 centry_put_string(centry
, domain_name
);
986 centry_put_string(centry
, name
);
989 centry_end(centry
, "SN/%s", sid_to_fstring(sid_string
, sid
));
990 DEBUG(10,("wcache_save_sid_to_name: %s -> %s\\%s (%s)\n", sid_string
,
991 domain_name
, name
, nt_errstr(status
)));
996 static void wcache_save_user(struct winbindd_domain
*domain
, NTSTATUS status
,
997 struct wbint_userinfo
*info
)
999 struct cache_entry
*centry
;
1002 if (is_null_sid(&info
->user_sid
)) {
1006 centry
= centry_start(domain
, status
);
1009 centry_put_string(centry
, info
->acct_name
);
1010 centry_put_string(centry
, info
->full_name
);
1011 centry_put_string(centry
, info
->homedir
);
1012 centry_put_string(centry
, info
->shell
);
1013 centry_put_uint32(centry
, info
->primary_gid
);
1014 centry_put_sid(centry
, &info
->user_sid
);
1015 centry_put_sid(centry
, &info
->group_sid
);
1016 centry_end(centry
, "U/%s", sid_to_fstring(sid_string
,
1018 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string
, info
->acct_name
));
1019 centry_free(centry
);
1022 static void wcache_save_lockout_policy(struct winbindd_domain
*domain
,
1024 struct samr_DomInfo12
*lockout_policy
)
1026 struct cache_entry
*centry
;
1028 centry
= centry_start(domain
, status
);
1032 centry_put_nttime(centry
, lockout_policy
->lockout_duration
);
1033 centry_put_nttime(centry
, lockout_policy
->lockout_window
);
1034 centry_put_uint16(centry
, lockout_policy
->lockout_threshold
);
1036 centry_end(centry
, "LOC_POL/%s", domain
->name
);
1038 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain
->name
));
1040 centry_free(centry
);
1045 static void wcache_save_password_policy(struct winbindd_domain
*domain
,
1047 struct samr_DomInfo1
*policy
)
1049 struct cache_entry
*centry
;
1051 centry
= centry_start(domain
, status
);
1055 centry_put_uint16(centry
, policy
->min_password_length
);
1056 centry_put_uint16(centry
, policy
->password_history_length
);
1057 centry_put_uint32(centry
, policy
->password_properties
);
1058 centry_put_nttime(centry
, policy
->max_password_age
);
1059 centry_put_nttime(centry
, policy
->min_password_age
);
1061 centry_end(centry
, "PWD_POL/%s", domain
->name
);
1063 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
1065 centry_free(centry
);
1068 /***************************************************************************
1069 ***************************************************************************/
1071 static void wcache_save_username_alias(struct winbindd_domain
*domain
,
1073 const char *name
, const char *alias
)
1075 struct cache_entry
*centry
;
1078 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1081 centry_put_string( centry
, alias
);
1083 fstrcpy(uname
, name
);
1084 (void)strupper_m(uname
);
1085 centry_end(centry
, "NSS/NA/%s", uname
);
1087 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name
, alias
));
1089 centry_free(centry
);
1092 static void wcache_save_alias_username(struct winbindd_domain
*domain
,
1094 const char *alias
, const char *name
)
1096 struct cache_entry
*centry
;
1099 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1102 centry_put_string( centry
, name
);
1104 fstrcpy(uname
, alias
);
1105 (void)strupper_m(uname
);
1106 centry_end(centry
, "NSS/AN/%s", uname
);
1108 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias
, name
));
1110 centry_free(centry
);
1113 /***************************************************************************
1114 ***************************************************************************/
1116 NTSTATUS
resolve_username_to_alias( TALLOC_CTX
*mem_ctx
,
1117 struct winbindd_domain
*domain
,
1118 const char *name
, char **alias
)
1120 struct winbind_cache
*cache
= get_cache(domain
);
1121 struct cache_entry
*centry
= NULL
;
1125 if ( domain
->internal
)
1126 return NT_STATUS_NOT_SUPPORTED
;
1131 upper_name
= talloc_strdup(mem_ctx
, name
);
1132 if (upper_name
== NULL
) {
1133 return NT_STATUS_NO_MEMORY
;
1135 if (!strupper_m(upper_name
)) {
1136 talloc_free(upper_name
);
1137 return NT_STATUS_INVALID_PARAMETER
;
1140 centry
= wcache_fetch(cache
, domain
, "NSS/NA/%s", upper_name
);
1142 talloc_free(upper_name
);
1147 status
= centry
->status
;
1149 if (!NT_STATUS_IS_OK(status
)) {
1150 centry_free(centry
);
1154 *alias
= centry_string( centry
, mem_ctx
);
1156 centry_free(centry
);
1158 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1159 name
, *alias
? *alias
: "(none)"));
1161 return (*alias
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1165 /* If its not in cache and we are offline, then fail */
1167 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1168 DEBUG(8,("resolve_username_to_alias: rejecting query "
1169 "in offline mode\n"));
1170 return NT_STATUS_NOT_FOUND
;
1173 status
= nss_map_to_alias( mem_ctx
, domain
->name
, name
, alias
);
1175 if ( NT_STATUS_IS_OK( status
) ) {
1176 wcache_save_username_alias(domain
, status
, name
, *alias
);
1179 if ( NT_STATUS_EQUAL( status
, NT_STATUS_NONE_MAPPED
) ) {
1180 wcache_save_username_alias(domain
, status
, name
, "(NULL)");
1183 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1184 nt_errstr(status
)));
1186 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1187 set_domain_offline( domain
);
1193 /***************************************************************************
1194 ***************************************************************************/
1196 NTSTATUS
resolve_alias_to_username( TALLOC_CTX
*mem_ctx
,
1197 struct winbindd_domain
*domain
,
1198 const char *alias
, char **name
)
1200 struct winbind_cache
*cache
= get_cache(domain
);
1201 struct cache_entry
*centry
= NULL
;
1205 if ( domain
->internal
)
1206 return NT_STATUS_NOT_SUPPORTED
;
1211 upper_name
= talloc_strdup(mem_ctx
, alias
);
1212 if (upper_name
== NULL
) {
1213 return NT_STATUS_NO_MEMORY
;
1215 if (!strupper_m(upper_name
)) {
1216 talloc_free(upper_name
);
1217 return NT_STATUS_INVALID_PARAMETER
;
1220 centry
= wcache_fetch(cache
, domain
, "NSS/AN/%s", upper_name
);
1222 talloc_free(upper_name
);
1227 status
= centry
->status
;
1229 if (!NT_STATUS_IS_OK(status
)) {
1230 centry_free(centry
);
1234 *name
= centry_string( centry
, mem_ctx
);
1236 centry_free(centry
);
1238 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1239 alias
, *name
? *name
: "(none)"));
1241 return (*name
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1245 /* If its not in cache and we are offline, then fail */
1247 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1248 DEBUG(8,("resolve_alias_to_username: rejecting query "
1249 "in offline mode\n"));
1250 return NT_STATUS_NOT_FOUND
;
1253 /* an alias cannot contain a domain prefix or '@' */
1255 if (strchr(alias
, '\\') || strchr(alias
, '@')) {
1256 DEBUG(10,("resolve_alias_to_username: skipping fully "
1257 "qualified name %s\n", alias
));
1258 return NT_STATUS_OBJECT_NAME_INVALID
;
1261 status
= nss_map_from_alias( mem_ctx
, domain
->name
, alias
, name
);
1263 if ( NT_STATUS_IS_OK( status
) ) {
1264 wcache_save_alias_username( domain
, status
, alias
, *name
);
1267 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1268 wcache_save_alias_username(domain
, status
, alias
, "(NULL)");
1271 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1272 nt_errstr(status
)));
1274 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1275 set_domain_offline( domain
);
1281 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
1283 struct winbind_cache
*cache
= get_cache(domain
);
1285 fstring key_str
, tmp
;
1289 return NT_STATUS_INTERNAL_DB_ERROR
;
1292 if (is_null_sid(sid
)) {
1293 return NT_STATUS_INVALID_SID
;
1296 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1297 return NT_STATUS_INVALID_SID
;
1300 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
1302 data
= tdb_fetch_compat(cache
->tdb
, string_tdb_data(key_str
));
1304 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1307 SAFE_FREE(data
.dptr
);
1308 return NT_STATUS_OK
;
1311 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1312 as new salted ones. */
1314 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
1315 TALLOC_CTX
*mem_ctx
,
1316 const struct dom_sid
*sid
,
1317 const uint8
**cached_nt_pass
,
1318 const uint8
**cached_salt
)
1320 struct winbind_cache
*cache
= get_cache(domain
);
1321 struct cache_entry
*centry
= NULL
;
1327 return NT_STATUS_INTERNAL_DB_ERROR
;
1330 if (is_null_sid(sid
)) {
1331 return NT_STATUS_INVALID_SID
;
1334 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1335 return NT_STATUS_INVALID_SID
;
1338 /* Try and get a salted cred first. If we can't
1339 fall back to an unsalted cred. */
1341 centry
= wcache_fetch(cache
, domain
, "CRED/%s",
1342 sid_to_fstring(tmp
, sid
));
1344 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1345 sid_string_dbg(sid
)));
1346 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1350 * We don't use the time element at this moment,
1351 * but we have to consume it, so that we don't
1352 * neet to change the disk format of the cache.
1354 (void)centry_time(centry
);
1356 /* In the salted case this isn't actually the nt_hash itself,
1357 but the MD5 of the salt + nt_hash. Let the caller
1358 sort this out. It can tell as we only return the cached_salt
1359 if we are returning a salted cred. */
1361 *cached_nt_pass
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1362 if (*cached_nt_pass
== NULL
) {
1365 sid_to_fstring(sidstr
, sid
);
1367 /* Bad (old) cred cache. Delete and pretend we
1369 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1371 wcache_delete("CRED/%s", sidstr
);
1372 centry_free(centry
);
1373 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1376 /* We only have 17 bytes more data in the salted cred case. */
1377 if (centry
->len
- centry
->ofs
== 17) {
1378 *cached_salt
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1380 *cached_salt
= NULL
;
1383 dump_data_pw("cached_nt_pass", *cached_nt_pass
, NT_HASH_LEN
);
1385 dump_data_pw("cached_salt", *cached_salt
, NT_HASH_LEN
);
1388 status
= centry
->status
;
1390 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1391 sid_string_dbg(sid
), nt_errstr(status
) ));
1393 centry_free(centry
);
1397 /* Store creds for a SID - only writes out new salted ones. */
1399 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1400 const struct dom_sid
*sid
,
1401 const uint8 nt_pass
[NT_HASH_LEN
])
1403 struct cache_entry
*centry
;
1406 uint8 cred_salt
[NT_HASH_LEN
];
1407 uint8 salted_hash
[NT_HASH_LEN
];
1409 if (is_null_sid(sid
)) {
1410 return NT_STATUS_INVALID_SID
;
1413 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1414 return NT_STATUS_INVALID_SID
;
1417 centry
= centry_start(domain
, NT_STATUS_OK
);
1419 return NT_STATUS_INTERNAL_DB_ERROR
;
1422 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1424 centry_put_time(centry
, time(NULL
));
1426 /* Create a salt and then salt the hash. */
1427 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1428 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1430 centry_put_hash16(centry
, salted_hash
);
1431 centry_put_hash16(centry
, cred_salt
);
1432 centry_end(centry
, "CRED/%s", sid_to_fstring(sid_string
, sid
));
1434 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1436 centry_free(centry
);
1438 return NT_STATUS_OK
;
1442 /* Query display info. This is the basic user list fn */
1443 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
1444 TALLOC_CTX
*mem_ctx
,
1445 uint32
*num_entries
,
1446 struct wbint_userinfo
**info
)
1448 struct winbind_cache
*cache
= get_cache(domain
);
1449 struct cache_entry
*centry
= NULL
;
1451 unsigned int i
, retry
;
1452 bool old_status
= domain
->online
;
1457 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1462 *num_entries
= centry_uint32(centry
);
1464 if (*num_entries
== 0)
1467 (*info
) = talloc_array(mem_ctx
, struct wbint_userinfo
, *num_entries
);
1469 smb_panic_fn("query_user_list out of memory");
1471 for (i
=0; i
<(*num_entries
); i
++) {
1472 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
1473 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
1474 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
1475 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
1476 centry_sid(centry
, &(*info
)[i
].user_sid
);
1477 centry_sid(centry
, &(*info
)[i
].group_sid
);
1481 status
= centry
->status
;
1483 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1484 domain
->name
, nt_errstr(status
) ));
1486 centry_free(centry
);
1493 /* Return status value returned by seq number check */
1495 if (!NT_STATUS_IS_OK(domain
->last_status
))
1496 return domain
->last_status
;
1498 /* Put the query_user_list() in a retry loop. There appears to be
1499 * some bug either with Windows 2000 or Samba's handling of large
1500 * rpc replies. This manifests itself as sudden disconnection
1501 * at a random point in the enumeration of a large (60k) user list.
1502 * The retry loop simply tries the operation again. )-: It's not
1503 * pretty but an acceptable workaround until we work out what the
1504 * real problem is. */
1509 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1512 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
1513 if (!NT_STATUS_IS_OK(status
)) {
1514 DEBUG(3, ("query_user_list: returned 0x%08x, "
1515 "retrying\n", NT_STATUS_V(status
)));
1517 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1518 DEBUG(3, ("query_user_list: flushing "
1519 "connection cache\n"));
1520 invalidate_cm_connection(&domain
->conn
);
1522 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1523 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1524 if (!domain
->internal
&& old_status
) {
1525 set_domain_offline(domain
);
1527 /* store partial response. */
1528 if (*num_entries
> 0) {
1530 * humm, what about the status used for cache?
1531 * Should it be NT_STATUS_OK?
1536 * domain is offline now, and there is no user entries,
1537 * try to fetch from cache again.
1539 if (cache
->tdb
&& !domain
->online
&& !domain
->internal
&& old_status
) {
1540 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1541 /* partial response... */
1545 goto do_fetch_cache
;
1552 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1556 refresh_sequence_number(domain
, false);
1557 if (!NT_STATUS_IS_OK(status
)) {
1560 centry
= centry_start(domain
, status
);
1563 centry_put_uint32(centry
, *num_entries
);
1564 for (i
=0; i
<(*num_entries
); i
++) {
1565 centry_put_string(centry
, (*info
)[i
].acct_name
);
1566 centry_put_string(centry
, (*info
)[i
].full_name
);
1567 centry_put_string(centry
, (*info
)[i
].homedir
);
1568 centry_put_string(centry
, (*info
)[i
].shell
);
1569 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1570 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1571 if (domain
->backend
&& domain
->backend
->consistent
) {
1572 /* when the backend is consistent we can pre-prime some mappings */
1573 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1575 (*info
)[i
].acct_name
,
1576 &(*info
)[i
].user_sid
,
1578 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1579 &(*info
)[i
].user_sid
,
1581 (*info
)[i
].acct_name
,
1583 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1586 centry_end(centry
, "UL/%s", domain
->name
);
1587 centry_free(centry
);
1593 /* list all domain groups */
1594 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
1595 TALLOC_CTX
*mem_ctx
,
1596 uint32
*num_entries
,
1597 struct wb_acct_info
**info
)
1599 struct winbind_cache
*cache
= get_cache(domain
);
1600 struct cache_entry
*centry
= NULL
;
1605 old_status
= domain
->online
;
1609 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1614 *num_entries
= centry_uint32(centry
);
1616 if (*num_entries
== 0)
1619 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1621 smb_panic_fn("enum_dom_groups out of memory");
1623 for (i
=0; i
<(*num_entries
); i
++) {
1624 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1625 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1626 (*info
)[i
].rid
= centry_uint32(centry
);
1630 status
= centry
->status
;
1632 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1633 domain
->name
, nt_errstr(status
) ));
1635 centry_free(centry
);
1642 /* Return status value returned by seq number check */
1644 if (!NT_STATUS_IS_OK(domain
->last_status
))
1645 return domain
->last_status
;
1647 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1650 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1652 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1653 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1654 if (!domain
->internal
&& old_status
) {
1655 set_domain_offline(domain
);
1659 !domain
->internal
&&
1661 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1663 goto do_fetch_cache
;
1668 refresh_sequence_number(domain
, false);
1669 if (!NT_STATUS_IS_OK(status
)) {
1672 centry
= centry_start(domain
, status
);
1675 centry_put_uint32(centry
, *num_entries
);
1676 for (i
=0; i
<(*num_entries
); i
++) {
1677 centry_put_string(centry
, (*info
)[i
].acct_name
);
1678 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1679 centry_put_uint32(centry
, (*info
)[i
].rid
);
1681 centry_end(centry
, "GL/%s/domain", domain
->name
);
1682 centry_free(centry
);
1688 /* list all domain groups */
1689 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
1690 TALLOC_CTX
*mem_ctx
,
1691 uint32
*num_entries
,
1692 struct wb_acct_info
**info
)
1694 struct winbind_cache
*cache
= get_cache(domain
);
1695 struct cache_entry
*centry
= NULL
;
1700 old_status
= domain
->online
;
1704 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1709 *num_entries
= centry_uint32(centry
);
1711 if (*num_entries
== 0)
1714 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1716 smb_panic_fn("enum_dom_groups out of memory");
1718 for (i
=0; i
<(*num_entries
); i
++) {
1719 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1720 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1721 (*info
)[i
].rid
= centry_uint32(centry
);
1726 /* If we are returning cached data and the domain controller
1727 is down then we don't know whether the data is up to date
1728 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1731 if (wcache_server_down(domain
)) {
1732 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1733 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1735 status
= centry
->status
;
1737 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1738 domain
->name
, nt_errstr(status
) ));
1740 centry_free(centry
);
1747 /* Return status value returned by seq number check */
1749 if (!NT_STATUS_IS_OK(domain
->last_status
))
1750 return domain
->last_status
;
1752 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1755 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1757 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1758 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1759 if (!domain
->internal
&& old_status
) {
1760 set_domain_offline(domain
);
1763 !domain
->internal
&&
1766 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1768 goto do_fetch_cache
;
1773 refresh_sequence_number(domain
, false);
1774 if (!NT_STATUS_IS_OK(status
)) {
1777 centry
= centry_start(domain
, status
);
1780 centry_put_uint32(centry
, *num_entries
);
1781 for (i
=0; i
<(*num_entries
); i
++) {
1782 centry_put_string(centry
, (*info
)[i
].acct_name
);
1783 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1784 centry_put_uint32(centry
, (*info
)[i
].rid
);
1786 centry_end(centry
, "GL/%s/local", domain
->name
);
1787 centry_free(centry
);
1793 NTSTATUS
wcache_name_to_sid(struct winbindd_domain
*domain
,
1794 const char *domain_name
,
1796 struct dom_sid
*sid
,
1797 enum lsa_SidType
*type
)
1799 struct winbind_cache
*cache
= get_cache(domain
);
1800 struct cache_entry
*centry
;
1804 if (cache
->tdb
== NULL
) {
1805 return NT_STATUS_NOT_FOUND
;
1808 uname
= talloc_strdup_upper(talloc_tos(), name
);
1809 if (uname
== NULL
) {
1810 return NT_STATUS_NO_MEMORY
;
1813 if ((domain_name
== NULL
) || (domain_name
[0] == '\0')) {
1814 domain_name
= domain
->name
;
1817 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1819 if (centry
== NULL
) {
1820 return NT_STATUS_NOT_FOUND
;
1823 status
= centry
->status
;
1824 if (NT_STATUS_IS_OK(status
)) {
1825 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1826 centry_sid(centry
, sid
);
1829 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1830 "%s\n", domain
->name
, nt_errstr(status
) ));
1832 centry_free(centry
);
1836 /* convert a single name to a sid in a domain */
1837 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
1838 TALLOC_CTX
*mem_ctx
,
1839 const char *domain_name
,
1842 struct dom_sid
*sid
,
1843 enum lsa_SidType
*type
)
1848 old_status
= domain
->online
;
1850 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1851 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1857 /* If the seq number check indicated that there is a problem
1858 * with this DC, then return that status... except for
1859 * access_denied. This is special because the dc may be in
1860 * "restrict anonymous = 1" mode, in which case it will deny
1861 * most unauthenticated operations, but *will* allow the LSA
1862 * name-to-sid that we try as a fallback. */
1864 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1865 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1866 return domain
->last_status
;
1868 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1871 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
,
1872 name
, flags
, sid
, type
);
1874 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1875 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1876 if (!domain
->internal
&& old_status
) {
1877 set_domain_offline(domain
);
1879 if (!domain
->internal
&&
1882 NTSTATUS cache_status
;
1883 cache_status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1884 return cache_status
;
1888 refresh_sequence_number(domain
, false);
1890 if (domain
->online
&&
1891 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1892 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1894 /* Only save the reverse mapping if this was not a UPN */
1895 if (!strchr(name
, '@')) {
1896 if (!strupper_m(discard_const_p(char, domain_name
))) {
1897 return NT_STATUS_INVALID_PARAMETER
;
1899 (void)strlower_m(discard_const_p(char, name
));
1900 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1907 NTSTATUS
wcache_sid_to_name(struct winbindd_domain
*domain
,
1908 const struct dom_sid
*sid
,
1909 TALLOC_CTX
*mem_ctx
,
1912 enum lsa_SidType
*type
)
1914 struct winbind_cache
*cache
= get_cache(domain
);
1915 struct cache_entry
*centry
;
1919 if (cache
->tdb
== NULL
) {
1920 return NT_STATUS_NOT_FOUND
;
1923 sid_string
= sid_string_tos(sid
);
1924 if (sid_string
== NULL
) {
1925 return NT_STATUS_NO_MEMORY
;
1928 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_string
);
1929 TALLOC_FREE(sid_string
);
1930 if (centry
== NULL
) {
1931 return NT_STATUS_NOT_FOUND
;
1934 if (NT_STATUS_IS_OK(centry
->status
)) {
1935 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1936 *domain_name
= centry_string(centry
, mem_ctx
);
1937 *name
= centry_string(centry
, mem_ctx
);
1940 status
= centry
->status
;
1941 centry_free(centry
);
1943 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1944 "%s\n", domain
->name
, nt_errstr(status
) ));
1949 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1951 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1952 TALLOC_CTX
*mem_ctx
,
1953 const struct dom_sid
*sid
,
1956 enum lsa_SidType
*type
)
1961 old_status
= domain
->online
;
1962 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
1964 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1969 *domain_name
= NULL
;
1971 /* If the seq number check indicated that there is a problem
1972 * with this DC, then return that status... except for
1973 * access_denied. This is special because the dc may be in
1974 * "restrict anonymous = 1" mode, in which case it will deny
1975 * most unauthenticated operations, but *will* allow the LSA
1976 * sid-to-name that we try as a fallback. */
1978 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1979 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1980 return domain
->last_status
;
1982 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1985 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1987 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1988 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1989 if (!domain
->internal
&& old_status
) {
1990 set_domain_offline(domain
);
1992 if (!domain
->internal
&&
1995 NTSTATUS cache_status
;
1996 cache_status
= wcache_sid_to_name(domain
, sid
, mem_ctx
,
1997 domain_name
, name
, type
);
1998 return cache_status
;
2002 refresh_sequence_number(domain
, false);
2003 if (!NT_STATUS_IS_OK(status
)) {
2006 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
2008 /* We can't save the name to sid mapping here, as with sid history a
2009 * later name2sid would give the wrong sid. */
2014 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
2015 TALLOC_CTX
*mem_ctx
,
2016 const struct dom_sid
*domain_sid
,
2021 enum lsa_SidType
**types
)
2023 struct winbind_cache
*cache
= get_cache(domain
);
2025 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
2030 old_status
= domain
->online
;
2031 *domain_name
= NULL
;
2039 if (num_rids
== 0) {
2040 return NT_STATUS_OK
;
2043 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2044 *types
= talloc_array(mem_ctx
, enum lsa_SidType
, num_rids
);
2046 if ((*names
== NULL
) || (*types
== NULL
)) {
2047 result
= NT_STATUS_NO_MEMORY
;
2051 have_mapped
= have_unmapped
= false;
2053 for (i
=0; i
<num_rids
; i
++) {
2055 struct cache_entry
*centry
;
2058 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2059 result
= NT_STATUS_INTERNAL_ERROR
;
2063 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2064 sid_to_fstring(tmp
, &sid
));
2069 (*types
)[i
] = SID_NAME_UNKNOWN
;
2070 (*names
)[i
] = talloc_strdup(*names
, "");
2072 if (NT_STATUS_IS_OK(centry
->status
)) {
2075 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2077 dom
= centry_string(centry
, mem_ctx
);
2078 if (*domain_name
== NULL
) {
2084 (*names
)[i
] = centry_string(centry
, *names
);
2086 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)
2087 || NT_STATUS_EQUAL(centry
->status
, STATUS_SOME_UNMAPPED
)) {
2088 have_unmapped
= true;
2091 /* something's definitely wrong */
2092 result
= centry
->status
;
2096 centry_free(centry
);
2100 return NT_STATUS_NONE_MAPPED
;
2102 if (!have_unmapped
) {
2103 return NT_STATUS_OK
;
2105 return STATUS_SOME_UNMAPPED
;
2109 TALLOC_FREE(*names
);
2110 TALLOC_FREE(*types
);
2112 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
2113 rids
, num_rids
, domain_name
,
2116 if (NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
2117 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2118 if (!domain
->internal
&& old_status
) {
2119 set_domain_offline(domain
);
2122 !domain
->internal
&&
2125 have_mapped
= have_unmapped
= false;
2127 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2128 if (*names
== NULL
) {
2129 result
= NT_STATUS_NO_MEMORY
;
2133 *types
= talloc_array(mem_ctx
, enum lsa_SidType
,
2135 if (*types
== NULL
) {
2136 result
= NT_STATUS_NO_MEMORY
;
2140 for (i
=0; i
<num_rids
; i
++) {
2142 struct cache_entry
*centry
;
2145 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2146 result
= NT_STATUS_INTERNAL_ERROR
;
2150 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2151 sid_to_fstring(tmp
, &sid
));
2153 (*types
)[i
] = SID_NAME_UNKNOWN
;
2154 (*names
)[i
] = talloc_strdup(*names
, "");
2158 (*types
)[i
] = SID_NAME_UNKNOWN
;
2159 (*names
)[i
] = talloc_strdup(*names
, "");
2161 if (NT_STATUS_IS_OK(centry
->status
)) {
2164 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2166 dom
= centry_string(centry
, mem_ctx
);
2167 if (*domain_name
== NULL
) {
2173 (*names
)[i
] = centry_string(centry
, *names
);
2175 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)) {
2176 have_unmapped
= true;
2179 /* something's definitely wrong */
2180 result
= centry
->status
;
2181 centry_free(centry
);
2185 centry_free(centry
);
2189 return NT_STATUS_NONE_MAPPED
;
2191 if (!have_unmapped
) {
2192 return NT_STATUS_OK
;
2194 return STATUS_SOME_UNMAPPED
;
2198 None of the queried rids has been found so save all negative entries
2200 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
2201 for (i
= 0; i
< num_rids
; i
++) {
2203 const char *name
= "";
2204 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
2205 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
2207 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2208 return NT_STATUS_INTERNAL_ERROR
;
2211 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2219 Some or all of the queried rids have been found.
2221 if (!NT_STATUS_IS_OK(result
) &&
2222 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
2226 refresh_sequence_number(domain
, false);
2228 for (i
=0; i
<num_rids
; i
++) {
2232 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2233 result
= NT_STATUS_INTERNAL_ERROR
;
2237 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
2238 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
2240 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2241 (*names
)[i
], (*types
)[i
]);
2247 TALLOC_FREE(*names
);
2248 TALLOC_FREE(*types
);
2252 NTSTATUS
wcache_query_user(struct winbindd_domain
*domain
,
2253 TALLOC_CTX
*mem_ctx
,
2254 const struct dom_sid
*user_sid
,
2255 struct wbint_userinfo
*info
)
2257 struct winbind_cache
*cache
= get_cache(domain
);
2258 struct cache_entry
*centry
= NULL
;
2262 if (cache
->tdb
== NULL
) {
2263 return NT_STATUS_NOT_FOUND
;
2266 sid_string
= sid_string_tos(user_sid
);
2267 if (sid_string
== NULL
) {
2268 return NT_STATUS_NO_MEMORY
;
2271 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string
);
2272 TALLOC_FREE(sid_string
);
2273 if (centry
== NULL
) {
2274 return NT_STATUS_NOT_FOUND
;
2278 * If we have an access denied cache entry and a cached info3
2279 * in the samlogon cache then do a query. This will force the
2280 * rpc back end to return the info3 data.
2283 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
) &&
2284 netsamlogon_cache_have(user_sid
)) {
2285 DEBUG(10, ("query_user: cached access denied and have cached "
2287 domain
->last_status
= NT_STATUS_OK
;
2288 centry_free(centry
);
2289 return NT_STATUS_NOT_FOUND
;
2292 /* if status is not ok then this is a negative hit
2293 and the rest of the data doesn't matter */
2294 status
= centry
->status
;
2295 if (NT_STATUS_IS_OK(status
)) {
2296 info
->acct_name
= centry_string(centry
, mem_ctx
);
2297 info
->full_name
= centry_string(centry
, mem_ctx
);
2298 info
->homedir
= centry_string(centry
, mem_ctx
);
2299 info
->shell
= centry_string(centry
, mem_ctx
);
2300 info
->primary_gid
= centry_uint32(centry
);
2301 centry_sid(centry
, &info
->user_sid
);
2302 centry_sid(centry
, &info
->group_sid
);
2305 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2306 "%s\n", domain
->name
, nt_errstr(status
) ));
2308 centry_free(centry
);
2312 /* Lookup user information from a rid */
2313 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
2314 TALLOC_CTX
*mem_ctx
,
2315 const struct dom_sid
*user_sid
,
2316 struct wbint_userinfo
*info
)
2321 old_status
= domain
->online
;
2322 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2323 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2329 /* Return status value returned by seq number check */
2331 if (!NT_STATUS_IS_OK(domain
->last_status
))
2332 return domain
->last_status
;
2334 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2337 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
2339 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2340 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2341 if (!domain
->internal
&& old_status
) {
2342 set_domain_offline(domain
);
2344 if (!domain
->internal
&&
2347 NTSTATUS cache_status
;
2348 cache_status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2349 return cache_status
;
2353 refresh_sequence_number(domain
, false);
2354 if (!NT_STATUS_IS_OK(status
)) {
2357 wcache_save_user(domain
, status
, info
);
2362 NTSTATUS
wcache_lookup_usergroups(struct winbindd_domain
*domain
,
2363 TALLOC_CTX
*mem_ctx
,
2364 const struct dom_sid
*user_sid
,
2365 uint32_t *pnum_sids
,
2366 struct dom_sid
**psids
)
2368 struct winbind_cache
*cache
= get_cache(domain
);
2369 struct cache_entry
*centry
= NULL
;
2371 uint32_t i
, num_sids
;
2372 struct dom_sid
*sids
;
2375 if (cache
->tdb
== NULL
) {
2376 return NT_STATUS_NOT_FOUND
;
2379 centry
= wcache_fetch(cache
, domain
, "UG/%s",
2380 sid_to_fstring(sid_string
, user_sid
));
2381 if (centry
== NULL
) {
2382 return NT_STATUS_NOT_FOUND
;
2385 /* If we have an access denied cache entry and a cached info3 in the
2386 samlogon cache then do a query. This will force the rpc back end
2387 to return the info3 data. */
2389 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)
2390 && netsamlogon_cache_have(user_sid
)) {
2391 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2393 domain
->last_status
= NT_STATUS_OK
;
2394 centry_free(centry
);
2395 return NT_STATUS_NOT_FOUND
;
2398 num_sids
= centry_uint32(centry
);
2399 sids
= talloc_array(mem_ctx
, struct dom_sid
, num_sids
);
2401 centry_free(centry
);
2402 return NT_STATUS_NO_MEMORY
;
2405 for (i
=0; i
<num_sids
; i
++) {
2406 centry_sid(centry
, &sids
[i
]);
2409 status
= centry
->status
;
2411 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2412 "status: %s\n", domain
->name
, nt_errstr(status
)));
2414 centry_free(centry
);
2416 *pnum_sids
= num_sids
;
2421 /* Lookup groups a user is a member of. */
2422 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
2423 TALLOC_CTX
*mem_ctx
,
2424 const struct dom_sid
*user_sid
,
2425 uint32
*num_groups
, struct dom_sid
**user_gids
)
2427 struct cache_entry
*centry
= NULL
;
2433 old_status
= domain
->online
;
2434 status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2435 num_groups
, user_gids
);
2436 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2441 (*user_gids
) = NULL
;
2443 /* Return status value returned by seq number check */
2445 if (!NT_STATUS_IS_OK(domain
->last_status
))
2446 return domain
->last_status
;
2448 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2451 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
2453 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2454 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2455 if (!domain
->internal
&& old_status
) {
2456 set_domain_offline(domain
);
2458 if (!domain
->internal
&&
2461 NTSTATUS cache_status
;
2462 cache_status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2463 num_groups
, user_gids
);
2464 return cache_status
;
2467 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
2471 refresh_sequence_number(domain
, false);
2472 if (!NT_STATUS_IS_OK(status
)) {
2475 centry
= centry_start(domain
, status
);
2479 centry_put_uint32(centry
, *num_groups
);
2480 for (i
=0; i
<(*num_groups
); i
++) {
2481 centry_put_sid(centry
, &(*user_gids
)[i
]);
2484 centry_end(centry
, "UG/%s", sid_to_fstring(sid_string
, user_sid
));
2485 centry_free(centry
);
2491 static char *wcache_make_sidlist(TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2492 const struct dom_sid
*sids
)
2497 sidlist
= talloc_strdup(mem_ctx
, "");
2498 if (sidlist
== NULL
) {
2501 for (i
=0; i
<num_sids
; i
++) {
2503 sidlist
= talloc_asprintf_append_buffer(
2504 sidlist
, "/%s", sid_to_fstring(tmp
, &sids
[i
]));
2505 if (sidlist
== NULL
) {
2512 NTSTATUS
wcache_lookup_useraliases(struct winbindd_domain
*domain
,
2513 TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2514 const struct dom_sid
*sids
,
2515 uint32_t *pnum_aliases
, uint32_t **paliases
)
2517 struct winbind_cache
*cache
= get_cache(domain
);
2518 struct cache_entry
*centry
= NULL
;
2519 uint32_t num_aliases
;
2525 if (cache
->tdb
== NULL
) {
2526 return NT_STATUS_NOT_FOUND
;
2529 if (num_sids
== 0) {
2532 return NT_STATUS_OK
;
2535 /* We need to cache indexed by the whole list of SIDs, the aliases
2536 * resulting might come from any of the SIDs. */
2538 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2539 if (sidlist
== NULL
) {
2540 return NT_STATUS_NO_MEMORY
;
2543 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2544 TALLOC_FREE(sidlist
);
2545 if (centry
== NULL
) {
2546 return NT_STATUS_NOT_FOUND
;
2549 num_aliases
= centry_uint32(centry
);
2550 aliases
= talloc_array(mem_ctx
, uint32_t, num_aliases
);
2551 if (aliases
== NULL
) {
2552 centry_free(centry
);
2553 return NT_STATUS_NO_MEMORY
;
2556 for (i
=0; i
<num_aliases
; i
++) {
2557 aliases
[i
] = centry_uint32(centry
);
2560 status
= centry
->status
;
2562 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2563 "status %s\n", domain
->name
, nt_errstr(status
)));
2565 centry_free(centry
);
2567 *pnum_aliases
= num_aliases
;
2568 *paliases
= aliases
;
2573 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
2574 TALLOC_CTX
*mem_ctx
,
2575 uint32 num_sids
, const struct dom_sid
*sids
,
2576 uint32
*num_aliases
, uint32
**alias_rids
)
2578 struct cache_entry
*centry
= NULL
;
2584 old_status
= domain
->online
;
2585 status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
2586 num_aliases
, alias_rids
);
2587 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2592 (*alias_rids
) = NULL
;
2594 if (!NT_STATUS_IS_OK(domain
->last_status
))
2595 return domain
->last_status
;
2597 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2598 "for domain %s\n", domain
->name
));
2600 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2601 if (sidlist
== NULL
) {
2602 return NT_STATUS_NO_MEMORY
;
2605 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2607 num_aliases
, alias_rids
);
2609 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2610 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2611 if (!domain
->internal
&& old_status
) {
2612 set_domain_offline(domain
);
2614 if (!domain
->internal
&&
2617 NTSTATUS cache_status
;
2618 cache_status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
,
2619 sids
, num_aliases
, alias_rids
);
2620 return cache_status
;
2624 refresh_sequence_number(domain
, false);
2625 if (!NT_STATUS_IS_OK(status
)) {
2628 centry
= centry_start(domain
, status
);
2631 centry_put_uint32(centry
, *num_aliases
);
2632 for (i
=0; i
<(*num_aliases
); i
++)
2633 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2634 centry_end(centry
, "UA%s", sidlist
);
2635 centry_free(centry
);
2641 NTSTATUS
wcache_lookup_groupmem(struct winbindd_domain
*domain
,
2642 TALLOC_CTX
*mem_ctx
,
2643 const struct dom_sid
*group_sid
,
2644 uint32_t *num_names
,
2645 struct dom_sid
**sid_mem
, char ***names
,
2646 uint32_t **name_types
)
2648 struct winbind_cache
*cache
= get_cache(domain
);
2649 struct cache_entry
*centry
= NULL
;
2654 if (cache
->tdb
== NULL
) {
2655 return NT_STATUS_NOT_FOUND
;
2658 sid_string
= sid_string_tos(group_sid
);
2659 if (sid_string
== NULL
) {
2660 return NT_STATUS_NO_MEMORY
;
2663 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_string
);
2664 TALLOC_FREE(sid_string
);
2665 if (centry
== NULL
) {
2666 return NT_STATUS_NOT_FOUND
;
2673 *num_names
= centry_uint32(centry
);
2674 if (*num_names
== 0) {
2675 centry_free(centry
);
2676 return NT_STATUS_OK
;
2679 *sid_mem
= talloc_array(mem_ctx
, struct dom_sid
, *num_names
);
2680 *names
= talloc_array(mem_ctx
, char *, *num_names
);
2681 *name_types
= talloc_array(mem_ctx
, uint32
, *num_names
);
2683 if ((*sid_mem
== NULL
) || (*names
== NULL
) || (*name_types
== NULL
)) {
2684 TALLOC_FREE(*sid_mem
);
2685 TALLOC_FREE(*names
);
2686 TALLOC_FREE(*name_types
);
2687 centry_free(centry
);
2688 return NT_STATUS_NO_MEMORY
;
2691 for (i
=0; i
<(*num_names
); i
++) {
2692 centry_sid(centry
, &(*sid_mem
)[i
]);
2693 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2694 (*name_types
)[i
] = centry_uint32(centry
);
2697 status
= centry
->status
;
2699 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2700 "status: %s\n", domain
->name
, nt_errstr(status
)));
2702 centry_free(centry
);
2706 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
2707 TALLOC_CTX
*mem_ctx
,
2708 const struct dom_sid
*group_sid
,
2709 enum lsa_SidType type
,
2711 struct dom_sid
**sid_mem
, char ***names
,
2712 uint32
**name_types
)
2714 struct cache_entry
*centry
= NULL
;
2720 old_status
= domain
->online
;
2721 status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2722 sid_mem
, names
, name_types
);
2723 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2730 (*name_types
) = NULL
;
2732 /* Return status value returned by seq number check */
2734 if (!NT_STATUS_IS_OK(domain
->last_status
))
2735 return domain
->last_status
;
2737 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2740 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
,
2742 sid_mem
, names
, name_types
);
2744 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2745 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2746 if (!domain
->internal
&& old_status
) {
2747 set_domain_offline(domain
);
2749 if (!domain
->internal
&&
2752 NTSTATUS cache_status
;
2753 cache_status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
,
2754 num_names
, sid_mem
, names
,
2756 return cache_status
;
2760 refresh_sequence_number(domain
, false);
2761 if (!NT_STATUS_IS_OK(status
)) {
2764 centry
= centry_start(domain
, status
);
2767 centry_put_uint32(centry
, *num_names
);
2768 for (i
=0; i
<(*num_names
); i
++) {
2769 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2770 centry_put_string(centry
, (*names
)[i
]);
2771 centry_put_uint32(centry
, (*name_types
)[i
]);
2773 centry_end(centry
, "GM/%s", sid_to_fstring(sid_string
, group_sid
));
2774 centry_free(centry
);
2780 /* find the sequence number for a domain */
2781 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
2783 refresh_sequence_number(domain
, false);
2785 *seq
= domain
->sequence_number
;
2787 return NT_STATUS_OK
;
2790 /* enumerate trusted domains
2791 * (we need to have the list of trustdoms in the cache when we go offline) -
2793 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
2794 TALLOC_CTX
*mem_ctx
,
2795 struct netr_DomainTrustList
*trusts
)
2798 struct winbind_cache
*cache
;
2799 struct winbindd_tdc_domain
*dom_list
= NULL
;
2800 size_t num_domains
= 0;
2801 bool retval
= false;
2805 old_status
= domain
->online
;
2807 trusts
->array
= NULL
;
2809 cache
= get_cache(domain
);
2810 if (!cache
|| !cache
->tdb
) {
2814 if (domain
->online
) {
2818 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2819 if (!retval
|| !num_domains
|| !dom_list
) {
2820 TALLOC_FREE(dom_list
);
2825 trusts
->array
= talloc_zero_array(mem_ctx
, struct netr_DomainTrust
, num_domains
);
2826 if (!trusts
->array
) {
2827 TALLOC_FREE(dom_list
);
2828 return NT_STATUS_NO_MEMORY
;
2831 for (i
= 0; i
< num_domains
; i
++) {
2832 struct netr_DomainTrust
*trust
;
2833 struct dom_sid
*sid
;
2834 struct winbindd_domain
*dom
;
2836 dom
= find_domain_from_name_noinit(dom_list
[i
].domain_name
);
2837 if (dom
&& dom
->internal
) {
2841 trust
= &trusts
->array
[trusts
->count
];
2842 trust
->netbios_name
= talloc_strdup(trusts
->array
, dom_list
[i
].domain_name
);
2843 trust
->dns_name
= talloc_strdup(trusts
->array
, dom_list
[i
].dns_name
);
2844 sid
= talloc(trusts
->array
, struct dom_sid
);
2845 if (!trust
->netbios_name
|| !trust
->dns_name
||
2847 TALLOC_FREE(dom_list
);
2848 TALLOC_FREE(trusts
->array
);
2849 return NT_STATUS_NO_MEMORY
;
2852 trust
->trust_flags
= dom_list
[i
].trust_flags
;
2853 trust
->trust_attributes
= dom_list
[i
].trust_attribs
;
2854 trust
->trust_type
= dom_list
[i
].trust_type
;
2855 sid_copy(sid
, &dom_list
[i
].sid
);
2860 TALLOC_FREE(dom_list
);
2861 return NT_STATUS_OK
;
2864 /* Return status value returned by seq number check */
2866 if (!NT_STATUS_IS_OK(domain
->last_status
))
2867 return domain
->last_status
;
2869 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2872 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, trusts
);
2874 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2875 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2876 if (!domain
->internal
&& old_status
) {
2877 set_domain_offline(domain
);
2879 if (!domain
->internal
&&
2882 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2883 if (retval
&& num_domains
&& dom_list
) {
2884 TALLOC_FREE(trusts
->array
);
2886 goto do_fetch_cache
;
2890 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2891 * so that the generic centry handling still applies correctly -
2894 if (!NT_STATUS_IS_ERR(status
)) {
2895 status
= NT_STATUS_OK
;
2900 /* get lockout policy */
2901 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
2902 TALLOC_CTX
*mem_ctx
,
2903 struct samr_DomInfo12
*policy
)
2905 struct winbind_cache
*cache
= get_cache(domain
);
2906 struct cache_entry
*centry
= NULL
;
2910 old_status
= domain
->online
;
2914 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2920 policy
->lockout_duration
= centry_nttime(centry
);
2921 policy
->lockout_window
= centry_nttime(centry
);
2922 policy
->lockout_threshold
= centry_uint16(centry
);
2924 status
= centry
->status
;
2926 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2927 domain
->name
, nt_errstr(status
) ));
2929 centry_free(centry
);
2933 ZERO_STRUCTP(policy
);
2935 /* Return status value returned by seq number check */
2937 if (!NT_STATUS_IS_OK(domain
->last_status
))
2938 return domain
->last_status
;
2940 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2943 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2945 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2946 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2947 if (!domain
->internal
&& old_status
) {
2948 set_domain_offline(domain
);
2951 !domain
->internal
&&
2954 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2956 goto do_fetch_cache
;
2961 refresh_sequence_number(domain
, false);
2962 if (!NT_STATUS_IS_OK(status
)) {
2965 wcache_save_lockout_policy(domain
, status
, policy
);
2970 /* get password policy */
2971 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
2972 TALLOC_CTX
*mem_ctx
,
2973 struct samr_DomInfo1
*policy
)
2975 struct winbind_cache
*cache
= get_cache(domain
);
2976 struct cache_entry
*centry
= NULL
;
2980 old_status
= domain
->online
;
2984 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2990 policy
->min_password_length
= centry_uint16(centry
);
2991 policy
->password_history_length
= centry_uint16(centry
);
2992 policy
->password_properties
= centry_uint32(centry
);
2993 policy
->max_password_age
= centry_nttime(centry
);
2994 policy
->min_password_age
= centry_nttime(centry
);
2996 status
= centry
->status
;
2998 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2999 domain
->name
, nt_errstr(status
) ));
3001 centry_free(centry
);
3005 ZERO_STRUCTP(policy
);
3007 /* Return status value returned by seq number check */
3009 if (!NT_STATUS_IS_OK(domain
->last_status
))
3010 return domain
->last_status
;
3012 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
3015 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
3017 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
3018 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
3019 if (!domain
->internal
&& old_status
) {
3020 set_domain_offline(domain
);
3023 !domain
->internal
&&
3026 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
3028 goto do_fetch_cache
;
3033 refresh_sequence_number(domain
, false);
3034 if (!NT_STATUS_IS_OK(status
)) {
3037 wcache_save_password_policy(domain
, status
, policy
);
3043 /* Invalidate cached user and group lists coherently */
3045 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3048 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
3049 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
3050 tdb_delete(the_tdb
, kbuf
);
3055 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3057 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
3058 const struct dom_sid
*sid
)
3060 fstring key_str
, sid_string
;
3061 struct winbind_cache
*cache
;
3063 /* dont clear cached U/SID and UG/SID entries when we want to logon
3066 if (lp_winbind_offline_logon()) {
3073 cache
= get_cache(domain
);
3079 /* Clear U/SID cache entry */
3080 fstr_sprintf(key_str
, "U/%s", sid_to_fstring(sid_string
, sid
));
3081 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3082 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3084 /* Clear UG/SID cache entry */
3085 fstr_sprintf(key_str
, "UG/%s", sid_to_fstring(sid_string
, sid
));
3086 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3087 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3089 /* Samba/winbindd never needs this. */
3090 netsamlogon_clear_cached_user(sid
);
3093 bool wcache_invalidate_cache(void)
3095 struct winbindd_domain
*domain
;
3097 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3098 struct winbind_cache
*cache
= get_cache(domain
);
3100 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3101 "entries for %s\n", domain
->name
));
3104 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3113 bool wcache_invalidate_cache_noinit(void)
3115 struct winbindd_domain
*domain
;
3117 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3118 struct winbind_cache
*cache
;
3120 /* Skip uninitialized domains. */
3121 if (!domain
->initialized
&& !domain
->internal
) {
3125 cache
= get_cache(domain
);
3127 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3128 "entries for %s\n", domain
->name
));
3131 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3133 * Flushing cache has nothing to with domains.
3134 * return here if we successfully flushed once.
3135 * To avoid unnecessary traversing the cache.
3146 bool init_wcache(void)
3148 if (wcache
== NULL
) {
3149 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
3150 ZERO_STRUCTP(wcache
);
3153 if (wcache
->tdb
!= NULL
)
3156 /* when working offline we must not clear the cache on restart */
3157 wcache
->tdb
= tdb_open_log(state_path("winbindd_cache.tdb"),
3158 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3159 TDB_INCOMPATIBLE_HASH
|
3160 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3161 O_RDWR
|O_CREAT
, 0600);
3163 if (wcache
->tdb
== NULL
) {
3164 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3171 /************************************************************************
3172 This is called by the parent to initialize the cache file.
3173 We don't need sophisticated locking here as we know we're the
3175 ************************************************************************/
3177 bool initialize_winbindd_cache(void)
3179 bool cache_bad
= true;
3182 if (!init_wcache()) {
3183 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3187 /* Check version number. */
3188 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
3189 vers
== WINBINDD_CACHE_VERSION
) {
3194 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3195 "and re-creating with version number %d\n",
3196 WINBINDD_CACHE_VERSION
));
3198 tdb_close(wcache
->tdb
);
3201 if (unlink(state_path("winbindd_cache.tdb")) == -1) {
3202 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3203 state_path("winbindd_cache.tdb"),
3207 if (!init_wcache()) {
3208 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3209 "init_wcache failed.\n"));
3213 /* Write the version. */
3214 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
3215 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3216 tdb_errorstr_compat(wcache
->tdb
) ));
3221 tdb_close(wcache
->tdb
);
3226 void close_winbindd_cache(void)
3232 tdb_close(wcache
->tdb
);
3237 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*sid
,
3238 char **domain_name
, char **name
,
3239 enum lsa_SidType
*type
)
3241 struct winbindd_domain
*domain
;
3244 domain
= find_lookup_domain_from_sid(sid
);
3245 if (domain
== NULL
) {
3248 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
3250 return NT_STATUS_IS_OK(status
);
3253 bool lookup_cached_name(const char *domain_name
,
3255 struct dom_sid
*sid
,
3256 enum lsa_SidType
*type
)
3258 struct winbindd_domain
*domain
;
3260 bool original_online_state
;
3262 domain
= find_lookup_domain_from_name(domain_name
);
3263 if (domain
== NULL
) {
3267 /* If we are doing a cached logon, temporarily set the domain
3268 offline so the cache won't expire the entry */
3270 original_online_state
= domain
->online
;
3271 domain
->online
= false;
3272 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
3273 domain
->online
= original_online_state
;
3275 return NT_STATUS_IS_OK(status
);
3278 void cache_name2sid(struct winbindd_domain
*domain
,
3279 const char *domain_name
, const char *name
,
3280 enum lsa_SidType type
, const struct dom_sid
*sid
)
3282 refresh_sequence_number(domain
, false);
3283 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
3288 * The original idea that this cache only contains centries has
3289 * been blurred - now other stuff gets put in here. Ensure we
3290 * ignore these things on cleanup.
3293 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
3294 TDB_DATA dbuf
, void *state
)
3296 struct cache_entry
*centry
;
3298 if (is_non_centry_key(kbuf
)) {
3302 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
3307 if (!NT_STATUS_IS_OK(centry
->status
)) {
3308 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
3309 tdb_delete(the_tdb
, kbuf
);
3312 centry_free(centry
);
3316 /* flush the cache */
3317 void wcache_flush_cache(void)
3322 tdb_close(wcache
->tdb
);
3325 if (!winbindd_use_cache()) {
3329 /* when working offline we must not clear the cache on restart */
3330 wcache
->tdb
= tdb_open_log(state_path("winbindd_cache.tdb"),
3331 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3332 TDB_INCOMPATIBLE_HASH
|
3333 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3334 O_RDWR
|O_CREAT
, 0600);
3337 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3341 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
3343 DEBUG(10,("wcache_flush_cache success\n"));
3346 /* Count cached creds */
3348 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3351 int *cred_count
= (int*)state
;
3353 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3359 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
3361 struct winbind_cache
*cache
= get_cache(domain
);
3366 return NT_STATUS_INTERNAL_DB_ERROR
;
3369 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
3371 return NT_STATUS_OK
;
3375 struct cred_list
*prev
, *next
;
3380 static struct cred_list
*wcache_cred_list
;
3382 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3385 struct cred_list
*cred
;
3387 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3389 cred
= SMB_MALLOC_P(struct cred_list
);
3391 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3397 /* save a copy of the key */
3399 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
3400 DLIST_ADD(wcache_cred_list
, cred
);
3406 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
3408 struct winbind_cache
*cache
= get_cache(domain
);
3411 struct cred_list
*cred
, *oldest
= NULL
;
3414 return NT_STATUS_INTERNAL_DB_ERROR
;
3417 /* we possibly already have an entry */
3418 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
3420 fstring key_str
, tmp
;
3422 DEBUG(11,("we already have an entry, deleting that\n"));
3424 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
3426 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3428 return NT_STATUS_OK
;
3431 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
3433 return NT_STATUS_OK
;
3434 } else if ((ret
< 0) || (wcache_cred_list
== NULL
)) {
3435 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3438 ZERO_STRUCTP(oldest
);
3440 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
3445 data
= tdb_fetch_compat(cache
->tdb
, string_tdb_data(cred
->name
));
3447 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3449 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3453 t
= IVAL(data
.dptr
, 0);
3454 SAFE_FREE(data
.dptr
);
3457 oldest
= SMB_MALLOC_P(struct cred_list
);
3458 if (oldest
== NULL
) {
3459 status
= NT_STATUS_NO_MEMORY
;
3463 fstrcpy(oldest
->name
, cred
->name
);
3464 oldest
->created
= t
;
3468 if (t
< oldest
->created
) {
3469 fstrcpy(oldest
->name
, cred
->name
);
3470 oldest
->created
= t
;
3474 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3475 status
= NT_STATUS_OK
;
3477 status
= NT_STATUS_UNSUCCESSFUL
;
3480 SAFE_FREE(wcache_cred_list
);
3486 /* Change the global online/offline state. */
3487 bool set_global_winbindd_state_offline(void)
3491 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3493 /* Only go offline if someone has created
3494 the key "WINBINDD_OFFLINE" in the cache tdb. */
3496 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3497 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3501 if (!lp_winbind_offline_logon()) {
3502 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3506 if (global_winbindd_offline_state
) {
3507 /* Already offline. */
3511 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
3513 if (!data
.dptr
|| data
.dsize
!= 4) {
3514 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3515 SAFE_FREE(data
.dptr
);
3518 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3519 global_winbindd_offline_state
= true;
3520 SAFE_FREE(data
.dptr
);
3525 void set_global_winbindd_state_online(void)
3527 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3529 if (!lp_winbind_offline_logon()) {
3530 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3534 if (!global_winbindd_offline_state
) {
3535 /* Already online. */
3538 global_winbindd_offline_state
= false;
3544 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3545 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3548 bool get_global_winbindd_state_offline(void)
3550 return global_winbindd_offline_state
;
3553 /***********************************************************************
3554 Validate functions for all possible cache tdb keys.
3555 ***********************************************************************/
3557 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3558 struct tdb_validation_status
*state
)
3560 struct cache_entry
*centry
;
3562 centry
= SMB_XMALLOC_P(struct cache_entry
);
3563 centry
->data
= (unsigned char *)smb_memdup(data
.dptr
, data
.dsize
);
3564 if (!centry
->data
) {
3568 centry
->len
= data
.dsize
;
3571 if (centry
->len
< 16) {
3572 /* huh? corrupt cache? */
3573 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3574 "(len < 16) ?\n", kstr
));
3575 centry_free(centry
);
3576 state
->bad_entry
= true;
3577 state
->success
= false;
3581 centry
->status
= NT_STATUS(centry_uint32(centry
));
3582 centry
->sequence_number
= centry_uint32(centry
);
3583 centry
->timeout
= centry_uint64_t(centry
);
3587 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3588 struct tdb_validation_status
*state
)
3590 if (dbuf
.dsize
!= 8) {
3591 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3592 keystr
, (unsigned int)dbuf
.dsize
));
3593 state
->bad_entry
= true;
3599 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3600 struct tdb_validation_status
*state
)
3602 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3607 (void)centry_uint32(centry
);
3608 if (NT_STATUS_IS_OK(centry
->status
)) {
3610 (void)centry_sid(centry
, &sid
);
3613 centry_free(centry
);
3615 if (!(state
->success
)) {
3618 DEBUG(10,("validate_ns: %s ok\n", keystr
));
3622 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3623 struct tdb_validation_status
*state
)
3625 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3630 if (NT_STATUS_IS_OK(centry
->status
)) {
3631 (void)centry_uint32(centry
);
3632 (void)centry_string(centry
, mem_ctx
);
3633 (void)centry_string(centry
, mem_ctx
);
3636 centry_free(centry
);
3638 if (!(state
->success
)) {
3641 DEBUG(10,("validate_sn: %s ok\n", keystr
));
3645 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3646 struct tdb_validation_status
*state
)
3648 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3655 (void)centry_string(centry
, mem_ctx
);
3656 (void)centry_string(centry
, mem_ctx
);
3657 (void)centry_string(centry
, mem_ctx
);
3658 (void)centry_string(centry
, mem_ctx
);
3659 (void)centry_uint32(centry
);
3660 (void)centry_sid(centry
, &sid
);
3661 (void)centry_sid(centry
, &sid
);
3663 centry_free(centry
);
3665 if (!(state
->success
)) {
3668 DEBUG(10,("validate_u: %s ok\n", keystr
));
3672 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3673 struct tdb_validation_status
*state
)
3675 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3681 (void)centry_nttime(centry
);
3682 (void)centry_nttime(centry
);
3683 (void)centry_uint16(centry
);
3685 centry_free(centry
);
3687 if (!(state
->success
)) {
3690 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3694 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3695 struct tdb_validation_status
*state
)
3697 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3703 (void)centry_uint16(centry
);
3704 (void)centry_uint16(centry
);
3705 (void)centry_uint32(centry
);
3706 (void)centry_nttime(centry
);
3707 (void)centry_nttime(centry
);
3709 centry_free(centry
);
3711 if (!(state
->success
)) {
3714 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3718 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3719 struct tdb_validation_status
*state
)
3721 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3727 (void)centry_time(centry
);
3728 (void)centry_hash16(centry
, mem_ctx
);
3730 /* We only have 17 bytes more data in the salted cred case. */
3731 if (centry
->len
- centry
->ofs
== 17) {
3732 (void)centry_hash16(centry
, mem_ctx
);
3735 centry_free(centry
);
3737 if (!(state
->success
)) {
3740 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3744 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3745 struct tdb_validation_status
*state
)
3747 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3748 int32 num_entries
, i
;
3754 num_entries
= (int32
)centry_uint32(centry
);
3756 for (i
=0; i
< num_entries
; i
++) {
3758 (void)centry_string(centry
, mem_ctx
);
3759 (void)centry_string(centry
, mem_ctx
);
3760 (void)centry_string(centry
, mem_ctx
);
3761 (void)centry_string(centry
, mem_ctx
);
3762 (void)centry_sid(centry
, &sid
);
3763 (void)centry_sid(centry
, &sid
);
3766 centry_free(centry
);
3768 if (!(state
->success
)) {
3771 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3775 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3776 struct tdb_validation_status
*state
)
3778 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3779 int32 num_entries
, i
;
3785 num_entries
= centry_uint32(centry
);
3787 for (i
=0; i
< num_entries
; i
++) {
3788 (void)centry_string(centry
, mem_ctx
);
3789 (void)centry_string(centry
, mem_ctx
);
3790 (void)centry_uint32(centry
);
3793 centry_free(centry
);
3795 if (!(state
->success
)) {
3798 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3802 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3803 struct tdb_validation_status
*state
)
3805 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3806 int32 num_groups
, i
;
3812 num_groups
= centry_uint32(centry
);
3814 for (i
=0; i
< num_groups
; i
++) {
3816 centry_sid(centry
, &sid
);
3819 centry_free(centry
);
3821 if (!(state
->success
)) {
3824 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3828 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3829 struct tdb_validation_status
*state
)
3831 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3832 int32 num_aliases
, i
;
3838 num_aliases
= centry_uint32(centry
);
3840 for (i
=0; i
< num_aliases
; i
++) {
3841 (void)centry_uint32(centry
);
3844 centry_free(centry
);
3846 if (!(state
->success
)) {
3849 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3853 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3854 struct tdb_validation_status
*state
)
3856 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3863 num_names
= centry_uint32(centry
);
3865 for (i
=0; i
< num_names
; i
++) {
3867 centry_sid(centry
, &sid
);
3868 (void)centry_string(centry
, mem_ctx
);
3869 (void)centry_uint32(centry
);
3872 centry_free(centry
);
3874 if (!(state
->success
)) {
3877 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3881 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3882 struct tdb_validation_status
*state
)
3884 /* Can't say anything about this other than must be nonzero. */
3885 if (dbuf
.dsize
== 0) {
3886 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3888 state
->bad_entry
= true;
3889 state
->success
= false;
3893 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3897 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3898 struct tdb_validation_status
*state
)
3900 /* Can't say anything about this other than must be nonzero. */
3901 if (dbuf
.dsize
== 0) {
3902 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3904 state
->bad_entry
= true;
3905 state
->success
= false;
3909 DEBUG(10,("validate_de: %s ok\n", keystr
));
3913 static int validate_pwinfo(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3914 TDB_DATA dbuf
, struct tdb_validation_status
*state
)
3916 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3922 (void)centry_string(centry
, mem_ctx
);
3923 (void)centry_string(centry
, mem_ctx
);
3924 (void)centry_string(centry
, mem_ctx
);
3925 (void)centry_uint32(centry
);
3927 centry_free(centry
);
3929 if (!(state
->success
)) {
3932 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3936 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3938 struct tdb_validation_status
*state
)
3940 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3946 (void)centry_string( centry
, mem_ctx
);
3948 centry_free(centry
);
3950 if (!(state
->success
)) {
3953 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3957 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3959 struct tdb_validation_status
*state
)
3961 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3967 (void)centry_string( centry
, mem_ctx
);
3969 centry_free(centry
);
3971 if (!(state
->success
)) {
3974 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3978 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3980 struct tdb_validation_status
*state
)
3982 if (dbuf
.dsize
== 0) {
3983 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3984 "key %s (len ==0) ?\n", keystr
));
3985 state
->bad_entry
= true;
3986 state
->success
= false;
3990 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3991 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3995 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3996 struct tdb_validation_status
*state
)
3998 if (dbuf
.dsize
!= 4) {
3999 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
4000 keystr
, (unsigned int)dbuf
.dsize
));
4001 state
->bad_entry
= true;
4002 state
->success
= false;
4005 DEBUG(10,("validate_offline: %s ok\n", keystr
));
4009 static int validate_ndr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
4010 struct tdb_validation_status
*state
)
4013 * Ignore validation for now. The proper way to do this is with a
4014 * checksum. Just pure parsing does not really catch much.
4019 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
4020 struct tdb_validation_status
*state
)
4022 if (dbuf
.dsize
!= 4) {
4023 DEBUG(0, ("validate_cache_version: Corrupt cache for "
4024 "key %s (len %u != 4) ?\n",
4025 keystr
, (unsigned int)dbuf
.dsize
));
4026 state
->bad_entry
= true;
4027 state
->success
= false;
4031 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
4035 /***********************************************************************
4036 A list of all possible cache tdb keys with associated validation
4038 ***********************************************************************/
4040 struct key_val_struct
{
4041 const char *keyname
;
4042 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
4044 {"SEQNUM/", validate_seqnum
},
4045 {"NS/", validate_ns
},
4046 {"SN/", validate_sn
},
4048 {"LOC_POL/", validate_loc_pol
},
4049 {"PWD_POL/", validate_pwd_pol
},
4050 {"CRED/", validate_cred
},
4051 {"UL/", validate_ul
},
4052 {"GL/", validate_gl
},
4053 {"UG/", validate_ug
},
4054 {"UA", validate_ua
},
4055 {"GM/", validate_gm
},
4056 {"DR/", validate_dr
},
4057 {"DE/", validate_de
},
4058 {"NSS/PWINFO/", validate_pwinfo
},
4059 {"TRUSTDOMCACHE/", validate_trustdomcache
},
4060 {"NSS/NA/", validate_nss_na
},
4061 {"NSS/AN/", validate_nss_an
},
4062 {"WINBINDD_OFFLINE", validate_offline
},
4063 {"NDR/", validate_ndr
},
4064 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
4068 /***********************************************************************
4069 Function to look at every entry in the tdb and validate it as far as
4071 ***********************************************************************/
4073 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
4076 unsigned int max_key_len
= 1024;
4077 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
4079 /* Paranoia check. */
4080 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0 ||
4081 strncmp("NDR/", (const char *)kbuf
.dptr
, 4) == 0) {
4082 max_key_len
= 1024 * 1024;
4084 if (kbuf
.dsize
> max_key_len
) {
4085 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4087 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
4091 for (i
= 0; key_val
[i
].keyname
; i
++) {
4092 size_t namelen
= strlen(key_val
[i
].keyname
);
4093 if (kbuf
.dsize
>= namelen
&& (
4094 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
4095 TALLOC_CTX
*mem_ctx
;
4099 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
4103 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
4104 keystr
[kbuf
.dsize
] = '\0';
4106 mem_ctx
= talloc_init("validate_ctx");
4112 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
4116 talloc_destroy(mem_ctx
);
4121 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4122 dump_data(0, (uint8
*)kbuf
.dptr
, kbuf
.dsize
);
4123 DEBUG(0,("data :\n"));
4124 dump_data(0, (uint8
*)dbuf
.dptr
, dbuf
.dsize
);
4125 v_state
->unknown_key
= true;
4126 v_state
->success
= false;
4127 return 1; /* terminate. */
4130 static void validate_panic(const char *const why
)
4132 DEBUG(0,("validating cache: would panic %s\n", why
));
4133 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4137 static int wbcache_update_centry_fn(TDB_CONTEXT
*tdb
,
4145 if (is_non_centry_key(key
)) {
4149 if (data
.dptr
== NULL
|| data
.dsize
== 0) {
4150 if (tdb_delete(tdb
, key
) < 0) {
4151 DEBUG(0, ("tdb_delete for [%s] failed!\n",
4157 /* add timeout to blob (uint64_t) */
4158 blob
.dsize
= data
.dsize
+ 8;
4160 blob
.dptr
= SMB_XMALLOC_ARRAY(uint8_t, blob
.dsize
);
4161 if (blob
.dptr
== NULL
) {
4164 memset(blob
.dptr
, 0, blob
.dsize
);
4166 /* copy status and seqnum */
4167 memcpy(blob
.dptr
, data
.dptr
, 8);
4170 ctimeout
= lp_winbind_cache_time() + time(NULL
);
4171 SBVAL(blob
.dptr
, 8, ctimeout
);
4174 memcpy(blob
.dptr
+ 16, data
.dptr
+ 8, data
.dsize
- 8);
4176 if (tdb_store(tdb
, key
, blob
, TDB_REPLACE
) < 0) {
4177 DEBUG(0, ("tdb_store to update [%s] failed!\n",
4179 SAFE_FREE(blob
.dptr
);
4183 SAFE_FREE(blob
.dptr
);
4187 static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT
*tdb
)
4191 DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
4193 rc
= tdb_traverse(tdb
, wbcache_update_centry_fn
, NULL
);
4201 /***********************************************************************
4202 Try and validate every entry in the winbindd cache. If we fail here,
4203 delete the cache tdb and return non-zero.
4204 ***********************************************************************/
4206 int winbindd_validate_cache(void)
4209 const char *tdb_path
= state_path("winbindd_cache.tdb");
4210 TDB_CONTEXT
*tdb
= NULL
;
4214 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4215 smb_panic_fn
= validate_panic
;
4217 tdb
= tdb_open_log(tdb_path
,
4218 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
4219 TDB_INCOMPATIBLE_HASH
|
4220 ( lp_winbind_offline_logon()
4222 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
4226 DEBUG(0, ("winbindd_validate_cache: "
4227 "error opening/initializing tdb\n"));
4231 /* Version check and upgrade code. */
4232 if (!tdb_fetch_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers_id
)) {
4233 DEBUG(10, ("Fresh database\n"));
4234 tdb_store_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
);
4235 vers_id
= WINBINDD_CACHE_VERSION
;
4238 if (vers_id
!= WINBINDD_CACHE_VERSION
) {
4239 if (vers_id
== WINBINDD_CACHE_VER1
) {
4240 ok
= wbcache_upgrade_v1_to_v2(tdb
);
4242 DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
4247 tdb_store_uint32(tdb
,
4248 WINBINDD_CACHE_VERSION_KEYSTR
,
4249 WINBINDD_CACHE_VERSION
);
4250 vers_id
= WINBINDD_CACHE_VER2
;
4256 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
4259 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4260 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
4265 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4266 smb_panic_fn
= smb_panic
;
4270 /***********************************************************************
4271 Try and validate every entry in the winbindd cache.
4272 ***********************************************************************/
4274 int winbindd_validate_cache_nobackup(void)
4277 const char *tdb_path
= state_path("winbindd_cache.tdb");
4279 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4280 smb_panic_fn
= validate_panic
;
4283 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
4284 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
4286 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
4290 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4294 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4296 smb_panic_fn
= smb_panic
;
4300 bool winbindd_cache_validate_and_initialize(void)
4302 close_winbindd_cache();
4304 if (lp_winbind_offline_logon()) {
4305 if (winbindd_validate_cache() < 0) {
4306 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4307 "could be restored.\n"));
4311 return initialize_winbindd_cache();
4314 /*********************************************************************
4315 ********************************************************************/
4317 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
4318 struct winbindd_tdc_domain
**domains
,
4319 size_t *num_domains
)
4321 struct winbindd_tdc_domain
*list
= NULL
;
4324 bool set_only
= false;
4326 /* don't allow duplicates */
4331 for ( i
=0; i
< (*num_domains
); i
++ ) {
4332 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
4333 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4344 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, 1 );
4347 list
= talloc_realloc( *domains
, *domains
,
4348 struct winbindd_tdc_domain
,
4353 ZERO_STRUCT( list
[idx
] );
4359 list
[idx
].domain_name
= talloc_strdup(list
, new_dom
->name
);
4360 if (list
[idx
].domain_name
== NULL
) {
4363 if (new_dom
->alt_name
!= NULL
) {
4364 list
[idx
].dns_name
= talloc_strdup(list
, new_dom
->alt_name
);
4365 if (list
[idx
].dns_name
== NULL
) {
4370 if ( !is_null_sid( &new_dom
->sid
) ) {
4371 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
4373 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
4376 if ( new_dom
->domain_flags
!= 0x0 )
4377 list
[idx
].trust_flags
= new_dom
->domain_flags
;
4379 if ( new_dom
->domain_type
!= 0x0 )
4380 list
[idx
].trust_type
= new_dom
->domain_type
;
4382 if ( new_dom
->domain_trust_attribs
!= 0x0 )
4383 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
4387 *num_domains
= idx
+ 1;
4393 /*********************************************************************
4394 ********************************************************************/
4396 static TDB_DATA
make_tdc_key( const char *domain_name
)
4398 char *keystr
= NULL
;
4399 TDB_DATA key
= { NULL
, 0 };
4401 if ( !domain_name
) {
4402 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4406 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
4409 key
= string_term_tdb_data(keystr
);
4414 /*********************************************************************
4415 ********************************************************************/
4417 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
4419 unsigned char **buf
)
4421 unsigned char *buffer
= NULL
;
4426 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4434 /* Store the number of array items first */
4435 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
4438 /* now pack each domain trust record */
4439 for ( i
=0; i
<num_domains
; i
++ ) {
4444 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4445 domains
[i
].domain_name
,
4446 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
4449 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
4450 domains
[i
].domain_name
,
4451 domains
[i
].dns_name
? domains
[i
].dns_name
: "",
4452 sid_to_fstring(tmp
, &domains
[i
].sid
),
4453 domains
[i
].trust_flags
,
4454 domains
[i
].trust_attribs
,
4455 domains
[i
].trust_type
);
4458 if ( buflen
< len
) {
4460 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
4461 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4475 /*********************************************************************
4476 ********************************************************************/
4478 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
4479 struct winbindd_tdc_domain
**domains
)
4481 fstring domain_name
, dns_name
, sid_string
;
4482 uint32 type
, attribs
, flags
;
4486 struct winbindd_tdc_domain
*list
= NULL
;
4488 /* get the number of domains */
4489 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
4491 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4495 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, num_domains
);
4497 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4501 for ( i
=0; i
<num_domains
; i
++ ) {
4504 this_len
= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
4512 if ( this_len
== -1 ) {
4513 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4514 TALLOC_FREE( list
);
4519 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4520 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4521 domain_name
, dns_name
, sid_string
,
4522 flags
, attribs
, type
));
4524 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
4525 list
[i
].dns_name
= NULL
;
4526 if (dns_name
[0] != '\0') {
4527 list
[i
].dns_name
= talloc_strdup(list
, dns_name
);
4529 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
4530 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4533 list
[i
].trust_flags
= flags
;
4534 list
[i
].trust_attribs
= attribs
;
4535 list
[i
].trust_type
= type
;
4543 /*********************************************************************
4544 ********************************************************************/
4546 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
4548 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4549 TDB_DATA data
= { NULL
, 0 };
4555 /* See if we were asked to delete the cache entry */
4558 ret
= tdb_delete( wcache
->tdb
, key
);
4562 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4569 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4572 SAFE_FREE( data
.dptr
);
4573 SAFE_FREE( key
.dptr
);
4575 return ( ret
== 0 );
4578 /*********************************************************************
4579 ********************************************************************/
4581 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4583 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4584 TDB_DATA data
= { NULL
, 0 };
4592 data
= tdb_fetch_compat( wcache
->tdb
, key
);
4594 SAFE_FREE( key
.dptr
);
4599 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4601 SAFE_FREE( data
.dptr
);
4609 /*********************************************************************
4610 ********************************************************************/
4612 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4614 struct winbindd_tdc_domain
*dom_list
= NULL
;
4615 size_t num_domains
= 0;
4618 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4619 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4620 domain
->name
, domain
->alt_name
,
4621 sid_string_dbg(&domain
->sid
),
4622 domain
->domain_flags
,
4623 domain
->domain_trust_attribs
,
4624 domain
->domain_type
));
4626 if ( !init_wcache() ) {
4630 /* fetch the list */
4632 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4634 /* add the new domain */
4636 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4640 /* pack the domain */
4642 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4650 TALLOC_FREE( dom_list
);
4655 static struct winbindd_tdc_domain
*wcache_tdc_dup_domain(
4656 TALLOC_CTX
*mem_ctx
, const struct winbindd_tdc_domain
*src
)
4658 struct winbindd_tdc_domain
*dst
;
4660 dst
= talloc(mem_ctx
, struct winbindd_tdc_domain
);
4664 dst
->domain_name
= talloc_strdup(dst
, src
->domain_name
);
4665 if (dst
->domain_name
== NULL
) {
4669 dst
->dns_name
= NULL
;
4670 if (src
->dns_name
!= NULL
) {
4671 dst
->dns_name
= talloc_strdup(dst
, src
->dns_name
);
4672 if (dst
->dns_name
== NULL
) {
4677 sid_copy(&dst
->sid
, &src
->sid
);
4678 dst
->trust_flags
= src
->trust_flags
;
4679 dst
->trust_type
= src
->trust_type
;
4680 dst
->trust_attribs
= src
->trust_attribs
;
4687 /*********************************************************************
4688 ********************************************************************/
4690 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4692 struct winbindd_tdc_domain
*dom_list
= NULL
;
4693 size_t num_domains
= 0;
4695 struct winbindd_tdc_domain
*d
= NULL
;
4697 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4699 if ( !init_wcache() ) {
4703 /* fetch the list */
4705 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4707 for ( i
=0; i
<num_domains
; i
++ ) {
4708 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4709 strequal(name
, dom_list
[i
].dns_name
) )
4711 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4714 d
= wcache_tdc_dup_domain(ctx
, &dom_list
[i
]);
4719 TALLOC_FREE( dom_list
);
4724 /*********************************************************************
4725 ********************************************************************/
4727 struct winbindd_tdc_domain
*
4728 wcache_tdc_fetch_domainbysid(TALLOC_CTX
*ctx
,
4729 const struct dom_sid
*sid
)
4731 struct winbindd_tdc_domain
*dom_list
= NULL
;
4732 size_t num_domains
= 0;
4734 struct winbindd_tdc_domain
*d
= NULL
;
4736 DEBUG(10,("wcache_tdc_fetch_domainbysid: Searching for domain %s\n",
4737 sid_string_dbg(sid
)));
4739 if (!init_wcache()) {
4743 /* fetch the list */
4745 wcache_tdc_fetch_list(&dom_list
, &num_domains
);
4747 for (i
= 0; i
<num_domains
; i
++) {
4748 if (dom_sid_equal(sid
, &(dom_list
[i
].sid
))) {
4749 DEBUG(10, ("wcache_tdc_fetch_domainbysid: "
4750 "Found domain %s for SID %s\n",
4751 dom_list
[i
].domain_name
,
4752 sid_string_dbg(sid
)));
4754 d
= wcache_tdc_dup_domain(ctx
, &dom_list
[i
]);
4759 TALLOC_FREE(dom_list
);
4765 /*********************************************************************
4766 ********************************************************************/
4768 void wcache_tdc_clear( void )
4770 if ( !init_wcache() )
4773 wcache_tdc_store_list( NULL
, 0 );
4779 /*********************************************************************
4780 ********************************************************************/
4782 static void wcache_save_user_pwinfo(struct winbindd_domain
*domain
,
4784 const struct dom_sid
*user_sid
,
4785 const char *homedir
,
4790 struct cache_entry
*centry
;
4793 if ( (centry
= centry_start(domain
, status
)) == NULL
)
4796 centry_put_string( centry
, homedir
);
4797 centry_put_string( centry
, shell
);
4798 centry_put_string( centry
, gecos
);
4799 centry_put_uint32( centry
, gid
);
4801 centry_end(centry
, "NSS/PWINFO/%s", sid_to_fstring(tmp
, user_sid
) );
4803 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid
) ));
4805 centry_free(centry
);
4810 NTSTATUS
nss_get_info_cached( struct winbindd_domain
*domain
,
4811 const struct dom_sid
*user_sid
,
4813 const char **homedir
, const char **shell
,
4814 const char **gecos
, gid_t
*p_gid
)
4816 struct winbind_cache
*cache
= get_cache(domain
);
4817 struct cache_entry
*centry
= NULL
;
4824 centry
= wcache_fetch(cache
, domain
, "NSS/PWINFO/%s",
4825 sid_to_fstring(tmp
, user_sid
));
4830 *homedir
= centry_string( centry
, ctx
);
4831 *shell
= centry_string( centry
, ctx
);
4832 *gecos
= centry_string( centry
, ctx
);
4833 *p_gid
= centry_uint32( centry
);
4835 centry_free(centry
);
4837 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4838 sid_string_dbg(user_sid
)));
4840 return NT_STATUS_OK
;
4844 nt_status
= nss_get_info( domain
->name
, user_sid
, ctx
,
4845 homedir
, shell
, gecos
, p_gid
);
4847 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status
)));
4849 if ( NT_STATUS_IS_OK(nt_status
) ) {
4850 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir
));
4851 DEBUGADD(10, ("\tshell = '%s'\n", *shell
));
4852 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos
));
4853 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid
));
4855 wcache_save_user_pwinfo( domain
, nt_status
, user_sid
,
4856 *homedir
, *shell
, *gecos
, *p_gid
);
4859 if ( NT_STATUS_EQUAL( nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
4860 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4862 set_domain_offline( domain
);
4870 /* the cache backend methods are exposed via this structure */
4871 struct winbindd_methods cache_methods
= {
4889 static bool wcache_ndr_key(TALLOC_CTX
*mem_ctx
, const char *domain_name
,
4890 uint32_t opnum
, const DATA_BLOB
*req
,
4896 key
= talloc_asprintf(mem_ctx
, "NDR/%s/%d/", domain_name
, (int)opnum
);
4900 keylen
= talloc_get_size(key
) - 1;
4902 key
= talloc_realloc(mem_ctx
, key
, char, keylen
+ req
->length
);
4906 memcpy(key
+ keylen
, req
->data
, req
->length
);
4908 pkey
->dptr
= (uint8_t *)key
;
4909 pkey
->dsize
= talloc_get_size(key
);
4913 static bool wcache_opnum_cacheable(uint32_t opnum
)
4916 case NDR_WBINT_PING
:
4917 case NDR_WBINT_QUERYSEQUENCENUMBER
:
4918 case NDR_WBINT_ALLOCATEUID
:
4919 case NDR_WBINT_ALLOCATEGID
:
4920 case NDR_WBINT_CHECKMACHINEACCOUNT
:
4921 case NDR_WBINT_CHANGEMACHINEACCOUNT
:
4922 case NDR_WBINT_PINGDC
:
4928 bool wcache_fetch_ndr(TALLOC_CTX
*mem_ctx
, struct winbindd_domain
*domain
,
4929 uint32_t opnum
, const DATA_BLOB
*req
, DATA_BLOB
*resp
)
4934 if (!wcache_opnum_cacheable(opnum
) ||
4935 is_my_own_sam_domain(domain
) ||
4936 is_builtin_domain(domain
)) {
4940 if (wcache
->tdb
== NULL
) {
4944 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4947 data
= tdb_fetch_compat(wcache
->tdb
, key
);
4948 TALLOC_FREE(key
.dptr
);
4950 if (data
.dptr
== NULL
) {
4953 if (data
.dsize
< 12) {
4957 if (!is_domain_offline(domain
)) {
4958 uint32_t entry_seqnum
, dom_seqnum
, last_check
;
4959 uint64_t entry_timeout
;
4961 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
,
4965 entry_seqnum
= IVAL(data
.dptr
, 0);
4966 if (entry_seqnum
!= dom_seqnum
) {
4967 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4968 (int)entry_seqnum
));
4971 entry_timeout
= BVAL(data
.dptr
, 4);
4972 if (time(NULL
) > entry_timeout
) {
4973 DEBUG(10, ("Entry has timed out\n"));
4978 resp
->data
= (uint8_t *)talloc_memdup(mem_ctx
, data
.dptr
+ 12,
4980 if (resp
->data
== NULL
) {
4981 DEBUG(10, ("talloc failed\n"));
4984 resp
->length
= data
.dsize
- 12;
4988 SAFE_FREE(data
.dptr
);
4992 void wcache_store_ndr(struct winbindd_domain
*domain
, uint32_t opnum
,
4993 const DATA_BLOB
*req
, const DATA_BLOB
*resp
)
4996 uint32_t dom_seqnum
, last_check
;
4999 if (!wcache_opnum_cacheable(opnum
) ||
5000 is_my_own_sam_domain(domain
) ||
5001 is_builtin_domain(domain
)) {
5005 if (wcache
->tdb
== NULL
) {
5009 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
, &last_check
)) {
5010 DEBUG(10, ("could not fetch seqnum for domain %s\n",
5015 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
5019 timeout
= time(NULL
) + lp_winbind_cache_time();
5021 data
.dsize
= resp
->length
+ 12;
5022 data
.dptr
= talloc_array(key
.dptr
, uint8_t, data
.dsize
);
5023 if (data
.dptr
== NULL
) {
5027 SIVAL(data
.dptr
, 0, dom_seqnum
);
5028 SBVAL(data
.dptr
, 4, timeout
);
5029 memcpy(data
.dptr
+ 12, resp
->data
, resp
->length
);
5031 tdb_store(wcache
->tdb
, key
, data
, 0);
5034 TALLOC_FREE(key
.dptr
);