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 for (i
=0; i
<num_rids
; i
++) {
2129 struct cache_entry
*centry
;
2132 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2133 result
= NT_STATUS_INTERNAL_ERROR
;
2137 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2138 sid_to_fstring(tmp
, &sid
));
2140 (*types
)[i
] = SID_NAME_UNKNOWN
;
2141 (*names
)[i
] = talloc_strdup(*names
, "");
2145 (*types
)[i
] = SID_NAME_UNKNOWN
;
2146 (*names
)[i
] = talloc_strdup(*names
, "");
2148 if (NT_STATUS_IS_OK(centry
->status
)) {
2151 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2153 dom
= centry_string(centry
, mem_ctx
);
2154 if (*domain_name
== NULL
) {
2160 (*names
)[i
] = centry_string(centry
, *names
);
2162 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)) {
2163 have_unmapped
= true;
2166 /* something's definitely wrong */
2167 result
= centry
->status
;
2168 centry_free(centry
);
2172 centry_free(centry
);
2176 return NT_STATUS_NONE_MAPPED
;
2178 if (!have_unmapped
) {
2179 return NT_STATUS_OK
;
2181 return STATUS_SOME_UNMAPPED
;
2185 None of the queried rids has been found so save all negative entries
2187 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
2188 for (i
= 0; i
< num_rids
; i
++) {
2190 const char *name
= "";
2191 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
2192 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
2194 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2195 return NT_STATUS_INTERNAL_ERROR
;
2198 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2206 Some or all of the queried rids have been found.
2208 if (!NT_STATUS_IS_OK(result
) &&
2209 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
2213 refresh_sequence_number(domain
, false);
2215 for (i
=0; i
<num_rids
; i
++) {
2219 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2220 result
= NT_STATUS_INTERNAL_ERROR
;
2224 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
2225 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
2227 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2228 (*names
)[i
], (*types
)[i
]);
2234 TALLOC_FREE(*names
);
2235 TALLOC_FREE(*types
);
2239 NTSTATUS
wcache_query_user(struct winbindd_domain
*domain
,
2240 TALLOC_CTX
*mem_ctx
,
2241 const struct dom_sid
*user_sid
,
2242 struct wbint_userinfo
*info
)
2244 struct winbind_cache
*cache
= get_cache(domain
);
2245 struct cache_entry
*centry
= NULL
;
2249 if (cache
->tdb
== NULL
) {
2250 return NT_STATUS_NOT_FOUND
;
2253 sid_string
= sid_string_tos(user_sid
);
2254 if (sid_string
== NULL
) {
2255 return NT_STATUS_NO_MEMORY
;
2258 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string
);
2259 TALLOC_FREE(sid_string
);
2260 if (centry
== NULL
) {
2261 return NT_STATUS_NOT_FOUND
;
2265 * If we have an access denied cache entry and a cached info3
2266 * in the samlogon cache then do a query. This will force the
2267 * rpc back end to return the info3 data.
2270 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
) &&
2271 netsamlogon_cache_have(user_sid
)) {
2272 DEBUG(10, ("query_user: cached access denied and have cached "
2274 domain
->last_status
= NT_STATUS_OK
;
2275 centry_free(centry
);
2276 return NT_STATUS_NOT_FOUND
;
2279 /* if status is not ok then this is a negative hit
2280 and the rest of the data doesn't matter */
2281 status
= centry
->status
;
2282 if (NT_STATUS_IS_OK(status
)) {
2283 info
->acct_name
= centry_string(centry
, mem_ctx
);
2284 info
->full_name
= centry_string(centry
, mem_ctx
);
2285 info
->homedir
= centry_string(centry
, mem_ctx
);
2286 info
->shell
= centry_string(centry
, mem_ctx
);
2287 info
->primary_gid
= centry_uint32(centry
);
2288 centry_sid(centry
, &info
->user_sid
);
2289 centry_sid(centry
, &info
->group_sid
);
2292 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2293 "%s\n", domain
->name
, nt_errstr(status
) ));
2295 centry_free(centry
);
2299 /* Lookup user information from a rid */
2300 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
2301 TALLOC_CTX
*mem_ctx
,
2302 const struct dom_sid
*user_sid
,
2303 struct wbint_userinfo
*info
)
2308 old_status
= domain
->online
;
2309 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2310 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2316 /* Return status value returned by seq number check */
2318 if (!NT_STATUS_IS_OK(domain
->last_status
))
2319 return domain
->last_status
;
2321 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2324 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
2326 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2327 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2328 if (!domain
->internal
&& old_status
) {
2329 set_domain_offline(domain
);
2331 if (!domain
->internal
&&
2334 NTSTATUS cache_status
;
2335 cache_status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2336 return cache_status
;
2340 refresh_sequence_number(domain
, false);
2341 if (!NT_STATUS_IS_OK(status
)) {
2344 wcache_save_user(domain
, status
, info
);
2349 NTSTATUS
wcache_lookup_usergroups(struct winbindd_domain
*domain
,
2350 TALLOC_CTX
*mem_ctx
,
2351 const struct dom_sid
*user_sid
,
2352 uint32_t *pnum_sids
,
2353 struct dom_sid
**psids
)
2355 struct winbind_cache
*cache
= get_cache(domain
);
2356 struct cache_entry
*centry
= NULL
;
2358 uint32_t i
, num_sids
;
2359 struct dom_sid
*sids
;
2362 if (cache
->tdb
== NULL
) {
2363 return NT_STATUS_NOT_FOUND
;
2366 centry
= wcache_fetch(cache
, domain
, "UG/%s",
2367 sid_to_fstring(sid_string
, user_sid
));
2368 if (centry
== NULL
) {
2369 return NT_STATUS_NOT_FOUND
;
2372 /* If we have an access denied cache entry and a cached info3 in the
2373 samlogon cache then do a query. This will force the rpc back end
2374 to return the info3 data. */
2376 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)
2377 && netsamlogon_cache_have(user_sid
)) {
2378 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2380 domain
->last_status
= NT_STATUS_OK
;
2381 centry_free(centry
);
2382 return NT_STATUS_NOT_FOUND
;
2385 num_sids
= centry_uint32(centry
);
2386 sids
= talloc_array(mem_ctx
, struct dom_sid
, num_sids
);
2388 centry_free(centry
);
2389 return NT_STATUS_NO_MEMORY
;
2392 for (i
=0; i
<num_sids
; i
++) {
2393 centry_sid(centry
, &sids
[i
]);
2396 status
= centry
->status
;
2398 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2399 "status: %s\n", domain
->name
, nt_errstr(status
)));
2401 centry_free(centry
);
2403 *pnum_sids
= num_sids
;
2408 /* Lookup groups a user is a member of. */
2409 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
2410 TALLOC_CTX
*mem_ctx
,
2411 const struct dom_sid
*user_sid
,
2412 uint32
*num_groups
, struct dom_sid
**user_gids
)
2414 struct cache_entry
*centry
= NULL
;
2420 old_status
= domain
->online
;
2421 status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2422 num_groups
, user_gids
);
2423 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2428 (*user_gids
) = NULL
;
2430 /* Return status value returned by seq number check */
2432 if (!NT_STATUS_IS_OK(domain
->last_status
))
2433 return domain
->last_status
;
2435 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2438 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
2440 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2441 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2442 if (!domain
->internal
&& old_status
) {
2443 set_domain_offline(domain
);
2445 if (!domain
->internal
&&
2448 NTSTATUS cache_status
;
2449 cache_status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2450 num_groups
, user_gids
);
2451 return cache_status
;
2454 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
2458 refresh_sequence_number(domain
, false);
2459 if (!NT_STATUS_IS_OK(status
)) {
2462 centry
= centry_start(domain
, status
);
2466 centry_put_uint32(centry
, *num_groups
);
2467 for (i
=0; i
<(*num_groups
); i
++) {
2468 centry_put_sid(centry
, &(*user_gids
)[i
]);
2471 centry_end(centry
, "UG/%s", sid_to_fstring(sid_string
, user_sid
));
2472 centry_free(centry
);
2478 static char *wcache_make_sidlist(TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2479 const struct dom_sid
*sids
)
2484 sidlist
= talloc_strdup(mem_ctx
, "");
2485 if (sidlist
== NULL
) {
2488 for (i
=0; i
<num_sids
; i
++) {
2490 sidlist
= talloc_asprintf_append_buffer(
2491 sidlist
, "/%s", sid_to_fstring(tmp
, &sids
[i
]));
2492 if (sidlist
== NULL
) {
2499 NTSTATUS
wcache_lookup_useraliases(struct winbindd_domain
*domain
,
2500 TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2501 const struct dom_sid
*sids
,
2502 uint32_t *pnum_aliases
, uint32_t **paliases
)
2504 struct winbind_cache
*cache
= get_cache(domain
);
2505 struct cache_entry
*centry
= NULL
;
2506 uint32_t num_aliases
;
2512 if (cache
->tdb
== NULL
) {
2513 return NT_STATUS_NOT_FOUND
;
2516 if (num_sids
== 0) {
2519 return NT_STATUS_OK
;
2522 /* We need to cache indexed by the whole list of SIDs, the aliases
2523 * resulting might come from any of the SIDs. */
2525 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2526 if (sidlist
== NULL
) {
2527 return NT_STATUS_NO_MEMORY
;
2530 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2531 TALLOC_FREE(sidlist
);
2532 if (centry
== NULL
) {
2533 return NT_STATUS_NOT_FOUND
;
2536 num_aliases
= centry_uint32(centry
);
2537 aliases
= talloc_array(mem_ctx
, uint32_t, num_aliases
);
2538 if (aliases
== NULL
) {
2539 centry_free(centry
);
2540 return NT_STATUS_NO_MEMORY
;
2543 for (i
=0; i
<num_aliases
; i
++) {
2544 aliases
[i
] = centry_uint32(centry
);
2547 status
= centry
->status
;
2549 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2550 "status %s\n", domain
->name
, nt_errstr(status
)));
2552 centry_free(centry
);
2554 *pnum_aliases
= num_aliases
;
2555 *paliases
= aliases
;
2560 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
2561 TALLOC_CTX
*mem_ctx
,
2562 uint32 num_sids
, const struct dom_sid
*sids
,
2563 uint32
*num_aliases
, uint32
**alias_rids
)
2565 struct cache_entry
*centry
= NULL
;
2571 old_status
= domain
->online
;
2572 status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
2573 num_aliases
, alias_rids
);
2574 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2579 (*alias_rids
) = NULL
;
2581 if (!NT_STATUS_IS_OK(domain
->last_status
))
2582 return domain
->last_status
;
2584 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2585 "for domain %s\n", domain
->name
));
2587 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2588 if (sidlist
== NULL
) {
2589 return NT_STATUS_NO_MEMORY
;
2592 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2594 num_aliases
, alias_rids
);
2596 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2597 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2598 if (!domain
->internal
&& old_status
) {
2599 set_domain_offline(domain
);
2601 if (!domain
->internal
&&
2604 NTSTATUS cache_status
;
2605 cache_status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
,
2606 sids
, num_aliases
, alias_rids
);
2607 return cache_status
;
2611 refresh_sequence_number(domain
, false);
2612 if (!NT_STATUS_IS_OK(status
)) {
2615 centry
= centry_start(domain
, status
);
2618 centry_put_uint32(centry
, *num_aliases
);
2619 for (i
=0; i
<(*num_aliases
); i
++)
2620 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2621 centry_end(centry
, "UA%s", sidlist
);
2622 centry_free(centry
);
2628 NTSTATUS
wcache_lookup_groupmem(struct winbindd_domain
*domain
,
2629 TALLOC_CTX
*mem_ctx
,
2630 const struct dom_sid
*group_sid
,
2631 uint32_t *num_names
,
2632 struct dom_sid
**sid_mem
, char ***names
,
2633 uint32_t **name_types
)
2635 struct winbind_cache
*cache
= get_cache(domain
);
2636 struct cache_entry
*centry
= NULL
;
2641 if (cache
->tdb
== NULL
) {
2642 return NT_STATUS_NOT_FOUND
;
2645 sid_string
= sid_string_tos(group_sid
);
2646 if (sid_string
== NULL
) {
2647 return NT_STATUS_NO_MEMORY
;
2650 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_string
);
2651 TALLOC_FREE(sid_string
);
2652 if (centry
== NULL
) {
2653 return NT_STATUS_NOT_FOUND
;
2660 *num_names
= centry_uint32(centry
);
2661 if (*num_names
== 0) {
2662 centry_free(centry
);
2663 return NT_STATUS_OK
;
2666 *sid_mem
= talloc_array(mem_ctx
, struct dom_sid
, *num_names
);
2667 *names
= talloc_array(mem_ctx
, char *, *num_names
);
2668 *name_types
= talloc_array(mem_ctx
, uint32
, *num_names
);
2670 if ((*sid_mem
== NULL
) || (*names
== NULL
) || (*name_types
== NULL
)) {
2671 TALLOC_FREE(*sid_mem
);
2672 TALLOC_FREE(*names
);
2673 TALLOC_FREE(*name_types
);
2674 centry_free(centry
);
2675 return NT_STATUS_NO_MEMORY
;
2678 for (i
=0; i
<(*num_names
); i
++) {
2679 centry_sid(centry
, &(*sid_mem
)[i
]);
2680 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2681 (*name_types
)[i
] = centry_uint32(centry
);
2684 status
= centry
->status
;
2686 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2687 "status: %s\n", domain
->name
, nt_errstr(status
)));
2689 centry_free(centry
);
2693 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
2694 TALLOC_CTX
*mem_ctx
,
2695 const struct dom_sid
*group_sid
,
2696 enum lsa_SidType type
,
2698 struct dom_sid
**sid_mem
, char ***names
,
2699 uint32
**name_types
)
2701 struct cache_entry
*centry
= NULL
;
2707 old_status
= domain
->online
;
2708 status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2709 sid_mem
, names
, name_types
);
2710 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2717 (*name_types
) = NULL
;
2719 /* Return status value returned by seq number check */
2721 if (!NT_STATUS_IS_OK(domain
->last_status
))
2722 return domain
->last_status
;
2724 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2727 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
,
2729 sid_mem
, names
, name_types
);
2731 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2732 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2733 if (!domain
->internal
&& old_status
) {
2734 set_domain_offline(domain
);
2736 if (!domain
->internal
&&
2739 NTSTATUS cache_status
;
2740 cache_status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
,
2741 num_names
, sid_mem
, names
,
2743 return cache_status
;
2747 refresh_sequence_number(domain
, false);
2748 if (!NT_STATUS_IS_OK(status
)) {
2751 centry
= centry_start(domain
, status
);
2754 centry_put_uint32(centry
, *num_names
);
2755 for (i
=0; i
<(*num_names
); i
++) {
2756 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2757 centry_put_string(centry
, (*names
)[i
]);
2758 centry_put_uint32(centry
, (*name_types
)[i
]);
2760 centry_end(centry
, "GM/%s", sid_to_fstring(sid_string
, group_sid
));
2761 centry_free(centry
);
2767 /* find the sequence number for a domain */
2768 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
2770 refresh_sequence_number(domain
, false);
2772 *seq
= domain
->sequence_number
;
2774 return NT_STATUS_OK
;
2777 /* enumerate trusted domains
2778 * (we need to have the list of trustdoms in the cache when we go offline) -
2780 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
2781 TALLOC_CTX
*mem_ctx
,
2782 struct netr_DomainTrustList
*trusts
)
2785 struct winbind_cache
*cache
;
2786 struct winbindd_tdc_domain
*dom_list
= NULL
;
2787 size_t num_domains
= 0;
2788 bool retval
= false;
2792 old_status
= domain
->online
;
2794 trusts
->array
= NULL
;
2796 cache
= get_cache(domain
);
2797 if (!cache
|| !cache
->tdb
) {
2801 if (domain
->online
) {
2805 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2806 if (!retval
|| !num_domains
|| !dom_list
) {
2807 TALLOC_FREE(dom_list
);
2812 trusts
->array
= talloc_zero_array(mem_ctx
, struct netr_DomainTrust
, num_domains
);
2813 if (!trusts
->array
) {
2814 TALLOC_FREE(dom_list
);
2815 return NT_STATUS_NO_MEMORY
;
2818 for (i
= 0; i
< num_domains
; i
++) {
2819 struct netr_DomainTrust
*trust
;
2820 struct dom_sid
*sid
;
2821 struct winbindd_domain
*dom
;
2823 dom
= find_domain_from_name_noinit(dom_list
[i
].domain_name
);
2824 if (dom
&& dom
->internal
) {
2828 trust
= &trusts
->array
[trusts
->count
];
2829 trust
->netbios_name
= talloc_strdup(trusts
->array
, dom_list
[i
].domain_name
);
2830 trust
->dns_name
= talloc_strdup(trusts
->array
, dom_list
[i
].dns_name
);
2831 sid
= talloc(trusts
->array
, struct dom_sid
);
2832 if (!trust
->netbios_name
|| !trust
->dns_name
||
2834 TALLOC_FREE(dom_list
);
2835 TALLOC_FREE(trusts
->array
);
2836 return NT_STATUS_NO_MEMORY
;
2839 trust
->trust_flags
= dom_list
[i
].trust_flags
;
2840 trust
->trust_attributes
= dom_list
[i
].trust_attribs
;
2841 trust
->trust_type
= dom_list
[i
].trust_type
;
2842 sid_copy(sid
, &dom_list
[i
].sid
);
2847 TALLOC_FREE(dom_list
);
2848 return NT_STATUS_OK
;
2851 /* Return status value returned by seq number check */
2853 if (!NT_STATUS_IS_OK(domain
->last_status
))
2854 return domain
->last_status
;
2856 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2859 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, trusts
);
2861 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2862 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2863 if (!domain
->internal
&& old_status
) {
2864 set_domain_offline(domain
);
2866 if (!domain
->internal
&&
2869 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2870 if (retval
&& num_domains
&& dom_list
) {
2871 TALLOC_FREE(trusts
->array
);
2873 goto do_fetch_cache
;
2877 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2878 * so that the generic centry handling still applies correctly -
2881 if (!NT_STATUS_IS_ERR(status
)) {
2882 status
= NT_STATUS_OK
;
2887 /* get lockout policy */
2888 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
2889 TALLOC_CTX
*mem_ctx
,
2890 struct samr_DomInfo12
*policy
)
2892 struct winbind_cache
*cache
= get_cache(domain
);
2893 struct cache_entry
*centry
= NULL
;
2897 old_status
= domain
->online
;
2901 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2907 policy
->lockout_duration
= centry_nttime(centry
);
2908 policy
->lockout_window
= centry_nttime(centry
);
2909 policy
->lockout_threshold
= centry_uint16(centry
);
2911 status
= centry
->status
;
2913 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2914 domain
->name
, nt_errstr(status
) ));
2916 centry_free(centry
);
2920 ZERO_STRUCTP(policy
);
2922 /* Return status value returned by seq number check */
2924 if (!NT_STATUS_IS_OK(domain
->last_status
))
2925 return domain
->last_status
;
2927 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2930 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2932 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2933 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2934 if (!domain
->internal
&& old_status
) {
2935 set_domain_offline(domain
);
2938 !domain
->internal
&&
2941 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2943 goto do_fetch_cache
;
2948 refresh_sequence_number(domain
, false);
2949 if (!NT_STATUS_IS_OK(status
)) {
2952 wcache_save_lockout_policy(domain
, status
, policy
);
2957 /* get password policy */
2958 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
2959 TALLOC_CTX
*mem_ctx
,
2960 struct samr_DomInfo1
*policy
)
2962 struct winbind_cache
*cache
= get_cache(domain
);
2963 struct cache_entry
*centry
= NULL
;
2967 old_status
= domain
->online
;
2971 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2977 policy
->min_password_length
= centry_uint16(centry
);
2978 policy
->password_history_length
= centry_uint16(centry
);
2979 policy
->password_properties
= centry_uint32(centry
);
2980 policy
->max_password_age
= centry_nttime(centry
);
2981 policy
->min_password_age
= centry_nttime(centry
);
2983 status
= centry
->status
;
2985 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2986 domain
->name
, nt_errstr(status
) ));
2988 centry_free(centry
);
2992 ZERO_STRUCTP(policy
);
2994 /* Return status value returned by seq number check */
2996 if (!NT_STATUS_IS_OK(domain
->last_status
))
2997 return domain
->last_status
;
2999 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
3002 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
3004 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
3005 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
3006 if (!domain
->internal
&& old_status
) {
3007 set_domain_offline(domain
);
3010 !domain
->internal
&&
3013 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
3015 goto do_fetch_cache
;
3020 refresh_sequence_number(domain
, false);
3021 if (!NT_STATUS_IS_OK(status
)) {
3024 wcache_save_password_policy(domain
, status
, policy
);
3030 /* Invalidate cached user and group lists coherently */
3032 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3035 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
3036 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
3037 tdb_delete(the_tdb
, kbuf
);
3042 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3044 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
3045 const struct dom_sid
*sid
)
3047 fstring key_str
, sid_string
;
3048 struct winbind_cache
*cache
;
3050 /* dont clear cached U/SID and UG/SID entries when we want to logon
3053 if (lp_winbind_offline_logon()) {
3060 cache
= get_cache(domain
);
3066 /* Clear U/SID cache entry */
3067 fstr_sprintf(key_str
, "U/%s", sid_to_fstring(sid_string
, sid
));
3068 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3069 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3071 /* Clear UG/SID cache entry */
3072 fstr_sprintf(key_str
, "UG/%s", sid_to_fstring(sid_string
, sid
));
3073 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3074 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3076 /* Samba/winbindd never needs this. */
3077 netsamlogon_clear_cached_user(sid
);
3080 bool wcache_invalidate_cache(void)
3082 struct winbindd_domain
*domain
;
3084 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3085 struct winbind_cache
*cache
= get_cache(domain
);
3087 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3088 "entries for %s\n", domain
->name
));
3091 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3100 bool wcache_invalidate_cache_noinit(void)
3102 struct winbindd_domain
*domain
;
3104 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3105 struct winbind_cache
*cache
;
3107 /* Skip uninitialized domains. */
3108 if (!domain
->initialized
&& !domain
->internal
) {
3112 cache
= get_cache(domain
);
3114 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3115 "entries for %s\n", domain
->name
));
3118 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3120 * Flushing cache has nothing to with domains.
3121 * return here if we successfully flushed once.
3122 * To avoid unnecessary traversing the cache.
3133 bool init_wcache(void)
3135 if (wcache
== NULL
) {
3136 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
3137 ZERO_STRUCTP(wcache
);
3140 if (wcache
->tdb
!= NULL
)
3143 /* when working offline we must not clear the cache on restart */
3144 wcache
->tdb
= tdb_open_log(state_path("winbindd_cache.tdb"),
3145 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3146 TDB_INCOMPATIBLE_HASH
|
3147 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3148 O_RDWR
|O_CREAT
, 0600);
3150 if (wcache
->tdb
== NULL
) {
3151 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3158 /************************************************************************
3159 This is called by the parent to initialize the cache file.
3160 We don't need sophisticated locking here as we know we're the
3162 ************************************************************************/
3164 bool initialize_winbindd_cache(void)
3166 bool cache_bad
= true;
3169 if (!init_wcache()) {
3170 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3174 /* Check version number. */
3175 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
3176 vers
== WINBINDD_CACHE_VERSION
) {
3181 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3182 "and re-creating with version number %d\n",
3183 WINBINDD_CACHE_VERSION
));
3185 tdb_close(wcache
->tdb
);
3188 if (unlink(state_path("winbindd_cache.tdb")) == -1) {
3189 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3190 state_path("winbindd_cache.tdb"),
3194 if (!init_wcache()) {
3195 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3196 "init_wcache failed.\n"));
3200 /* Write the version. */
3201 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
3202 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3203 tdb_errorstr_compat(wcache
->tdb
) ));
3208 tdb_close(wcache
->tdb
);
3213 void close_winbindd_cache(void)
3219 tdb_close(wcache
->tdb
);
3224 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*sid
,
3225 char **domain_name
, char **name
,
3226 enum lsa_SidType
*type
)
3228 struct winbindd_domain
*domain
;
3231 domain
= find_lookup_domain_from_sid(sid
);
3232 if (domain
== NULL
) {
3235 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
3237 return NT_STATUS_IS_OK(status
);
3240 bool lookup_cached_name(const char *domain_name
,
3242 struct dom_sid
*sid
,
3243 enum lsa_SidType
*type
)
3245 struct winbindd_domain
*domain
;
3247 bool original_online_state
;
3249 domain
= find_lookup_domain_from_name(domain_name
);
3250 if (domain
== NULL
) {
3254 /* If we are doing a cached logon, temporarily set the domain
3255 offline so the cache won't expire the entry */
3257 original_online_state
= domain
->online
;
3258 domain
->online
= false;
3259 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
3260 domain
->online
= original_online_state
;
3262 return NT_STATUS_IS_OK(status
);
3265 void cache_name2sid(struct winbindd_domain
*domain
,
3266 const char *domain_name
, const char *name
,
3267 enum lsa_SidType type
, const struct dom_sid
*sid
)
3269 refresh_sequence_number(domain
, false);
3270 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
3275 * The original idea that this cache only contains centries has
3276 * been blurred - now other stuff gets put in here. Ensure we
3277 * ignore these things on cleanup.
3280 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
3281 TDB_DATA dbuf
, void *state
)
3283 struct cache_entry
*centry
;
3285 if (is_non_centry_key(kbuf
)) {
3289 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
3294 if (!NT_STATUS_IS_OK(centry
->status
)) {
3295 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
3296 tdb_delete(the_tdb
, kbuf
);
3299 centry_free(centry
);
3303 /* flush the cache */
3304 void wcache_flush_cache(void)
3309 tdb_close(wcache
->tdb
);
3312 if (!winbindd_use_cache()) {
3316 /* when working offline we must not clear the cache on restart */
3317 wcache
->tdb
= tdb_open_log(state_path("winbindd_cache.tdb"),
3318 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3319 TDB_INCOMPATIBLE_HASH
|
3320 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3321 O_RDWR
|O_CREAT
, 0600);
3324 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3328 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
3330 DEBUG(10,("wcache_flush_cache success\n"));
3333 /* Count cached creds */
3335 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3338 int *cred_count
= (int*)state
;
3340 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3346 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
3348 struct winbind_cache
*cache
= get_cache(domain
);
3353 return NT_STATUS_INTERNAL_DB_ERROR
;
3356 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
3358 return NT_STATUS_OK
;
3362 struct cred_list
*prev
, *next
;
3367 static struct cred_list
*wcache_cred_list
;
3369 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3372 struct cred_list
*cred
;
3374 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3376 cred
= SMB_MALLOC_P(struct cred_list
);
3378 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3384 /* save a copy of the key */
3386 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
3387 DLIST_ADD(wcache_cred_list
, cred
);
3393 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
3395 struct winbind_cache
*cache
= get_cache(domain
);
3398 struct cred_list
*cred
, *oldest
= NULL
;
3401 return NT_STATUS_INTERNAL_DB_ERROR
;
3404 /* we possibly already have an entry */
3405 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
3407 fstring key_str
, tmp
;
3409 DEBUG(11,("we already have an entry, deleting that\n"));
3411 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
3413 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3415 return NT_STATUS_OK
;
3418 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
3420 return NT_STATUS_OK
;
3421 } else if ((ret
< 0) || (wcache_cred_list
== NULL
)) {
3422 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3425 ZERO_STRUCTP(oldest
);
3427 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
3432 data
= tdb_fetch_compat(cache
->tdb
, string_tdb_data(cred
->name
));
3434 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3436 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3440 t
= IVAL(data
.dptr
, 0);
3441 SAFE_FREE(data
.dptr
);
3444 oldest
= SMB_MALLOC_P(struct cred_list
);
3445 if (oldest
== NULL
) {
3446 status
= NT_STATUS_NO_MEMORY
;
3450 fstrcpy(oldest
->name
, cred
->name
);
3451 oldest
->created
= t
;
3455 if (t
< oldest
->created
) {
3456 fstrcpy(oldest
->name
, cred
->name
);
3457 oldest
->created
= t
;
3461 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3462 status
= NT_STATUS_OK
;
3464 status
= NT_STATUS_UNSUCCESSFUL
;
3467 SAFE_FREE(wcache_cred_list
);
3473 /* Change the global online/offline state. */
3474 bool set_global_winbindd_state_offline(void)
3478 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3480 /* Only go offline if someone has created
3481 the key "WINBINDD_OFFLINE" in the cache tdb. */
3483 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3484 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3488 if (!lp_winbind_offline_logon()) {
3489 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3493 if (global_winbindd_offline_state
) {
3494 /* Already offline. */
3498 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
3500 if (!data
.dptr
|| data
.dsize
!= 4) {
3501 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3502 SAFE_FREE(data
.dptr
);
3505 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3506 global_winbindd_offline_state
= true;
3507 SAFE_FREE(data
.dptr
);
3512 void set_global_winbindd_state_online(void)
3514 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3516 if (!lp_winbind_offline_logon()) {
3517 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3521 if (!global_winbindd_offline_state
) {
3522 /* Already online. */
3525 global_winbindd_offline_state
= false;
3531 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3532 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3535 bool get_global_winbindd_state_offline(void)
3537 return global_winbindd_offline_state
;
3540 /***********************************************************************
3541 Validate functions for all possible cache tdb keys.
3542 ***********************************************************************/
3544 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3545 struct tdb_validation_status
*state
)
3547 struct cache_entry
*centry
;
3549 centry
= SMB_XMALLOC_P(struct cache_entry
);
3550 centry
->data
= (unsigned char *)memdup(data
.dptr
, data
.dsize
);
3551 if (!centry
->data
) {
3555 centry
->len
= data
.dsize
;
3558 if (centry
->len
< 16) {
3559 /* huh? corrupt cache? */
3560 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3561 "(len < 16) ?\n", kstr
));
3562 centry_free(centry
);
3563 state
->bad_entry
= true;
3564 state
->success
= false;
3568 centry
->status
= NT_STATUS(centry_uint32(centry
));
3569 centry
->sequence_number
= centry_uint32(centry
);
3570 centry
->timeout
= centry_uint64_t(centry
);
3574 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3575 struct tdb_validation_status
*state
)
3577 if (dbuf
.dsize
!= 8) {
3578 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3579 keystr
, (unsigned int)dbuf
.dsize
));
3580 state
->bad_entry
= true;
3586 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3587 struct tdb_validation_status
*state
)
3589 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3594 (void)centry_uint32(centry
);
3595 if (NT_STATUS_IS_OK(centry
->status
)) {
3597 (void)centry_sid(centry
, &sid
);
3600 centry_free(centry
);
3602 if (!(state
->success
)) {
3605 DEBUG(10,("validate_ns: %s ok\n", keystr
));
3609 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3610 struct tdb_validation_status
*state
)
3612 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3617 if (NT_STATUS_IS_OK(centry
->status
)) {
3618 (void)centry_uint32(centry
);
3619 (void)centry_string(centry
, mem_ctx
);
3620 (void)centry_string(centry
, mem_ctx
);
3623 centry_free(centry
);
3625 if (!(state
->success
)) {
3628 DEBUG(10,("validate_sn: %s ok\n", keystr
));
3632 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3633 struct tdb_validation_status
*state
)
3635 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3642 (void)centry_string(centry
, mem_ctx
);
3643 (void)centry_string(centry
, mem_ctx
);
3644 (void)centry_string(centry
, mem_ctx
);
3645 (void)centry_string(centry
, mem_ctx
);
3646 (void)centry_uint32(centry
);
3647 (void)centry_sid(centry
, &sid
);
3648 (void)centry_sid(centry
, &sid
);
3650 centry_free(centry
);
3652 if (!(state
->success
)) {
3655 DEBUG(10,("validate_u: %s ok\n", keystr
));
3659 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3660 struct tdb_validation_status
*state
)
3662 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3668 (void)centry_nttime(centry
);
3669 (void)centry_nttime(centry
);
3670 (void)centry_uint16(centry
);
3672 centry_free(centry
);
3674 if (!(state
->success
)) {
3677 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3681 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3682 struct tdb_validation_status
*state
)
3684 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3690 (void)centry_uint16(centry
);
3691 (void)centry_uint16(centry
);
3692 (void)centry_uint32(centry
);
3693 (void)centry_nttime(centry
);
3694 (void)centry_nttime(centry
);
3696 centry_free(centry
);
3698 if (!(state
->success
)) {
3701 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3705 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3706 struct tdb_validation_status
*state
)
3708 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3714 (void)centry_time(centry
);
3715 (void)centry_hash16(centry
, mem_ctx
);
3717 /* We only have 17 bytes more data in the salted cred case. */
3718 if (centry
->len
- centry
->ofs
== 17) {
3719 (void)centry_hash16(centry
, mem_ctx
);
3722 centry_free(centry
);
3724 if (!(state
->success
)) {
3727 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3731 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3732 struct tdb_validation_status
*state
)
3734 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3735 int32 num_entries
, i
;
3741 num_entries
= (int32
)centry_uint32(centry
);
3743 for (i
=0; i
< num_entries
; i
++) {
3745 (void)centry_string(centry
, mem_ctx
);
3746 (void)centry_string(centry
, mem_ctx
);
3747 (void)centry_string(centry
, mem_ctx
);
3748 (void)centry_string(centry
, mem_ctx
);
3749 (void)centry_sid(centry
, &sid
);
3750 (void)centry_sid(centry
, &sid
);
3753 centry_free(centry
);
3755 if (!(state
->success
)) {
3758 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3762 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3763 struct tdb_validation_status
*state
)
3765 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3766 int32 num_entries
, i
;
3772 num_entries
= centry_uint32(centry
);
3774 for (i
=0; i
< num_entries
; i
++) {
3775 (void)centry_string(centry
, mem_ctx
);
3776 (void)centry_string(centry
, mem_ctx
);
3777 (void)centry_uint32(centry
);
3780 centry_free(centry
);
3782 if (!(state
->success
)) {
3785 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3789 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3790 struct tdb_validation_status
*state
)
3792 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3793 int32 num_groups
, i
;
3799 num_groups
= centry_uint32(centry
);
3801 for (i
=0; i
< num_groups
; i
++) {
3803 centry_sid(centry
, &sid
);
3806 centry_free(centry
);
3808 if (!(state
->success
)) {
3811 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3815 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3816 struct tdb_validation_status
*state
)
3818 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3819 int32 num_aliases
, i
;
3825 num_aliases
= centry_uint32(centry
);
3827 for (i
=0; i
< num_aliases
; i
++) {
3828 (void)centry_uint32(centry
);
3831 centry_free(centry
);
3833 if (!(state
->success
)) {
3836 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3840 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3841 struct tdb_validation_status
*state
)
3843 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3850 num_names
= centry_uint32(centry
);
3852 for (i
=0; i
< num_names
; i
++) {
3854 centry_sid(centry
, &sid
);
3855 (void)centry_string(centry
, mem_ctx
);
3856 (void)centry_uint32(centry
);
3859 centry_free(centry
);
3861 if (!(state
->success
)) {
3864 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3868 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3869 struct tdb_validation_status
*state
)
3871 /* Can't say anything about this other than must be nonzero. */
3872 if (dbuf
.dsize
== 0) {
3873 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3875 state
->bad_entry
= true;
3876 state
->success
= false;
3880 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3884 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3885 struct tdb_validation_status
*state
)
3887 /* Can't say anything about this other than must be nonzero. */
3888 if (dbuf
.dsize
== 0) {
3889 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3891 state
->bad_entry
= true;
3892 state
->success
= false;
3896 DEBUG(10,("validate_de: %s ok\n", keystr
));
3900 static int validate_pwinfo(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3901 TDB_DATA dbuf
, struct tdb_validation_status
*state
)
3903 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3909 (void)centry_string(centry
, mem_ctx
);
3910 (void)centry_string(centry
, mem_ctx
);
3911 (void)centry_string(centry
, mem_ctx
);
3912 (void)centry_uint32(centry
);
3914 centry_free(centry
);
3916 if (!(state
->success
)) {
3919 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3923 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3925 struct tdb_validation_status
*state
)
3927 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3933 (void)centry_string( centry
, mem_ctx
);
3935 centry_free(centry
);
3937 if (!(state
->success
)) {
3940 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3944 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3946 struct tdb_validation_status
*state
)
3948 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3954 (void)centry_string( centry
, mem_ctx
);
3956 centry_free(centry
);
3958 if (!(state
->success
)) {
3961 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3965 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3967 struct tdb_validation_status
*state
)
3969 if (dbuf
.dsize
== 0) {
3970 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3971 "key %s (len ==0) ?\n", keystr
));
3972 state
->bad_entry
= true;
3973 state
->success
= false;
3977 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3978 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3982 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3983 struct tdb_validation_status
*state
)
3985 if (dbuf
.dsize
!= 4) {
3986 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3987 keystr
, (unsigned int)dbuf
.dsize
));
3988 state
->bad_entry
= true;
3989 state
->success
= false;
3992 DEBUG(10,("validate_offline: %s ok\n", keystr
));
3996 static int validate_ndr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3997 struct tdb_validation_status
*state
)
4000 * Ignore validation for now. The proper way to do this is with a
4001 * checksum. Just pure parsing does not really catch much.
4006 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
4007 struct tdb_validation_status
*state
)
4009 if (dbuf
.dsize
!= 4) {
4010 DEBUG(0, ("validate_cache_version: Corrupt cache for "
4011 "key %s (len %u != 4) ?\n",
4012 keystr
, (unsigned int)dbuf
.dsize
));
4013 state
->bad_entry
= true;
4014 state
->success
= false;
4018 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
4022 /***********************************************************************
4023 A list of all possible cache tdb keys with associated validation
4025 ***********************************************************************/
4027 struct key_val_struct
{
4028 const char *keyname
;
4029 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
4031 {"SEQNUM/", validate_seqnum
},
4032 {"NS/", validate_ns
},
4033 {"SN/", validate_sn
},
4035 {"LOC_POL/", validate_loc_pol
},
4036 {"PWD_POL/", validate_pwd_pol
},
4037 {"CRED/", validate_cred
},
4038 {"UL/", validate_ul
},
4039 {"GL/", validate_gl
},
4040 {"UG/", validate_ug
},
4041 {"UA", validate_ua
},
4042 {"GM/", validate_gm
},
4043 {"DR/", validate_dr
},
4044 {"DE/", validate_de
},
4045 {"NSS/PWINFO/", validate_pwinfo
},
4046 {"TRUSTDOMCACHE/", validate_trustdomcache
},
4047 {"NSS/NA/", validate_nss_na
},
4048 {"NSS/AN/", validate_nss_an
},
4049 {"WINBINDD_OFFLINE", validate_offline
},
4050 {"NDR/", validate_ndr
},
4051 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
4055 /***********************************************************************
4056 Function to look at every entry in the tdb and validate it as far as
4058 ***********************************************************************/
4060 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
4063 unsigned int max_key_len
= 1024;
4064 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
4066 /* Paranoia check. */
4067 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0) {
4068 max_key_len
= 1024 * 1024;
4070 if (kbuf
.dsize
> max_key_len
) {
4071 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4073 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
4077 for (i
= 0; key_val
[i
].keyname
; i
++) {
4078 size_t namelen
= strlen(key_val
[i
].keyname
);
4079 if (kbuf
.dsize
>= namelen
&& (
4080 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
4081 TALLOC_CTX
*mem_ctx
;
4085 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
4089 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
4090 keystr
[kbuf
.dsize
] = '\0';
4092 mem_ctx
= talloc_init("validate_ctx");
4098 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
4102 talloc_destroy(mem_ctx
);
4107 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4108 dump_data(0, (uint8
*)kbuf
.dptr
, kbuf
.dsize
);
4109 DEBUG(0,("data :\n"));
4110 dump_data(0, (uint8
*)dbuf
.dptr
, dbuf
.dsize
);
4111 v_state
->unknown_key
= true;
4112 v_state
->success
= false;
4113 return 1; /* terminate. */
4116 static void validate_panic(const char *const why
)
4118 DEBUG(0,("validating cache: would panic %s\n", why
));
4119 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4123 static int wbcache_update_centry_fn(TDB_CONTEXT
*tdb
,
4131 if (is_non_centry_key(key
)) {
4135 if (data
.dptr
== NULL
|| data
.dsize
== 0) {
4136 if (tdb_delete(tdb
, key
) < 0) {
4137 DEBUG(0, ("tdb_delete for [%s] failed!\n",
4143 /* add timeout to blob (uint64_t) */
4144 blob
.dsize
= data
.dsize
+ 8;
4146 blob
.dptr
= SMB_XMALLOC_ARRAY(uint8_t, blob
.dsize
);
4147 if (blob
.dptr
== NULL
) {
4150 memset(blob
.dptr
, 0, blob
.dsize
);
4152 /* copy status and seqnum */
4153 memcpy(blob
.dptr
, data
.dptr
, 8);
4156 ctimeout
= lp_winbind_cache_time() + time(NULL
);
4157 SBVAL(blob
.dptr
, 8, ctimeout
);
4160 memcpy(blob
.dptr
+ 16, data
.dptr
+ 8, data
.dsize
- 8);
4162 if (tdb_store(tdb
, key
, blob
, TDB_REPLACE
) < 0) {
4163 DEBUG(0, ("tdb_store to update [%s] failed!\n",
4165 SAFE_FREE(blob
.dptr
);
4169 SAFE_FREE(blob
.dptr
);
4173 static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT
*tdb
)
4177 DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
4179 rc
= tdb_traverse(tdb
, wbcache_update_centry_fn
, NULL
);
4187 /***********************************************************************
4188 Try and validate every entry in the winbindd cache. If we fail here,
4189 delete the cache tdb and return non-zero.
4190 ***********************************************************************/
4192 int winbindd_validate_cache(void)
4195 const char *tdb_path
= state_path("winbindd_cache.tdb");
4196 TDB_CONTEXT
*tdb
= NULL
;
4200 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4201 smb_panic_fn
= validate_panic
;
4203 tdb
= tdb_open_log(tdb_path
,
4204 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
4205 TDB_INCOMPATIBLE_HASH
|
4206 ( lp_winbind_offline_logon()
4208 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
4212 DEBUG(0, ("winbindd_validate_cache: "
4213 "error opening/initializing tdb\n"));
4217 /* Version check and upgrade code. */
4218 if (!tdb_fetch_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers_id
)) {
4219 DEBUG(10, ("Fresh database\n"));
4220 tdb_store_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
);
4221 vers_id
= WINBINDD_CACHE_VERSION
;
4224 if (vers_id
!= WINBINDD_CACHE_VERSION
) {
4225 if (vers_id
== WINBINDD_CACHE_VER1
) {
4226 ok
= wbcache_upgrade_v1_to_v2(tdb
);
4228 DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
4233 tdb_store_uint32(tdb
,
4234 WINBINDD_CACHE_VERSION_KEYSTR
,
4235 WINBINDD_CACHE_VERSION
);
4236 vers_id
= WINBINDD_CACHE_VER2
;
4242 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
4245 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4246 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
4251 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4252 smb_panic_fn
= smb_panic
;
4256 /***********************************************************************
4257 Try and validate every entry in the winbindd cache.
4258 ***********************************************************************/
4260 int winbindd_validate_cache_nobackup(void)
4263 const char *tdb_path
= state_path("winbindd_cache.tdb");
4265 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4266 smb_panic_fn
= validate_panic
;
4269 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
4270 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
4272 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
4276 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4280 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4282 smb_panic_fn
= smb_panic
;
4286 bool winbindd_cache_validate_and_initialize(void)
4288 close_winbindd_cache();
4290 if (lp_winbind_offline_logon()) {
4291 if (winbindd_validate_cache() < 0) {
4292 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4293 "could be restored.\n"));
4297 return initialize_winbindd_cache();
4300 /*********************************************************************
4301 ********************************************************************/
4303 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
4304 struct winbindd_tdc_domain
**domains
,
4305 size_t *num_domains
)
4307 struct winbindd_tdc_domain
*list
= NULL
;
4310 bool set_only
= false;
4312 /* don't allow duplicates */
4317 for ( i
=0; i
< (*num_domains
); i
++ ) {
4318 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
4319 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4330 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, 1 );
4333 list
= talloc_realloc( *domains
, *domains
,
4334 struct winbindd_tdc_domain
,
4339 ZERO_STRUCT( list
[idx
] );
4345 list
[idx
].domain_name
= talloc_strdup(list
, new_dom
->name
);
4346 if (list
[idx
].domain_name
== NULL
) {
4349 if (new_dom
->alt_name
!= NULL
) {
4350 list
[idx
].dns_name
= talloc_strdup(list
, new_dom
->alt_name
);
4351 if (list
[idx
].dns_name
== NULL
) {
4356 if ( !is_null_sid( &new_dom
->sid
) ) {
4357 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
4359 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
4362 if ( new_dom
->domain_flags
!= 0x0 )
4363 list
[idx
].trust_flags
= new_dom
->domain_flags
;
4365 if ( new_dom
->domain_type
!= 0x0 )
4366 list
[idx
].trust_type
= new_dom
->domain_type
;
4368 if ( new_dom
->domain_trust_attribs
!= 0x0 )
4369 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
4373 *num_domains
= idx
+ 1;
4379 /*********************************************************************
4380 ********************************************************************/
4382 static TDB_DATA
make_tdc_key( const char *domain_name
)
4384 char *keystr
= NULL
;
4385 TDB_DATA key
= { NULL
, 0 };
4387 if ( !domain_name
) {
4388 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4392 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
4395 key
= string_term_tdb_data(keystr
);
4400 /*********************************************************************
4401 ********************************************************************/
4403 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
4405 unsigned char **buf
)
4407 unsigned char *buffer
= NULL
;
4412 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4420 /* Store the number of array items first */
4421 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
4424 /* now pack each domain trust record */
4425 for ( i
=0; i
<num_domains
; i
++ ) {
4430 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4431 domains
[i
].domain_name
,
4432 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
4435 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
4436 domains
[i
].domain_name
,
4437 domains
[i
].dns_name
? domains
[i
].dns_name
: "",
4438 sid_to_fstring(tmp
, &domains
[i
].sid
),
4439 domains
[i
].trust_flags
,
4440 domains
[i
].trust_attribs
,
4441 domains
[i
].trust_type
);
4444 if ( buflen
< len
) {
4446 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
4447 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4461 /*********************************************************************
4462 ********************************************************************/
4464 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
4465 struct winbindd_tdc_domain
**domains
)
4467 fstring domain_name
, dns_name
, sid_string
;
4468 uint32 type
, attribs
, flags
;
4472 struct winbindd_tdc_domain
*list
= NULL
;
4474 /* get the number of domains */
4475 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
4477 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4481 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, num_domains
);
4483 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4487 for ( i
=0; i
<num_domains
; i
++ ) {
4490 this_len
= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
4498 if ( this_len
== -1 ) {
4499 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4500 TALLOC_FREE( list
);
4505 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4506 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4507 domain_name
, dns_name
, sid_string
,
4508 flags
, attribs
, type
));
4510 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
4511 list
[i
].dns_name
= NULL
;
4512 if (dns_name
[0] != '\0') {
4513 list
[i
].dns_name
= talloc_strdup(list
, dns_name
);
4515 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
4516 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4519 list
[i
].trust_flags
= flags
;
4520 list
[i
].trust_attribs
= attribs
;
4521 list
[i
].trust_type
= type
;
4529 /*********************************************************************
4530 ********************************************************************/
4532 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
4534 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4535 TDB_DATA data
= { NULL
, 0 };
4541 /* See if we were asked to delete the cache entry */
4544 ret
= tdb_delete( wcache
->tdb
, key
);
4548 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4555 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4558 SAFE_FREE( data
.dptr
);
4559 SAFE_FREE( key
.dptr
);
4561 return ( ret
== 0 );
4564 /*********************************************************************
4565 ********************************************************************/
4567 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4569 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4570 TDB_DATA data
= { NULL
, 0 };
4578 data
= tdb_fetch_compat( wcache
->tdb
, key
);
4580 SAFE_FREE( key
.dptr
);
4585 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4587 SAFE_FREE( data
.dptr
);
4595 /*********************************************************************
4596 ********************************************************************/
4598 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4600 struct winbindd_tdc_domain
*dom_list
= NULL
;
4601 size_t num_domains
= 0;
4604 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4605 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4606 domain
->name
, domain
->alt_name
,
4607 sid_string_dbg(&domain
->sid
),
4608 domain
->domain_flags
,
4609 domain
->domain_trust_attribs
,
4610 domain
->domain_type
));
4612 if ( !init_wcache() ) {
4616 /* fetch the list */
4618 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4620 /* add the new domain */
4622 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4626 /* pack the domain */
4628 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4636 TALLOC_FREE( dom_list
);
4641 static struct winbindd_tdc_domain
*wcache_tdc_dup_domain(
4642 TALLOC_CTX
*mem_ctx
, const struct winbindd_tdc_domain
*src
)
4644 struct winbindd_tdc_domain
*dst
;
4646 dst
= talloc(mem_ctx
, struct winbindd_tdc_domain
);
4650 dst
->domain_name
= talloc_strdup(dst
, src
->domain_name
);
4651 if (dst
->domain_name
== NULL
) {
4655 dst
->dns_name
= NULL
;
4656 if (src
->dns_name
!= NULL
) {
4657 dst
->dns_name
= talloc_strdup(dst
, src
->dns_name
);
4658 if (dst
->dns_name
== NULL
) {
4663 sid_copy(&dst
->sid
, &src
->sid
);
4664 dst
->trust_flags
= src
->trust_flags
;
4665 dst
->trust_type
= src
->trust_type
;
4666 dst
->trust_attribs
= src
->trust_attribs
;
4673 /*********************************************************************
4674 ********************************************************************/
4676 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4678 struct winbindd_tdc_domain
*dom_list
= NULL
;
4679 size_t num_domains
= 0;
4681 struct winbindd_tdc_domain
*d
= NULL
;
4683 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4685 if ( !init_wcache() ) {
4689 /* fetch the list */
4691 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4693 for ( i
=0; i
<num_domains
; i
++ ) {
4694 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4695 strequal(name
, dom_list
[i
].dns_name
) )
4697 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4700 d
= wcache_tdc_dup_domain(ctx
, &dom_list
[i
]);
4705 TALLOC_FREE( dom_list
);
4710 /*********************************************************************
4711 ********************************************************************/
4713 struct winbindd_tdc_domain
*
4714 wcache_tdc_fetch_domainbysid(TALLOC_CTX
*ctx
,
4715 const struct dom_sid
*sid
)
4717 struct winbindd_tdc_domain
*dom_list
= NULL
;
4718 size_t num_domains
= 0;
4720 struct winbindd_tdc_domain
*d
= NULL
;
4722 DEBUG(10,("wcache_tdc_fetch_domainbysid: Searching for domain %s\n",
4723 sid_string_dbg(sid
)));
4725 if (!init_wcache()) {
4729 /* fetch the list */
4731 wcache_tdc_fetch_list(&dom_list
, &num_domains
);
4733 for (i
= 0; i
<num_domains
; i
++) {
4734 if (dom_sid_equal(sid
, &(dom_list
[i
].sid
))) {
4735 DEBUG(10, ("wcache_tdc_fetch_domainbysid: "
4736 "Found domain %s for SID %s\n",
4737 dom_list
[i
].domain_name
,
4738 sid_string_dbg(sid
)));
4740 d
= wcache_tdc_dup_domain(ctx
, &dom_list
[i
]);
4745 TALLOC_FREE(dom_list
);
4751 /*********************************************************************
4752 ********************************************************************/
4754 void wcache_tdc_clear( void )
4756 if ( !init_wcache() )
4759 wcache_tdc_store_list( NULL
, 0 );
4765 /*********************************************************************
4766 ********************************************************************/
4768 static void wcache_save_user_pwinfo(struct winbindd_domain
*domain
,
4770 const struct dom_sid
*user_sid
,
4771 const char *homedir
,
4776 struct cache_entry
*centry
;
4779 if ( (centry
= centry_start(domain
, status
)) == NULL
)
4782 centry_put_string( centry
, homedir
);
4783 centry_put_string( centry
, shell
);
4784 centry_put_string( centry
, gecos
);
4785 centry_put_uint32( centry
, gid
);
4787 centry_end(centry
, "NSS/PWINFO/%s", sid_to_fstring(tmp
, user_sid
) );
4789 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid
) ));
4791 centry_free(centry
);
4796 NTSTATUS
nss_get_info_cached( struct winbindd_domain
*domain
,
4797 const struct dom_sid
*user_sid
,
4799 const char **homedir
, const char **shell
,
4800 const char **gecos
, gid_t
*p_gid
)
4802 struct winbind_cache
*cache
= get_cache(domain
);
4803 struct cache_entry
*centry
= NULL
;
4810 centry
= wcache_fetch(cache
, domain
, "NSS/PWINFO/%s",
4811 sid_to_fstring(tmp
, user_sid
));
4816 *homedir
= centry_string( centry
, ctx
);
4817 *shell
= centry_string( centry
, ctx
);
4818 *gecos
= centry_string( centry
, ctx
);
4819 *p_gid
= centry_uint32( centry
);
4821 centry_free(centry
);
4823 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4824 sid_string_dbg(user_sid
)));
4826 return NT_STATUS_OK
;
4830 nt_status
= nss_get_info( domain
->name
, user_sid
, ctx
,
4831 homedir
, shell
, gecos
, p_gid
);
4833 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status
)));
4835 if ( NT_STATUS_IS_OK(nt_status
) ) {
4836 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir
));
4837 DEBUGADD(10, ("\tshell = '%s'\n", *shell
));
4838 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos
));
4839 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid
));
4841 wcache_save_user_pwinfo( domain
, nt_status
, user_sid
,
4842 *homedir
, *shell
, *gecos
, *p_gid
);
4845 if ( NT_STATUS_EQUAL( nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
4846 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4848 set_domain_offline( domain
);
4856 /* the cache backend methods are exposed via this structure */
4857 struct winbindd_methods cache_methods
= {
4875 static bool wcache_ndr_key(TALLOC_CTX
*mem_ctx
, const char *domain_name
,
4876 uint32_t opnum
, const DATA_BLOB
*req
,
4882 key
= talloc_asprintf(mem_ctx
, "NDR/%s/%d/", domain_name
, (int)opnum
);
4886 keylen
= talloc_get_size(key
) - 1;
4888 key
= talloc_realloc(mem_ctx
, key
, char, keylen
+ req
->length
);
4892 memcpy(key
+ keylen
, req
->data
, req
->length
);
4894 pkey
->dptr
= (uint8_t *)key
;
4895 pkey
->dsize
= talloc_get_size(key
);
4899 static bool wcache_opnum_cacheable(uint32_t opnum
)
4902 case NDR_WBINT_PING
:
4903 case NDR_WBINT_QUERYSEQUENCENUMBER
:
4904 case NDR_WBINT_ALLOCATEUID
:
4905 case NDR_WBINT_ALLOCATEGID
:
4906 case NDR_WBINT_CHECKMACHINEACCOUNT
:
4907 case NDR_WBINT_CHANGEMACHINEACCOUNT
:
4908 case NDR_WBINT_PINGDC
:
4914 bool wcache_fetch_ndr(TALLOC_CTX
*mem_ctx
, struct winbindd_domain
*domain
,
4915 uint32_t opnum
, const DATA_BLOB
*req
, DATA_BLOB
*resp
)
4920 if (!wcache_opnum_cacheable(opnum
) ||
4921 is_my_own_sam_domain(domain
) ||
4922 is_builtin_domain(domain
)) {
4926 if (wcache
->tdb
== NULL
) {
4930 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4933 data
= tdb_fetch_compat(wcache
->tdb
, key
);
4934 TALLOC_FREE(key
.dptr
);
4936 if (data
.dptr
== NULL
) {
4939 if (data
.dsize
< 12) {
4943 if (!is_domain_offline(domain
)) {
4944 uint32_t entry_seqnum
, dom_seqnum
, last_check
;
4945 uint64_t entry_timeout
;
4947 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
,
4951 entry_seqnum
= IVAL(data
.dptr
, 0);
4952 if (entry_seqnum
!= dom_seqnum
) {
4953 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4954 (int)entry_seqnum
));
4957 entry_timeout
= BVAL(data
.dptr
, 4);
4958 if (time(NULL
) > entry_timeout
) {
4959 DEBUG(10, ("Entry has timed out\n"));
4964 resp
->data
= (uint8_t *)talloc_memdup(mem_ctx
, data
.dptr
+ 12,
4966 if (resp
->data
== NULL
) {
4967 DEBUG(10, ("talloc failed\n"));
4970 resp
->length
= data
.dsize
- 12;
4974 SAFE_FREE(data
.dptr
);
4978 void wcache_store_ndr(struct winbindd_domain
*domain
, uint32_t opnum
,
4979 const DATA_BLOB
*req
, const DATA_BLOB
*resp
)
4982 uint32_t dom_seqnum
, last_check
;
4985 if (!wcache_opnum_cacheable(opnum
) ||
4986 is_my_own_sam_domain(domain
) ||
4987 is_builtin_domain(domain
)) {
4991 if (wcache
->tdb
== NULL
) {
4995 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
, &last_check
)) {
4996 DEBUG(10, ("could not fetch seqnum for domain %s\n",
5001 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
5005 timeout
= time(NULL
) + lp_winbind_cache_time();
5007 data
.dsize
= resp
->length
+ 12;
5008 data
.dptr
= talloc_array(key
.dptr
, uint8_t, data
.dsize
);
5009 if (data
.dptr
== NULL
) {
5013 SIVAL(data
.dptr
, 0, dom_seqnum
);
5014 SBVAL(data
.dptr
, 4, timeout
);
5015 memcpy(data
.dptr
+ 12, resp
->data
, resp
->length
);
5017 tdb_store(wcache
->tdb
, key
, data
, 0);
5020 TALLOC_FREE(key
.dptr
);