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 if ( (upper_name
= SMB_STRDUP(name
)) == NULL
)
1132 return NT_STATUS_NO_MEMORY
;
1133 if (!strupper_m(upper_name
)) {
1135 return NT_STATUS_INVALID_PARAMETER
;
1138 centry
= wcache_fetch(cache
, domain
, "NSS/NA/%s", upper_name
);
1140 SAFE_FREE( upper_name
);
1145 status
= centry
->status
;
1147 if (!NT_STATUS_IS_OK(status
)) {
1148 centry_free(centry
);
1152 *alias
= centry_string( centry
, mem_ctx
);
1154 centry_free(centry
);
1156 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1157 name
, *alias
? *alias
: "(none)"));
1159 return (*alias
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1163 /* If its not in cache and we are offline, then fail */
1165 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1166 DEBUG(8,("resolve_username_to_alias: rejecting query "
1167 "in offline mode\n"));
1168 return NT_STATUS_NOT_FOUND
;
1171 status
= nss_map_to_alias( mem_ctx
, domain
->name
, name
, alias
);
1173 if ( NT_STATUS_IS_OK( status
) ) {
1174 wcache_save_username_alias(domain
, status
, name
, *alias
);
1177 if ( NT_STATUS_EQUAL( status
, NT_STATUS_NONE_MAPPED
) ) {
1178 wcache_save_username_alias(domain
, status
, name
, "(NULL)");
1181 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1182 nt_errstr(status
)));
1184 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1185 set_domain_offline( domain
);
1191 /***************************************************************************
1192 ***************************************************************************/
1194 NTSTATUS
resolve_alias_to_username( TALLOC_CTX
*mem_ctx
,
1195 struct winbindd_domain
*domain
,
1196 const char *alias
, char **name
)
1198 struct winbind_cache
*cache
= get_cache(domain
);
1199 struct cache_entry
*centry
= NULL
;
1203 if ( domain
->internal
)
1204 return NT_STATUS_NOT_SUPPORTED
;
1209 if ( (upper_name
= SMB_STRDUP(alias
)) == NULL
)
1210 return NT_STATUS_NO_MEMORY
;
1211 if (!strupper_m(upper_name
)) {
1213 return NT_STATUS_INVALID_PARAMETER
;
1216 centry
= wcache_fetch(cache
, domain
, "NSS/AN/%s", upper_name
);
1218 SAFE_FREE( upper_name
);
1223 status
= centry
->status
;
1225 if (!NT_STATUS_IS_OK(status
)) {
1226 centry_free(centry
);
1230 *name
= centry_string( centry
, mem_ctx
);
1232 centry_free(centry
);
1234 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1235 alias
, *name
? *name
: "(none)"));
1237 return (*name
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1241 /* If its not in cache and we are offline, then fail */
1243 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1244 DEBUG(8,("resolve_alias_to_username: rejecting query "
1245 "in offline mode\n"));
1246 return NT_STATUS_NOT_FOUND
;
1249 /* an alias cannot contain a domain prefix or '@' */
1251 if (strchr(alias
, '\\') || strchr(alias
, '@')) {
1252 DEBUG(10,("resolve_alias_to_username: skipping fully "
1253 "qualified name %s\n", alias
));
1254 return NT_STATUS_OBJECT_NAME_INVALID
;
1257 status
= nss_map_from_alias( mem_ctx
, domain
->name
, alias
, name
);
1259 if ( NT_STATUS_IS_OK( status
) ) {
1260 wcache_save_alias_username( domain
, status
, alias
, *name
);
1263 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1264 wcache_save_alias_username(domain
, status
, alias
, "(NULL)");
1267 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1268 nt_errstr(status
)));
1270 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1271 set_domain_offline( domain
);
1277 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
1279 struct winbind_cache
*cache
= get_cache(domain
);
1281 fstring key_str
, tmp
;
1285 return NT_STATUS_INTERNAL_DB_ERROR
;
1288 if (is_null_sid(sid
)) {
1289 return NT_STATUS_INVALID_SID
;
1292 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1293 return NT_STATUS_INVALID_SID
;
1296 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
1298 data
= tdb_fetch_compat(cache
->tdb
, string_tdb_data(key_str
));
1300 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1303 SAFE_FREE(data
.dptr
);
1304 return NT_STATUS_OK
;
1307 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1308 as new salted ones. */
1310 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
1311 TALLOC_CTX
*mem_ctx
,
1312 const struct dom_sid
*sid
,
1313 const uint8
**cached_nt_pass
,
1314 const uint8
**cached_salt
)
1316 struct winbind_cache
*cache
= get_cache(domain
);
1317 struct cache_entry
*centry
= NULL
;
1323 return NT_STATUS_INTERNAL_DB_ERROR
;
1326 if (is_null_sid(sid
)) {
1327 return NT_STATUS_INVALID_SID
;
1330 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1331 return NT_STATUS_INVALID_SID
;
1334 /* Try and get a salted cred first. If we can't
1335 fall back to an unsalted cred. */
1337 centry
= wcache_fetch(cache
, domain
, "CRED/%s",
1338 sid_to_fstring(tmp
, sid
));
1340 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1341 sid_string_dbg(sid
)));
1342 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1346 * We don't use the time element at this moment,
1347 * but we have to consume it, so that we don't
1348 * neet to change the disk format of the cache.
1350 (void)centry_time(centry
);
1352 /* In the salted case this isn't actually the nt_hash itself,
1353 but the MD5 of the salt + nt_hash. Let the caller
1354 sort this out. It can tell as we only return the cached_salt
1355 if we are returning a salted cred. */
1357 *cached_nt_pass
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1358 if (*cached_nt_pass
== NULL
) {
1361 sid_to_fstring(sidstr
, sid
);
1363 /* Bad (old) cred cache. Delete and pretend we
1365 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1367 wcache_delete("CRED/%s", sidstr
);
1368 centry_free(centry
);
1369 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1372 /* We only have 17 bytes more data in the salted cred case. */
1373 if (centry
->len
- centry
->ofs
== 17) {
1374 *cached_salt
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1376 *cached_salt
= NULL
;
1379 dump_data_pw("cached_nt_pass", *cached_nt_pass
, NT_HASH_LEN
);
1381 dump_data_pw("cached_salt", *cached_salt
, NT_HASH_LEN
);
1384 status
= centry
->status
;
1386 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1387 sid_string_dbg(sid
), nt_errstr(status
) ));
1389 centry_free(centry
);
1393 /* Store creds for a SID - only writes out new salted ones. */
1395 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1396 const struct dom_sid
*sid
,
1397 const uint8 nt_pass
[NT_HASH_LEN
])
1399 struct cache_entry
*centry
;
1402 uint8 cred_salt
[NT_HASH_LEN
];
1403 uint8 salted_hash
[NT_HASH_LEN
];
1405 if (is_null_sid(sid
)) {
1406 return NT_STATUS_INVALID_SID
;
1409 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1410 return NT_STATUS_INVALID_SID
;
1413 centry
= centry_start(domain
, NT_STATUS_OK
);
1415 return NT_STATUS_INTERNAL_DB_ERROR
;
1418 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1420 centry_put_time(centry
, time(NULL
));
1422 /* Create a salt and then salt the hash. */
1423 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1424 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1426 centry_put_hash16(centry
, salted_hash
);
1427 centry_put_hash16(centry
, cred_salt
);
1428 centry_end(centry
, "CRED/%s", sid_to_fstring(sid_string
, sid
));
1430 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1432 centry_free(centry
);
1434 return NT_STATUS_OK
;
1438 /* Query display info. This is the basic user list fn */
1439 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
1440 TALLOC_CTX
*mem_ctx
,
1441 uint32
*num_entries
,
1442 struct wbint_userinfo
**info
)
1444 struct winbind_cache
*cache
= get_cache(domain
);
1445 struct cache_entry
*centry
= NULL
;
1447 unsigned int i
, retry
;
1448 bool old_status
= domain
->online
;
1453 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1458 *num_entries
= centry_uint32(centry
);
1460 if (*num_entries
== 0)
1463 (*info
) = talloc_array(mem_ctx
, struct wbint_userinfo
, *num_entries
);
1465 smb_panic_fn("query_user_list out of memory");
1467 for (i
=0; i
<(*num_entries
); i
++) {
1468 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
1469 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
1470 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
1471 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
1472 centry_sid(centry
, &(*info
)[i
].user_sid
);
1473 centry_sid(centry
, &(*info
)[i
].group_sid
);
1477 status
= centry
->status
;
1479 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1480 domain
->name
, nt_errstr(status
) ));
1482 centry_free(centry
);
1489 /* Return status value returned by seq number check */
1491 if (!NT_STATUS_IS_OK(domain
->last_status
))
1492 return domain
->last_status
;
1494 /* Put the query_user_list() in a retry loop. There appears to be
1495 * some bug either with Windows 2000 or Samba's handling of large
1496 * rpc replies. This manifests itself as sudden disconnection
1497 * at a random point in the enumeration of a large (60k) user list.
1498 * The retry loop simply tries the operation again. )-: It's not
1499 * pretty but an acceptable workaround until we work out what the
1500 * real problem is. */
1505 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1508 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
1509 if (!NT_STATUS_IS_OK(status
)) {
1510 DEBUG(3, ("query_user_list: returned 0x%08x, "
1511 "retrying\n", NT_STATUS_V(status
)));
1513 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1514 DEBUG(3, ("query_user_list: flushing "
1515 "connection cache\n"));
1516 invalidate_cm_connection(&domain
->conn
);
1518 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1519 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1520 if (!domain
->internal
&& old_status
) {
1521 set_domain_offline(domain
);
1523 /* store partial response. */
1524 if (*num_entries
> 0) {
1526 * humm, what about the status used for cache?
1527 * Should it be NT_STATUS_OK?
1532 * domain is offline now, and there is no user entries,
1533 * try to fetch from cache again.
1535 if (cache
->tdb
&& !domain
->online
&& !domain
->internal
&& old_status
) {
1536 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1537 /* partial response... */
1541 goto do_fetch_cache
;
1548 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1552 refresh_sequence_number(domain
, false);
1553 if (!NT_STATUS_IS_OK(status
)) {
1556 centry
= centry_start(domain
, status
);
1559 centry_put_uint32(centry
, *num_entries
);
1560 for (i
=0; i
<(*num_entries
); i
++) {
1561 centry_put_string(centry
, (*info
)[i
].acct_name
);
1562 centry_put_string(centry
, (*info
)[i
].full_name
);
1563 centry_put_string(centry
, (*info
)[i
].homedir
);
1564 centry_put_string(centry
, (*info
)[i
].shell
);
1565 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1566 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1567 if (domain
->backend
&& domain
->backend
->consistent
) {
1568 /* when the backend is consistent we can pre-prime some mappings */
1569 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1571 (*info
)[i
].acct_name
,
1572 &(*info
)[i
].user_sid
,
1574 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1575 &(*info
)[i
].user_sid
,
1577 (*info
)[i
].acct_name
,
1579 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1582 centry_end(centry
, "UL/%s", domain
->name
);
1583 centry_free(centry
);
1589 /* list all domain groups */
1590 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
1591 TALLOC_CTX
*mem_ctx
,
1592 uint32
*num_entries
,
1593 struct wb_acct_info
**info
)
1595 struct winbind_cache
*cache
= get_cache(domain
);
1596 struct cache_entry
*centry
= NULL
;
1601 old_status
= domain
->online
;
1605 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1610 *num_entries
= centry_uint32(centry
);
1612 if (*num_entries
== 0)
1615 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1617 smb_panic_fn("enum_dom_groups out of memory");
1619 for (i
=0; i
<(*num_entries
); i
++) {
1620 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1621 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1622 (*info
)[i
].rid
= centry_uint32(centry
);
1626 status
= centry
->status
;
1628 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1629 domain
->name
, nt_errstr(status
) ));
1631 centry_free(centry
);
1638 /* Return status value returned by seq number check */
1640 if (!NT_STATUS_IS_OK(domain
->last_status
))
1641 return domain
->last_status
;
1643 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1646 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1648 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1649 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1650 if (!domain
->internal
&& old_status
) {
1651 set_domain_offline(domain
);
1655 !domain
->internal
&&
1657 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1659 goto do_fetch_cache
;
1664 refresh_sequence_number(domain
, false);
1665 if (!NT_STATUS_IS_OK(status
)) {
1668 centry
= centry_start(domain
, status
);
1671 centry_put_uint32(centry
, *num_entries
);
1672 for (i
=0; i
<(*num_entries
); i
++) {
1673 centry_put_string(centry
, (*info
)[i
].acct_name
);
1674 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1675 centry_put_uint32(centry
, (*info
)[i
].rid
);
1677 centry_end(centry
, "GL/%s/domain", domain
->name
);
1678 centry_free(centry
);
1684 /* list all domain groups */
1685 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
1686 TALLOC_CTX
*mem_ctx
,
1687 uint32
*num_entries
,
1688 struct wb_acct_info
**info
)
1690 struct winbind_cache
*cache
= get_cache(domain
);
1691 struct cache_entry
*centry
= NULL
;
1696 old_status
= domain
->online
;
1700 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1705 *num_entries
= centry_uint32(centry
);
1707 if (*num_entries
== 0)
1710 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1712 smb_panic_fn("enum_dom_groups out of memory");
1714 for (i
=0; i
<(*num_entries
); i
++) {
1715 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1716 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1717 (*info
)[i
].rid
= centry_uint32(centry
);
1722 /* If we are returning cached data and the domain controller
1723 is down then we don't know whether the data is up to date
1724 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1727 if (wcache_server_down(domain
)) {
1728 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1729 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1731 status
= centry
->status
;
1733 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1734 domain
->name
, nt_errstr(status
) ));
1736 centry_free(centry
);
1743 /* Return status value returned by seq number check */
1745 if (!NT_STATUS_IS_OK(domain
->last_status
))
1746 return domain
->last_status
;
1748 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1751 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1753 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1754 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1755 if (!domain
->internal
&& old_status
) {
1756 set_domain_offline(domain
);
1759 !domain
->internal
&&
1762 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1764 goto do_fetch_cache
;
1769 refresh_sequence_number(domain
, false);
1770 if (!NT_STATUS_IS_OK(status
)) {
1773 centry
= centry_start(domain
, status
);
1776 centry_put_uint32(centry
, *num_entries
);
1777 for (i
=0; i
<(*num_entries
); i
++) {
1778 centry_put_string(centry
, (*info
)[i
].acct_name
);
1779 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1780 centry_put_uint32(centry
, (*info
)[i
].rid
);
1782 centry_end(centry
, "GL/%s/local", domain
->name
);
1783 centry_free(centry
);
1789 NTSTATUS
wcache_name_to_sid(struct winbindd_domain
*domain
,
1790 const char *domain_name
,
1792 struct dom_sid
*sid
,
1793 enum lsa_SidType
*type
)
1795 struct winbind_cache
*cache
= get_cache(domain
);
1796 struct cache_entry
*centry
;
1800 if (cache
->tdb
== NULL
) {
1801 return NT_STATUS_NOT_FOUND
;
1804 uname
= talloc_strdup_upper(talloc_tos(), name
);
1805 if (uname
== NULL
) {
1806 return NT_STATUS_NO_MEMORY
;
1809 if ((domain_name
== NULL
) || (domain_name
[0] == '\0')) {
1810 domain_name
= domain
->name
;
1813 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1815 if (centry
== NULL
) {
1816 return NT_STATUS_NOT_FOUND
;
1819 status
= centry
->status
;
1820 if (NT_STATUS_IS_OK(status
)) {
1821 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1822 centry_sid(centry
, sid
);
1825 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1826 "%s\n", domain
->name
, nt_errstr(status
) ));
1828 centry_free(centry
);
1832 /* convert a single name to a sid in a domain */
1833 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
1834 TALLOC_CTX
*mem_ctx
,
1835 const char *domain_name
,
1838 struct dom_sid
*sid
,
1839 enum lsa_SidType
*type
)
1844 old_status
= domain
->online
;
1846 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1847 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1853 /* If the seq number check indicated that there is a problem
1854 * with this DC, then return that status... except for
1855 * access_denied. This is special because the dc may be in
1856 * "restrict anonymous = 1" mode, in which case it will deny
1857 * most unauthenticated operations, but *will* allow the LSA
1858 * name-to-sid that we try as a fallback. */
1860 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1861 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1862 return domain
->last_status
;
1864 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1867 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
,
1868 name
, flags
, sid
, type
);
1870 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1871 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1872 if (!domain
->internal
&& old_status
) {
1873 set_domain_offline(domain
);
1875 if (!domain
->internal
&&
1878 NTSTATUS cache_status
;
1879 cache_status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1880 return cache_status
;
1884 refresh_sequence_number(domain
, false);
1886 if (domain
->online
&&
1887 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1888 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1890 /* Only save the reverse mapping if this was not a UPN */
1891 if (!strchr(name
, '@')) {
1892 if (!strupper_m(discard_const_p(char, domain_name
))) {
1893 return NT_STATUS_INVALID_PARAMETER
;
1895 (void)strlower_m(discard_const_p(char, name
));
1896 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1903 NTSTATUS
wcache_sid_to_name(struct winbindd_domain
*domain
,
1904 const struct dom_sid
*sid
,
1905 TALLOC_CTX
*mem_ctx
,
1908 enum lsa_SidType
*type
)
1910 struct winbind_cache
*cache
= get_cache(domain
);
1911 struct cache_entry
*centry
;
1915 if (cache
->tdb
== NULL
) {
1916 return NT_STATUS_NOT_FOUND
;
1919 sid_string
= sid_string_tos(sid
);
1920 if (sid_string
== NULL
) {
1921 return NT_STATUS_NO_MEMORY
;
1924 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_string
);
1925 TALLOC_FREE(sid_string
);
1926 if (centry
== NULL
) {
1927 return NT_STATUS_NOT_FOUND
;
1930 if (NT_STATUS_IS_OK(centry
->status
)) {
1931 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1932 *domain_name
= centry_string(centry
, mem_ctx
);
1933 *name
= centry_string(centry
, mem_ctx
);
1936 status
= centry
->status
;
1937 centry_free(centry
);
1939 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1940 "%s\n", domain
->name
, nt_errstr(status
) ));
1945 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1947 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1948 TALLOC_CTX
*mem_ctx
,
1949 const struct dom_sid
*sid
,
1952 enum lsa_SidType
*type
)
1957 old_status
= domain
->online
;
1958 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
1960 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1965 *domain_name
= NULL
;
1967 /* If the seq number check indicated that there is a problem
1968 * with this DC, then return that status... except for
1969 * access_denied. This is special because the dc may be in
1970 * "restrict anonymous = 1" mode, in which case it will deny
1971 * most unauthenticated operations, but *will* allow the LSA
1972 * sid-to-name that we try as a fallback. */
1974 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1975 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1976 return domain
->last_status
;
1978 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1981 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1983 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1984 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1985 if (!domain
->internal
&& old_status
) {
1986 set_domain_offline(domain
);
1988 if (!domain
->internal
&&
1991 NTSTATUS cache_status
;
1992 cache_status
= wcache_sid_to_name(domain
, sid
, mem_ctx
,
1993 domain_name
, name
, type
);
1994 return cache_status
;
1998 refresh_sequence_number(domain
, false);
1999 if (!NT_STATUS_IS_OK(status
)) {
2002 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
2004 /* We can't save the name to sid mapping here, as with sid history a
2005 * later name2sid would give the wrong sid. */
2010 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
2011 TALLOC_CTX
*mem_ctx
,
2012 const struct dom_sid
*domain_sid
,
2017 enum lsa_SidType
**types
)
2019 struct winbind_cache
*cache
= get_cache(domain
);
2021 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
2026 old_status
= domain
->online
;
2027 *domain_name
= NULL
;
2035 if (num_rids
== 0) {
2036 return NT_STATUS_OK
;
2039 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2040 *types
= talloc_array(mem_ctx
, enum lsa_SidType
, num_rids
);
2042 if ((*names
== NULL
) || (*types
== NULL
)) {
2043 result
= NT_STATUS_NO_MEMORY
;
2047 have_mapped
= have_unmapped
= false;
2049 for (i
=0; i
<num_rids
; i
++) {
2051 struct cache_entry
*centry
;
2054 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2055 result
= NT_STATUS_INTERNAL_ERROR
;
2059 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2060 sid_to_fstring(tmp
, &sid
));
2065 (*types
)[i
] = SID_NAME_UNKNOWN
;
2066 (*names
)[i
] = talloc_strdup(*names
, "");
2068 if (NT_STATUS_IS_OK(centry
->status
)) {
2071 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2073 dom
= centry_string(centry
, mem_ctx
);
2074 if (*domain_name
== NULL
) {
2080 (*names
)[i
] = centry_string(centry
, *names
);
2082 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)
2083 || NT_STATUS_EQUAL(centry
->status
, STATUS_SOME_UNMAPPED
)) {
2084 have_unmapped
= true;
2087 /* something's definitely wrong */
2088 result
= centry
->status
;
2092 centry_free(centry
);
2096 return NT_STATUS_NONE_MAPPED
;
2098 if (!have_unmapped
) {
2099 return NT_STATUS_OK
;
2101 return STATUS_SOME_UNMAPPED
;
2105 TALLOC_FREE(*names
);
2106 TALLOC_FREE(*types
);
2108 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
2109 rids
, num_rids
, domain_name
,
2112 if (NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
2113 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2114 if (!domain
->internal
&& old_status
) {
2115 set_domain_offline(domain
);
2118 !domain
->internal
&&
2121 have_mapped
= have_unmapped
= false;
2123 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2124 if (*names
== NULL
) {
2125 result
= NT_STATUS_NO_MEMORY
;
2129 *types
= talloc_array(mem_ctx
, enum lsa_SidType
,
2131 if (*types
== NULL
) {
2132 result
= NT_STATUS_NO_MEMORY
;
2136 for (i
=0; i
<num_rids
; i
++) {
2138 struct cache_entry
*centry
;
2141 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2142 result
= NT_STATUS_INTERNAL_ERROR
;
2146 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2147 sid_to_fstring(tmp
, &sid
));
2149 (*types
)[i
] = SID_NAME_UNKNOWN
;
2150 (*names
)[i
] = talloc_strdup(*names
, "");
2154 (*types
)[i
] = SID_NAME_UNKNOWN
;
2155 (*names
)[i
] = talloc_strdup(*names
, "");
2157 if (NT_STATUS_IS_OK(centry
->status
)) {
2160 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2162 dom
= centry_string(centry
, mem_ctx
);
2163 if (*domain_name
== NULL
) {
2169 (*names
)[i
] = centry_string(centry
, *names
);
2171 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)) {
2172 have_unmapped
= true;
2175 /* something's definitely wrong */
2176 result
= centry
->status
;
2177 centry_free(centry
);
2181 centry_free(centry
);
2185 return NT_STATUS_NONE_MAPPED
;
2187 if (!have_unmapped
) {
2188 return NT_STATUS_OK
;
2190 return STATUS_SOME_UNMAPPED
;
2194 None of the queried rids has been found so save all negative entries
2196 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
2197 for (i
= 0; i
< num_rids
; i
++) {
2199 const char *name
= "";
2200 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
2201 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
2203 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2204 return NT_STATUS_INTERNAL_ERROR
;
2207 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2215 Some or all of the queried rids have been found.
2217 if (!NT_STATUS_IS_OK(result
) &&
2218 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
2222 refresh_sequence_number(domain
, false);
2224 for (i
=0; i
<num_rids
; i
++) {
2228 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2229 result
= NT_STATUS_INTERNAL_ERROR
;
2233 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
2234 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
2236 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2237 (*names
)[i
], (*types
)[i
]);
2243 TALLOC_FREE(*names
);
2244 TALLOC_FREE(*types
);
2248 NTSTATUS
wcache_query_user(struct winbindd_domain
*domain
,
2249 TALLOC_CTX
*mem_ctx
,
2250 const struct dom_sid
*user_sid
,
2251 struct wbint_userinfo
*info
)
2253 struct winbind_cache
*cache
= get_cache(domain
);
2254 struct cache_entry
*centry
= NULL
;
2258 if (cache
->tdb
== NULL
) {
2259 return NT_STATUS_NOT_FOUND
;
2262 sid_string
= sid_string_tos(user_sid
);
2263 if (sid_string
== NULL
) {
2264 return NT_STATUS_NO_MEMORY
;
2267 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string
);
2268 TALLOC_FREE(sid_string
);
2269 if (centry
== NULL
) {
2270 return NT_STATUS_NOT_FOUND
;
2274 * If we have an access denied cache entry and a cached info3
2275 * in the samlogon cache then do a query. This will force the
2276 * rpc back end to return the info3 data.
2279 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
) &&
2280 netsamlogon_cache_have(user_sid
)) {
2281 DEBUG(10, ("query_user: cached access denied and have cached "
2283 domain
->last_status
= NT_STATUS_OK
;
2284 centry_free(centry
);
2285 return NT_STATUS_NOT_FOUND
;
2288 /* if status is not ok then this is a negative hit
2289 and the rest of the data doesn't matter */
2290 status
= centry
->status
;
2291 if (NT_STATUS_IS_OK(status
)) {
2292 info
->acct_name
= centry_string(centry
, mem_ctx
);
2293 info
->full_name
= centry_string(centry
, mem_ctx
);
2294 info
->homedir
= centry_string(centry
, mem_ctx
);
2295 info
->shell
= centry_string(centry
, mem_ctx
);
2296 info
->primary_gid
= centry_uint32(centry
);
2297 centry_sid(centry
, &info
->user_sid
);
2298 centry_sid(centry
, &info
->group_sid
);
2301 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2302 "%s\n", domain
->name
, nt_errstr(status
) ));
2304 centry_free(centry
);
2308 /* Lookup user information from a rid */
2309 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
2310 TALLOC_CTX
*mem_ctx
,
2311 const struct dom_sid
*user_sid
,
2312 struct wbint_userinfo
*info
)
2317 old_status
= domain
->online
;
2318 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2319 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2325 /* Return status value returned by seq number check */
2327 if (!NT_STATUS_IS_OK(domain
->last_status
))
2328 return domain
->last_status
;
2330 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2333 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
2335 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2336 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2337 if (!domain
->internal
&& old_status
) {
2338 set_domain_offline(domain
);
2340 if (!domain
->internal
&&
2343 NTSTATUS cache_status
;
2344 cache_status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2345 return cache_status
;
2349 refresh_sequence_number(domain
, false);
2350 if (!NT_STATUS_IS_OK(status
)) {
2353 wcache_save_user(domain
, status
, info
);
2358 NTSTATUS
wcache_lookup_usergroups(struct winbindd_domain
*domain
,
2359 TALLOC_CTX
*mem_ctx
,
2360 const struct dom_sid
*user_sid
,
2361 uint32_t *pnum_sids
,
2362 struct dom_sid
**psids
)
2364 struct winbind_cache
*cache
= get_cache(domain
);
2365 struct cache_entry
*centry
= NULL
;
2367 uint32_t i
, num_sids
;
2368 struct dom_sid
*sids
;
2371 if (cache
->tdb
== NULL
) {
2372 return NT_STATUS_NOT_FOUND
;
2375 centry
= wcache_fetch(cache
, domain
, "UG/%s",
2376 sid_to_fstring(sid_string
, user_sid
));
2377 if (centry
== NULL
) {
2378 return NT_STATUS_NOT_FOUND
;
2381 /* If we have an access denied cache entry and a cached info3 in the
2382 samlogon cache then do a query. This will force the rpc back end
2383 to return the info3 data. */
2385 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)
2386 && netsamlogon_cache_have(user_sid
)) {
2387 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2389 domain
->last_status
= NT_STATUS_OK
;
2390 centry_free(centry
);
2391 return NT_STATUS_NOT_FOUND
;
2394 num_sids
= centry_uint32(centry
);
2395 sids
= talloc_array(mem_ctx
, struct dom_sid
, num_sids
);
2397 centry_free(centry
);
2398 return NT_STATUS_NO_MEMORY
;
2401 for (i
=0; i
<num_sids
; i
++) {
2402 centry_sid(centry
, &sids
[i
]);
2405 status
= centry
->status
;
2407 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2408 "status: %s\n", domain
->name
, nt_errstr(status
)));
2410 centry_free(centry
);
2412 *pnum_sids
= num_sids
;
2417 /* Lookup groups a user is a member of. */
2418 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
2419 TALLOC_CTX
*mem_ctx
,
2420 const struct dom_sid
*user_sid
,
2421 uint32
*num_groups
, struct dom_sid
**user_gids
)
2423 struct cache_entry
*centry
= NULL
;
2429 old_status
= domain
->online
;
2430 status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2431 num_groups
, user_gids
);
2432 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2437 (*user_gids
) = NULL
;
2439 /* Return status value returned by seq number check */
2441 if (!NT_STATUS_IS_OK(domain
->last_status
))
2442 return domain
->last_status
;
2444 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2447 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
2449 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2450 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2451 if (!domain
->internal
&& old_status
) {
2452 set_domain_offline(domain
);
2454 if (!domain
->internal
&&
2457 NTSTATUS cache_status
;
2458 cache_status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2459 num_groups
, user_gids
);
2460 return cache_status
;
2463 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
2467 refresh_sequence_number(domain
, false);
2468 if (!NT_STATUS_IS_OK(status
)) {
2471 centry
= centry_start(domain
, status
);
2475 centry_put_uint32(centry
, *num_groups
);
2476 for (i
=0; i
<(*num_groups
); i
++) {
2477 centry_put_sid(centry
, &(*user_gids
)[i
]);
2480 centry_end(centry
, "UG/%s", sid_to_fstring(sid_string
, user_sid
));
2481 centry_free(centry
);
2487 static char *wcache_make_sidlist(TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2488 const struct dom_sid
*sids
)
2493 sidlist
= talloc_strdup(mem_ctx
, "");
2494 if (sidlist
== NULL
) {
2497 for (i
=0; i
<num_sids
; i
++) {
2499 sidlist
= talloc_asprintf_append_buffer(
2500 sidlist
, "/%s", sid_to_fstring(tmp
, &sids
[i
]));
2501 if (sidlist
== NULL
) {
2508 NTSTATUS
wcache_lookup_useraliases(struct winbindd_domain
*domain
,
2509 TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2510 const struct dom_sid
*sids
,
2511 uint32_t *pnum_aliases
, uint32_t **paliases
)
2513 struct winbind_cache
*cache
= get_cache(domain
);
2514 struct cache_entry
*centry
= NULL
;
2515 uint32_t num_aliases
;
2521 if (cache
->tdb
== NULL
) {
2522 return NT_STATUS_NOT_FOUND
;
2525 if (num_sids
== 0) {
2528 return NT_STATUS_OK
;
2531 /* We need to cache indexed by the whole list of SIDs, the aliases
2532 * resulting might come from any of the SIDs. */
2534 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2535 if (sidlist
== NULL
) {
2536 return NT_STATUS_NO_MEMORY
;
2539 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2540 TALLOC_FREE(sidlist
);
2541 if (centry
== NULL
) {
2542 return NT_STATUS_NOT_FOUND
;
2545 num_aliases
= centry_uint32(centry
);
2546 aliases
= talloc_array(mem_ctx
, uint32_t, num_aliases
);
2547 if (aliases
== NULL
) {
2548 centry_free(centry
);
2549 return NT_STATUS_NO_MEMORY
;
2552 for (i
=0; i
<num_aliases
; i
++) {
2553 aliases
[i
] = centry_uint32(centry
);
2556 status
= centry
->status
;
2558 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2559 "status %s\n", domain
->name
, nt_errstr(status
)));
2561 centry_free(centry
);
2563 *pnum_aliases
= num_aliases
;
2564 *paliases
= aliases
;
2569 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
2570 TALLOC_CTX
*mem_ctx
,
2571 uint32 num_sids
, const struct dom_sid
*sids
,
2572 uint32
*num_aliases
, uint32
**alias_rids
)
2574 struct cache_entry
*centry
= NULL
;
2580 old_status
= domain
->online
;
2581 status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
2582 num_aliases
, alias_rids
);
2583 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2588 (*alias_rids
) = NULL
;
2590 if (!NT_STATUS_IS_OK(domain
->last_status
))
2591 return domain
->last_status
;
2593 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2594 "for domain %s\n", domain
->name
));
2596 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2597 if (sidlist
== NULL
) {
2598 return NT_STATUS_NO_MEMORY
;
2601 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2603 num_aliases
, alias_rids
);
2605 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2606 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2607 if (!domain
->internal
&& old_status
) {
2608 set_domain_offline(domain
);
2610 if (!domain
->internal
&&
2613 NTSTATUS cache_status
;
2614 cache_status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
,
2615 sids
, num_aliases
, alias_rids
);
2616 return cache_status
;
2620 refresh_sequence_number(domain
, false);
2621 if (!NT_STATUS_IS_OK(status
)) {
2624 centry
= centry_start(domain
, status
);
2627 centry_put_uint32(centry
, *num_aliases
);
2628 for (i
=0; i
<(*num_aliases
); i
++)
2629 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2630 centry_end(centry
, "UA%s", sidlist
);
2631 centry_free(centry
);
2637 NTSTATUS
wcache_lookup_groupmem(struct winbindd_domain
*domain
,
2638 TALLOC_CTX
*mem_ctx
,
2639 const struct dom_sid
*group_sid
,
2640 uint32_t *num_names
,
2641 struct dom_sid
**sid_mem
, char ***names
,
2642 uint32_t **name_types
)
2644 struct winbind_cache
*cache
= get_cache(domain
);
2645 struct cache_entry
*centry
= NULL
;
2650 if (cache
->tdb
== NULL
) {
2651 return NT_STATUS_NOT_FOUND
;
2654 sid_string
= sid_string_tos(group_sid
);
2655 if (sid_string
== NULL
) {
2656 return NT_STATUS_NO_MEMORY
;
2659 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_string
);
2660 TALLOC_FREE(sid_string
);
2661 if (centry
== NULL
) {
2662 return NT_STATUS_NOT_FOUND
;
2669 *num_names
= centry_uint32(centry
);
2670 if (*num_names
== 0) {
2671 centry_free(centry
);
2672 return NT_STATUS_OK
;
2675 *sid_mem
= talloc_array(mem_ctx
, struct dom_sid
, *num_names
);
2676 *names
= talloc_array(mem_ctx
, char *, *num_names
);
2677 *name_types
= talloc_array(mem_ctx
, uint32
, *num_names
);
2679 if ((*sid_mem
== NULL
) || (*names
== NULL
) || (*name_types
== NULL
)) {
2680 TALLOC_FREE(*sid_mem
);
2681 TALLOC_FREE(*names
);
2682 TALLOC_FREE(*name_types
);
2683 centry_free(centry
);
2684 return NT_STATUS_NO_MEMORY
;
2687 for (i
=0; i
<(*num_names
); i
++) {
2688 centry_sid(centry
, &(*sid_mem
)[i
]);
2689 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2690 (*name_types
)[i
] = centry_uint32(centry
);
2693 status
= centry
->status
;
2695 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2696 "status: %s\n", domain
->name
, nt_errstr(status
)));
2698 centry_free(centry
);
2702 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
2703 TALLOC_CTX
*mem_ctx
,
2704 const struct dom_sid
*group_sid
,
2705 enum lsa_SidType type
,
2707 struct dom_sid
**sid_mem
, char ***names
,
2708 uint32
**name_types
)
2710 struct cache_entry
*centry
= NULL
;
2716 old_status
= domain
->online
;
2717 status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2718 sid_mem
, names
, name_types
);
2719 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2726 (*name_types
) = NULL
;
2728 /* Return status value returned by seq number check */
2730 if (!NT_STATUS_IS_OK(domain
->last_status
))
2731 return domain
->last_status
;
2733 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2736 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
,
2738 sid_mem
, names
, name_types
);
2740 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2741 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2742 if (!domain
->internal
&& old_status
) {
2743 set_domain_offline(domain
);
2745 if (!domain
->internal
&&
2748 NTSTATUS cache_status
;
2749 cache_status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
,
2750 num_names
, sid_mem
, names
,
2752 return cache_status
;
2756 refresh_sequence_number(domain
, false);
2757 if (!NT_STATUS_IS_OK(status
)) {
2760 centry
= centry_start(domain
, status
);
2763 centry_put_uint32(centry
, *num_names
);
2764 for (i
=0; i
<(*num_names
); i
++) {
2765 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2766 centry_put_string(centry
, (*names
)[i
]);
2767 centry_put_uint32(centry
, (*name_types
)[i
]);
2769 centry_end(centry
, "GM/%s", sid_to_fstring(sid_string
, group_sid
));
2770 centry_free(centry
);
2776 /* find the sequence number for a domain */
2777 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
2779 refresh_sequence_number(domain
, false);
2781 *seq
= domain
->sequence_number
;
2783 return NT_STATUS_OK
;
2786 /* enumerate trusted domains
2787 * (we need to have the list of trustdoms in the cache when we go offline) -
2789 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
2790 TALLOC_CTX
*mem_ctx
,
2791 struct netr_DomainTrustList
*trusts
)
2794 struct winbind_cache
*cache
;
2795 struct winbindd_tdc_domain
*dom_list
= NULL
;
2796 size_t num_domains
= 0;
2797 bool retval
= false;
2801 old_status
= domain
->online
;
2803 trusts
->array
= NULL
;
2805 cache
= get_cache(domain
);
2806 if (!cache
|| !cache
->tdb
) {
2810 if (domain
->online
) {
2814 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2815 if (!retval
|| !num_domains
|| !dom_list
) {
2816 TALLOC_FREE(dom_list
);
2821 trusts
->array
= talloc_zero_array(mem_ctx
, struct netr_DomainTrust
, num_domains
);
2822 if (!trusts
->array
) {
2823 TALLOC_FREE(dom_list
);
2824 return NT_STATUS_NO_MEMORY
;
2827 for (i
= 0; i
< num_domains
; i
++) {
2828 struct netr_DomainTrust
*trust
;
2829 struct dom_sid
*sid
;
2830 struct winbindd_domain
*dom
;
2832 dom
= find_domain_from_name_noinit(dom_list
[i
].domain_name
);
2833 if (dom
&& dom
->internal
) {
2837 trust
= &trusts
->array
[trusts
->count
];
2838 trust
->netbios_name
= talloc_strdup(trusts
->array
, dom_list
[i
].domain_name
);
2839 trust
->dns_name
= talloc_strdup(trusts
->array
, dom_list
[i
].dns_name
);
2840 sid
= talloc(trusts
->array
, struct dom_sid
);
2841 if (!trust
->netbios_name
|| !trust
->dns_name
||
2843 TALLOC_FREE(dom_list
);
2844 TALLOC_FREE(trusts
->array
);
2845 return NT_STATUS_NO_MEMORY
;
2848 trust
->trust_flags
= dom_list
[i
].trust_flags
;
2849 trust
->trust_attributes
= dom_list
[i
].trust_attribs
;
2850 trust
->trust_type
= dom_list
[i
].trust_type
;
2851 sid_copy(sid
, &dom_list
[i
].sid
);
2856 TALLOC_FREE(dom_list
);
2857 return NT_STATUS_OK
;
2860 /* Return status value returned by seq number check */
2862 if (!NT_STATUS_IS_OK(domain
->last_status
))
2863 return domain
->last_status
;
2865 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2868 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, trusts
);
2870 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2871 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2872 if (!domain
->internal
&& old_status
) {
2873 set_domain_offline(domain
);
2875 if (!domain
->internal
&&
2878 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2879 if (retval
&& num_domains
&& dom_list
) {
2880 TALLOC_FREE(trusts
->array
);
2882 goto do_fetch_cache
;
2886 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2887 * so that the generic centry handling still applies correctly -
2890 if (!NT_STATUS_IS_ERR(status
)) {
2891 status
= NT_STATUS_OK
;
2896 /* get lockout policy */
2897 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
2898 TALLOC_CTX
*mem_ctx
,
2899 struct samr_DomInfo12
*policy
)
2901 struct winbind_cache
*cache
= get_cache(domain
);
2902 struct cache_entry
*centry
= NULL
;
2906 old_status
= domain
->online
;
2910 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2916 policy
->lockout_duration
= centry_nttime(centry
);
2917 policy
->lockout_window
= centry_nttime(centry
);
2918 policy
->lockout_threshold
= centry_uint16(centry
);
2920 status
= centry
->status
;
2922 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2923 domain
->name
, nt_errstr(status
) ));
2925 centry_free(centry
);
2929 ZERO_STRUCTP(policy
);
2931 /* Return status value returned by seq number check */
2933 if (!NT_STATUS_IS_OK(domain
->last_status
))
2934 return domain
->last_status
;
2936 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2939 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2941 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2942 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2943 if (!domain
->internal
&& old_status
) {
2944 set_domain_offline(domain
);
2947 !domain
->internal
&&
2950 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2952 goto do_fetch_cache
;
2957 refresh_sequence_number(domain
, false);
2958 if (!NT_STATUS_IS_OK(status
)) {
2961 wcache_save_lockout_policy(domain
, status
, policy
);
2966 /* get password policy */
2967 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
2968 TALLOC_CTX
*mem_ctx
,
2969 struct samr_DomInfo1
*policy
)
2971 struct winbind_cache
*cache
= get_cache(domain
);
2972 struct cache_entry
*centry
= NULL
;
2976 old_status
= domain
->online
;
2980 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2986 policy
->min_password_length
= centry_uint16(centry
);
2987 policy
->password_history_length
= centry_uint16(centry
);
2988 policy
->password_properties
= centry_uint32(centry
);
2989 policy
->max_password_age
= centry_nttime(centry
);
2990 policy
->min_password_age
= centry_nttime(centry
);
2992 status
= centry
->status
;
2994 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2995 domain
->name
, nt_errstr(status
) ));
2997 centry_free(centry
);
3001 ZERO_STRUCTP(policy
);
3003 /* Return status value returned by seq number check */
3005 if (!NT_STATUS_IS_OK(domain
->last_status
))
3006 return domain
->last_status
;
3008 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
3011 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
3013 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
3014 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
3015 if (!domain
->internal
&& old_status
) {
3016 set_domain_offline(domain
);
3019 !domain
->internal
&&
3022 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
3024 goto do_fetch_cache
;
3029 refresh_sequence_number(domain
, false);
3030 if (!NT_STATUS_IS_OK(status
)) {
3033 wcache_save_password_policy(domain
, status
, policy
);
3039 /* Invalidate cached user and group lists coherently */
3041 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3044 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
3045 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
3046 tdb_delete(the_tdb
, kbuf
);
3051 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3053 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
3054 const struct dom_sid
*sid
)
3056 fstring key_str
, sid_string
;
3057 struct winbind_cache
*cache
;
3059 /* dont clear cached U/SID and UG/SID entries when we want to logon
3062 if (lp_winbind_offline_logon()) {
3069 cache
= get_cache(domain
);
3075 /* Clear U/SID cache entry */
3076 fstr_sprintf(key_str
, "U/%s", sid_to_fstring(sid_string
, sid
));
3077 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3078 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3080 /* Clear UG/SID cache entry */
3081 fstr_sprintf(key_str
, "UG/%s", sid_to_fstring(sid_string
, sid
));
3082 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3083 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3085 /* Samba/winbindd never needs this. */
3086 netsamlogon_clear_cached_user(sid
);
3089 bool wcache_invalidate_cache(void)
3091 struct winbindd_domain
*domain
;
3093 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3094 struct winbind_cache
*cache
= get_cache(domain
);
3096 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3097 "entries for %s\n", domain
->name
));
3100 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3109 bool wcache_invalidate_cache_noinit(void)
3111 struct winbindd_domain
*domain
;
3113 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3114 struct winbind_cache
*cache
;
3116 /* Skip uninitialized domains. */
3117 if (!domain
->initialized
&& !domain
->internal
) {
3121 cache
= get_cache(domain
);
3123 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3124 "entries for %s\n", domain
->name
));
3127 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3129 * Flushing cache has nothing to with domains.
3130 * return here if we successfully flushed once.
3131 * To avoid unnecessary traversing the cache.
3142 bool init_wcache(void)
3144 if (wcache
== NULL
) {
3145 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
3146 ZERO_STRUCTP(wcache
);
3149 if (wcache
->tdb
!= NULL
)
3152 /* when working offline we must not clear the cache on restart */
3153 wcache
->tdb
= tdb_open_log(state_path("winbindd_cache.tdb"),
3154 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3155 TDB_INCOMPATIBLE_HASH
|
3156 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3157 O_RDWR
|O_CREAT
, 0600);
3159 if (wcache
->tdb
== NULL
) {
3160 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3167 /************************************************************************
3168 This is called by the parent to initialize the cache file.
3169 We don't need sophisticated locking here as we know we're the
3171 ************************************************************************/
3173 bool initialize_winbindd_cache(void)
3175 bool cache_bad
= true;
3178 if (!init_wcache()) {
3179 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3183 /* Check version number. */
3184 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
3185 vers
== WINBINDD_CACHE_VERSION
) {
3190 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3191 "and re-creating with version number %d\n",
3192 WINBINDD_CACHE_VERSION
));
3194 tdb_close(wcache
->tdb
);
3197 if (unlink(state_path("winbindd_cache.tdb")) == -1) {
3198 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3199 state_path("winbindd_cache.tdb"),
3203 if (!init_wcache()) {
3204 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3205 "init_wcache failed.\n"));
3209 /* Write the version. */
3210 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
3211 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3212 tdb_errorstr_compat(wcache
->tdb
) ));
3217 tdb_close(wcache
->tdb
);
3222 void close_winbindd_cache(void)
3228 tdb_close(wcache
->tdb
);
3233 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*sid
,
3234 char **domain_name
, char **name
,
3235 enum lsa_SidType
*type
)
3237 struct winbindd_domain
*domain
;
3240 domain
= find_lookup_domain_from_sid(sid
);
3241 if (domain
== NULL
) {
3244 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
3246 return NT_STATUS_IS_OK(status
);
3249 bool lookup_cached_name(const char *domain_name
,
3251 struct dom_sid
*sid
,
3252 enum lsa_SidType
*type
)
3254 struct winbindd_domain
*domain
;
3256 bool original_online_state
;
3258 domain
= find_lookup_domain_from_name(domain_name
);
3259 if (domain
== NULL
) {
3263 /* If we are doing a cached logon, temporarily set the domain
3264 offline so the cache won't expire the entry */
3266 original_online_state
= domain
->online
;
3267 domain
->online
= false;
3268 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
3269 domain
->online
= original_online_state
;
3271 return NT_STATUS_IS_OK(status
);
3274 void cache_name2sid(struct winbindd_domain
*domain
,
3275 const char *domain_name
, const char *name
,
3276 enum lsa_SidType type
, const struct dom_sid
*sid
)
3278 refresh_sequence_number(domain
, false);
3279 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
3284 * The original idea that this cache only contains centries has
3285 * been blurred - now other stuff gets put in here. Ensure we
3286 * ignore these things on cleanup.
3289 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
3290 TDB_DATA dbuf
, void *state
)
3292 struct cache_entry
*centry
;
3294 if (is_non_centry_key(kbuf
)) {
3298 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
3303 if (!NT_STATUS_IS_OK(centry
->status
)) {
3304 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
3305 tdb_delete(the_tdb
, kbuf
);
3308 centry_free(centry
);
3312 /* flush the cache */
3313 void wcache_flush_cache(void)
3318 tdb_close(wcache
->tdb
);
3321 if (!winbindd_use_cache()) {
3325 /* when working offline we must not clear the cache on restart */
3326 wcache
->tdb
= tdb_open_log(state_path("winbindd_cache.tdb"),
3327 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3328 TDB_INCOMPATIBLE_HASH
|
3329 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3330 O_RDWR
|O_CREAT
, 0600);
3333 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3337 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
3339 DEBUG(10,("wcache_flush_cache success\n"));
3342 /* Count cached creds */
3344 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3347 int *cred_count
= (int*)state
;
3349 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3355 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
3357 struct winbind_cache
*cache
= get_cache(domain
);
3362 return NT_STATUS_INTERNAL_DB_ERROR
;
3365 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
3367 return NT_STATUS_OK
;
3371 struct cred_list
*prev
, *next
;
3376 static struct cred_list
*wcache_cred_list
;
3378 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3381 struct cred_list
*cred
;
3383 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3385 cred
= SMB_MALLOC_P(struct cred_list
);
3387 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3393 /* save a copy of the key */
3395 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
3396 DLIST_ADD(wcache_cred_list
, cred
);
3402 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
3404 struct winbind_cache
*cache
= get_cache(domain
);
3407 struct cred_list
*cred
, *oldest
= NULL
;
3410 return NT_STATUS_INTERNAL_DB_ERROR
;
3413 /* we possibly already have an entry */
3414 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
3416 fstring key_str
, tmp
;
3418 DEBUG(11,("we already have an entry, deleting that\n"));
3420 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
3422 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3424 return NT_STATUS_OK
;
3427 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
3429 return NT_STATUS_OK
;
3430 } else if ((ret
< 0) || (wcache_cred_list
== NULL
)) {
3431 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3434 ZERO_STRUCTP(oldest
);
3436 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
3441 data
= tdb_fetch_compat(cache
->tdb
, string_tdb_data(cred
->name
));
3443 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3445 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3449 t
= IVAL(data
.dptr
, 0);
3450 SAFE_FREE(data
.dptr
);
3453 oldest
= SMB_MALLOC_P(struct cred_list
);
3454 if (oldest
== NULL
) {
3455 status
= NT_STATUS_NO_MEMORY
;
3459 fstrcpy(oldest
->name
, cred
->name
);
3460 oldest
->created
= t
;
3464 if (t
< oldest
->created
) {
3465 fstrcpy(oldest
->name
, cred
->name
);
3466 oldest
->created
= t
;
3470 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3471 status
= NT_STATUS_OK
;
3473 status
= NT_STATUS_UNSUCCESSFUL
;
3476 SAFE_FREE(wcache_cred_list
);
3482 /* Change the global online/offline state. */
3483 bool set_global_winbindd_state_offline(void)
3487 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3489 /* Only go offline if someone has created
3490 the key "WINBINDD_OFFLINE" in the cache tdb. */
3492 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3493 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3497 if (!lp_winbind_offline_logon()) {
3498 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3502 if (global_winbindd_offline_state
) {
3503 /* Already offline. */
3507 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
3509 if (!data
.dptr
|| data
.dsize
!= 4) {
3510 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3511 SAFE_FREE(data
.dptr
);
3514 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3515 global_winbindd_offline_state
= true;
3516 SAFE_FREE(data
.dptr
);
3521 void set_global_winbindd_state_online(void)
3523 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3525 if (!lp_winbind_offline_logon()) {
3526 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3530 if (!global_winbindd_offline_state
) {
3531 /* Already online. */
3534 global_winbindd_offline_state
= false;
3540 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3541 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3544 bool get_global_winbindd_state_offline(void)
3546 return global_winbindd_offline_state
;
3549 /***********************************************************************
3550 Validate functions for all possible cache tdb keys.
3551 ***********************************************************************/
3553 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3554 struct tdb_validation_status
*state
)
3556 struct cache_entry
*centry
;
3558 centry
= SMB_XMALLOC_P(struct cache_entry
);
3559 centry
->data
= (unsigned char *)smb_memdup(data
.dptr
, data
.dsize
);
3560 if (!centry
->data
) {
3564 centry
->len
= data
.dsize
;
3567 if (centry
->len
< 16) {
3568 /* huh? corrupt cache? */
3569 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3570 "(len < 16) ?\n", kstr
));
3571 centry_free(centry
);
3572 state
->bad_entry
= true;
3573 state
->success
= false;
3577 centry
->status
= NT_STATUS(centry_uint32(centry
));
3578 centry
->sequence_number
= centry_uint32(centry
);
3579 centry
->timeout
= centry_uint64_t(centry
);
3583 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3584 struct tdb_validation_status
*state
)
3586 if (dbuf
.dsize
!= 8) {
3587 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3588 keystr
, (unsigned int)dbuf
.dsize
));
3589 state
->bad_entry
= true;
3595 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3596 struct tdb_validation_status
*state
)
3598 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3603 (void)centry_uint32(centry
);
3604 if (NT_STATUS_IS_OK(centry
->status
)) {
3606 (void)centry_sid(centry
, &sid
);
3609 centry_free(centry
);
3611 if (!(state
->success
)) {
3614 DEBUG(10,("validate_ns: %s ok\n", keystr
));
3618 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3619 struct tdb_validation_status
*state
)
3621 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3626 if (NT_STATUS_IS_OK(centry
->status
)) {
3627 (void)centry_uint32(centry
);
3628 (void)centry_string(centry
, mem_ctx
);
3629 (void)centry_string(centry
, mem_ctx
);
3632 centry_free(centry
);
3634 if (!(state
->success
)) {
3637 DEBUG(10,("validate_sn: %s ok\n", keystr
));
3641 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3642 struct tdb_validation_status
*state
)
3644 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3651 (void)centry_string(centry
, mem_ctx
);
3652 (void)centry_string(centry
, mem_ctx
);
3653 (void)centry_string(centry
, mem_ctx
);
3654 (void)centry_string(centry
, mem_ctx
);
3655 (void)centry_uint32(centry
);
3656 (void)centry_sid(centry
, &sid
);
3657 (void)centry_sid(centry
, &sid
);
3659 centry_free(centry
);
3661 if (!(state
->success
)) {
3664 DEBUG(10,("validate_u: %s ok\n", keystr
));
3668 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3669 struct tdb_validation_status
*state
)
3671 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3677 (void)centry_nttime(centry
);
3678 (void)centry_nttime(centry
);
3679 (void)centry_uint16(centry
);
3681 centry_free(centry
);
3683 if (!(state
->success
)) {
3686 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3690 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3691 struct tdb_validation_status
*state
)
3693 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3699 (void)centry_uint16(centry
);
3700 (void)centry_uint16(centry
);
3701 (void)centry_uint32(centry
);
3702 (void)centry_nttime(centry
);
3703 (void)centry_nttime(centry
);
3705 centry_free(centry
);
3707 if (!(state
->success
)) {
3710 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3714 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3715 struct tdb_validation_status
*state
)
3717 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3723 (void)centry_time(centry
);
3724 (void)centry_hash16(centry
, mem_ctx
);
3726 /* We only have 17 bytes more data in the salted cred case. */
3727 if (centry
->len
- centry
->ofs
== 17) {
3728 (void)centry_hash16(centry
, mem_ctx
);
3731 centry_free(centry
);
3733 if (!(state
->success
)) {
3736 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3740 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3741 struct tdb_validation_status
*state
)
3743 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3744 int32 num_entries
, i
;
3750 num_entries
= (int32
)centry_uint32(centry
);
3752 for (i
=0; i
< num_entries
; i
++) {
3754 (void)centry_string(centry
, mem_ctx
);
3755 (void)centry_string(centry
, mem_ctx
);
3756 (void)centry_string(centry
, mem_ctx
);
3757 (void)centry_string(centry
, mem_ctx
);
3758 (void)centry_sid(centry
, &sid
);
3759 (void)centry_sid(centry
, &sid
);
3762 centry_free(centry
);
3764 if (!(state
->success
)) {
3767 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3771 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3772 struct tdb_validation_status
*state
)
3774 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3775 int32 num_entries
, i
;
3781 num_entries
= centry_uint32(centry
);
3783 for (i
=0; i
< num_entries
; i
++) {
3784 (void)centry_string(centry
, mem_ctx
);
3785 (void)centry_string(centry
, mem_ctx
);
3786 (void)centry_uint32(centry
);
3789 centry_free(centry
);
3791 if (!(state
->success
)) {
3794 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3798 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3799 struct tdb_validation_status
*state
)
3801 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3802 int32 num_groups
, i
;
3808 num_groups
= centry_uint32(centry
);
3810 for (i
=0; i
< num_groups
; i
++) {
3812 centry_sid(centry
, &sid
);
3815 centry_free(centry
);
3817 if (!(state
->success
)) {
3820 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3824 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3825 struct tdb_validation_status
*state
)
3827 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3828 int32 num_aliases
, i
;
3834 num_aliases
= centry_uint32(centry
);
3836 for (i
=0; i
< num_aliases
; i
++) {
3837 (void)centry_uint32(centry
);
3840 centry_free(centry
);
3842 if (!(state
->success
)) {
3845 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3849 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3850 struct tdb_validation_status
*state
)
3852 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3859 num_names
= centry_uint32(centry
);
3861 for (i
=0; i
< num_names
; i
++) {
3863 centry_sid(centry
, &sid
);
3864 (void)centry_string(centry
, mem_ctx
);
3865 (void)centry_uint32(centry
);
3868 centry_free(centry
);
3870 if (!(state
->success
)) {
3873 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3877 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3878 struct tdb_validation_status
*state
)
3880 /* Can't say anything about this other than must be nonzero. */
3881 if (dbuf
.dsize
== 0) {
3882 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3884 state
->bad_entry
= true;
3885 state
->success
= false;
3889 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3893 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3894 struct tdb_validation_status
*state
)
3896 /* Can't say anything about this other than must be nonzero. */
3897 if (dbuf
.dsize
== 0) {
3898 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3900 state
->bad_entry
= true;
3901 state
->success
= false;
3905 DEBUG(10,("validate_de: %s ok\n", keystr
));
3909 static int validate_pwinfo(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3910 TDB_DATA dbuf
, struct tdb_validation_status
*state
)
3912 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3918 (void)centry_string(centry
, mem_ctx
);
3919 (void)centry_string(centry
, mem_ctx
);
3920 (void)centry_string(centry
, mem_ctx
);
3921 (void)centry_uint32(centry
);
3923 centry_free(centry
);
3925 if (!(state
->success
)) {
3928 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3932 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3934 struct tdb_validation_status
*state
)
3936 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3942 (void)centry_string( centry
, mem_ctx
);
3944 centry_free(centry
);
3946 if (!(state
->success
)) {
3949 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3953 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3955 struct tdb_validation_status
*state
)
3957 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3963 (void)centry_string( centry
, mem_ctx
);
3965 centry_free(centry
);
3967 if (!(state
->success
)) {
3970 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3974 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3976 struct tdb_validation_status
*state
)
3978 if (dbuf
.dsize
== 0) {
3979 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3980 "key %s (len ==0) ?\n", keystr
));
3981 state
->bad_entry
= true;
3982 state
->success
= false;
3986 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3987 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3991 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3992 struct tdb_validation_status
*state
)
3994 if (dbuf
.dsize
!= 4) {
3995 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3996 keystr
, (unsigned int)dbuf
.dsize
));
3997 state
->bad_entry
= true;
3998 state
->success
= false;
4001 DEBUG(10,("validate_offline: %s ok\n", keystr
));
4005 static int validate_ndr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
4006 struct tdb_validation_status
*state
)
4009 * Ignore validation for now. The proper way to do this is with a
4010 * checksum. Just pure parsing does not really catch much.
4015 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
4016 struct tdb_validation_status
*state
)
4018 if (dbuf
.dsize
!= 4) {
4019 DEBUG(0, ("validate_cache_version: Corrupt cache for "
4020 "key %s (len %u != 4) ?\n",
4021 keystr
, (unsigned int)dbuf
.dsize
));
4022 state
->bad_entry
= true;
4023 state
->success
= false;
4027 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
4031 /***********************************************************************
4032 A list of all possible cache tdb keys with associated validation
4034 ***********************************************************************/
4036 struct key_val_struct
{
4037 const char *keyname
;
4038 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
4040 {"SEQNUM/", validate_seqnum
},
4041 {"NS/", validate_ns
},
4042 {"SN/", validate_sn
},
4044 {"LOC_POL/", validate_loc_pol
},
4045 {"PWD_POL/", validate_pwd_pol
},
4046 {"CRED/", validate_cred
},
4047 {"UL/", validate_ul
},
4048 {"GL/", validate_gl
},
4049 {"UG/", validate_ug
},
4050 {"UA", validate_ua
},
4051 {"GM/", validate_gm
},
4052 {"DR/", validate_dr
},
4053 {"DE/", validate_de
},
4054 {"NSS/PWINFO/", validate_pwinfo
},
4055 {"TRUSTDOMCACHE/", validate_trustdomcache
},
4056 {"NSS/NA/", validate_nss_na
},
4057 {"NSS/AN/", validate_nss_an
},
4058 {"WINBINDD_OFFLINE", validate_offline
},
4059 {"NDR/", validate_ndr
},
4060 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
4064 /***********************************************************************
4065 Function to look at every entry in the tdb and validate it as far as
4067 ***********************************************************************/
4069 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
4072 unsigned int max_key_len
= 1024;
4073 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
4075 /* Paranoia check. */
4076 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0 ||
4077 strncmp("NDR/", (const char *)kbuf
.dptr
, 4) == 0) {
4078 max_key_len
= 1024 * 1024;
4080 if (kbuf
.dsize
> max_key_len
) {
4081 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4083 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
4087 for (i
= 0; key_val
[i
].keyname
; i
++) {
4088 size_t namelen
= strlen(key_val
[i
].keyname
);
4089 if (kbuf
.dsize
>= namelen
&& (
4090 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
4091 TALLOC_CTX
*mem_ctx
;
4095 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
4099 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
4100 keystr
[kbuf
.dsize
] = '\0';
4102 mem_ctx
= talloc_init("validate_ctx");
4108 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
4112 talloc_destroy(mem_ctx
);
4117 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4118 dump_data(0, (uint8
*)kbuf
.dptr
, kbuf
.dsize
);
4119 DEBUG(0,("data :\n"));
4120 dump_data(0, (uint8
*)dbuf
.dptr
, dbuf
.dsize
);
4121 v_state
->unknown_key
= true;
4122 v_state
->success
= false;
4123 return 1; /* terminate. */
4126 static void validate_panic(const char *const why
)
4128 DEBUG(0,("validating cache: would panic %s\n", why
));
4129 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4133 static int wbcache_update_centry_fn(TDB_CONTEXT
*tdb
,
4141 if (is_non_centry_key(key
)) {
4145 if (data
.dptr
== NULL
|| data
.dsize
== 0) {
4146 if (tdb_delete(tdb
, key
) < 0) {
4147 DEBUG(0, ("tdb_delete for [%s] failed!\n",
4153 /* add timeout to blob (uint64_t) */
4154 blob
.dsize
= data
.dsize
+ 8;
4156 blob
.dptr
= SMB_XMALLOC_ARRAY(uint8_t, blob
.dsize
);
4157 if (blob
.dptr
== NULL
) {
4160 memset(blob
.dptr
, 0, blob
.dsize
);
4162 /* copy status and seqnum */
4163 memcpy(blob
.dptr
, data
.dptr
, 8);
4166 ctimeout
= lp_winbind_cache_time() + time(NULL
);
4167 SBVAL(blob
.dptr
, 8, ctimeout
);
4170 memcpy(blob
.dptr
+ 16, data
.dptr
+ 8, data
.dsize
- 8);
4172 if (tdb_store(tdb
, key
, blob
, TDB_REPLACE
) < 0) {
4173 DEBUG(0, ("tdb_store to update [%s] failed!\n",
4175 SAFE_FREE(blob
.dptr
);
4179 SAFE_FREE(blob
.dptr
);
4183 static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT
*tdb
)
4187 DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
4189 rc
= tdb_traverse(tdb
, wbcache_update_centry_fn
, NULL
);
4197 /***********************************************************************
4198 Try and validate every entry in the winbindd cache. If we fail here,
4199 delete the cache tdb and return non-zero.
4200 ***********************************************************************/
4202 int winbindd_validate_cache(void)
4205 const char *tdb_path
= state_path("winbindd_cache.tdb");
4206 TDB_CONTEXT
*tdb
= NULL
;
4210 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4211 smb_panic_fn
= validate_panic
;
4213 tdb
= tdb_open_log(tdb_path
,
4214 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
4215 TDB_INCOMPATIBLE_HASH
|
4216 ( lp_winbind_offline_logon()
4218 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
4222 DEBUG(0, ("winbindd_validate_cache: "
4223 "error opening/initializing tdb\n"));
4227 /* Version check and upgrade code. */
4228 if (!tdb_fetch_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers_id
)) {
4229 DEBUG(10, ("Fresh database\n"));
4230 tdb_store_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
);
4231 vers_id
= WINBINDD_CACHE_VERSION
;
4234 if (vers_id
!= WINBINDD_CACHE_VERSION
) {
4235 if (vers_id
== WINBINDD_CACHE_VER1
) {
4236 ok
= wbcache_upgrade_v1_to_v2(tdb
);
4238 DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
4243 tdb_store_uint32(tdb
,
4244 WINBINDD_CACHE_VERSION_KEYSTR
,
4245 WINBINDD_CACHE_VERSION
);
4246 vers_id
= WINBINDD_CACHE_VER2
;
4252 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
4255 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4256 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
4261 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4262 smb_panic_fn
= smb_panic
;
4266 /***********************************************************************
4267 Try and validate every entry in the winbindd cache.
4268 ***********************************************************************/
4270 int winbindd_validate_cache_nobackup(void)
4273 const char *tdb_path
= state_path("winbindd_cache.tdb");
4275 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4276 smb_panic_fn
= validate_panic
;
4279 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
4280 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
4282 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
4286 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4290 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4292 smb_panic_fn
= smb_panic
;
4296 bool winbindd_cache_validate_and_initialize(void)
4298 close_winbindd_cache();
4300 if (lp_winbind_offline_logon()) {
4301 if (winbindd_validate_cache() < 0) {
4302 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4303 "could be restored.\n"));
4307 return initialize_winbindd_cache();
4310 /*********************************************************************
4311 ********************************************************************/
4313 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
4314 struct winbindd_tdc_domain
**domains
,
4315 size_t *num_domains
)
4317 struct winbindd_tdc_domain
*list
= NULL
;
4320 bool set_only
= false;
4322 /* don't allow duplicates */
4327 for ( i
=0; i
< (*num_domains
); i
++ ) {
4328 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
4329 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4340 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, 1 );
4343 list
= talloc_realloc( *domains
, *domains
,
4344 struct winbindd_tdc_domain
,
4349 ZERO_STRUCT( list
[idx
] );
4355 list
[idx
].domain_name
= talloc_strdup( list
, new_dom
->name
);
4356 list
[idx
].dns_name
= talloc_strdup( list
, new_dom
->alt_name
);
4358 if ( !is_null_sid( &new_dom
->sid
) ) {
4359 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
4361 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
4364 if ( new_dom
->domain_flags
!= 0x0 )
4365 list
[idx
].trust_flags
= new_dom
->domain_flags
;
4367 if ( new_dom
->domain_type
!= 0x0 )
4368 list
[idx
].trust_type
= new_dom
->domain_type
;
4370 if ( new_dom
->domain_trust_attribs
!= 0x0 )
4371 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
4375 *num_domains
= idx
+ 1;
4381 /*********************************************************************
4382 ********************************************************************/
4384 static TDB_DATA
make_tdc_key( const char *domain_name
)
4386 char *keystr
= NULL
;
4387 TDB_DATA key
= { NULL
, 0 };
4389 if ( !domain_name
) {
4390 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4394 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
4397 key
= string_term_tdb_data(keystr
);
4402 /*********************************************************************
4403 ********************************************************************/
4405 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
4407 unsigned char **buf
)
4409 unsigned char *buffer
= NULL
;
4414 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4422 /* Store the number of array items first */
4423 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
4426 /* now pack each domain trust record */
4427 for ( i
=0; i
<num_domains
; i
++ ) {
4432 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4433 domains
[i
].domain_name
,
4434 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
4437 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
4438 domains
[i
].domain_name
,
4439 domains
[i
].dns_name
,
4440 sid_to_fstring(tmp
, &domains
[i
].sid
),
4441 domains
[i
].trust_flags
,
4442 domains
[i
].trust_attribs
,
4443 domains
[i
].trust_type
);
4446 if ( buflen
< len
) {
4448 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
4449 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4463 /*********************************************************************
4464 ********************************************************************/
4466 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
4467 struct winbindd_tdc_domain
**domains
)
4469 fstring domain_name
, dns_name
, sid_string
;
4470 uint32 type
, attribs
, flags
;
4474 struct winbindd_tdc_domain
*list
= NULL
;
4476 /* get the number of domains */
4477 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
4479 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4483 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, num_domains
);
4485 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4489 for ( i
=0; i
<num_domains
; i
++ ) {
4490 len
+= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
4499 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4500 TALLOC_FREE( list
);
4504 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4505 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4506 domain_name
, dns_name
, sid_string
,
4507 flags
, attribs
, type
));
4509 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
4510 list
[i
].dns_name
= talloc_strdup( list
, dns_name
);
4511 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
4512 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4515 list
[i
].trust_flags
= flags
;
4516 list
[i
].trust_attribs
= attribs
;
4517 list
[i
].trust_type
= type
;
4525 /*********************************************************************
4526 ********************************************************************/
4528 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
4530 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4531 TDB_DATA data
= { NULL
, 0 };
4537 /* See if we were asked to delete the cache entry */
4540 ret
= tdb_delete( wcache
->tdb
, key
);
4544 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4551 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4554 SAFE_FREE( data
.dptr
);
4555 SAFE_FREE( key
.dptr
);
4557 return ( ret
== 0 );
4560 /*********************************************************************
4561 ********************************************************************/
4563 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4565 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4566 TDB_DATA data
= { NULL
, 0 };
4574 data
= tdb_fetch_compat( wcache
->tdb
, key
);
4576 SAFE_FREE( key
.dptr
);
4581 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4583 SAFE_FREE( data
.dptr
);
4591 /*********************************************************************
4592 ********************************************************************/
4594 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4596 struct winbindd_tdc_domain
*dom_list
= NULL
;
4597 size_t num_domains
= 0;
4600 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4601 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4602 domain
->name
, domain
->alt_name
,
4603 sid_string_dbg(&domain
->sid
),
4604 domain
->domain_flags
,
4605 domain
->domain_trust_attribs
,
4606 domain
->domain_type
));
4608 if ( !init_wcache() ) {
4612 /* fetch the list */
4614 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4616 /* add the new domain */
4618 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4622 /* pack the domain */
4624 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4632 TALLOC_FREE( dom_list
);
4637 /*********************************************************************
4638 ********************************************************************/
4640 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4642 struct winbindd_tdc_domain
*dom_list
= NULL
;
4643 size_t num_domains
= 0;
4645 struct winbindd_tdc_domain
*d
= NULL
;
4647 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4649 if ( !init_wcache() ) {
4653 /* fetch the list */
4655 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4657 for ( i
=0; i
<num_domains
; i
++ ) {
4658 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4659 strequal(name
, dom_list
[i
].dns_name
) )
4661 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4664 d
= talloc( ctx
, struct winbindd_tdc_domain
);
4668 d
->domain_name
= talloc_strdup( d
, dom_list
[i
].domain_name
);
4669 d
->dns_name
= talloc_strdup( d
, dom_list
[i
].dns_name
);
4670 sid_copy( &d
->sid
, &dom_list
[i
].sid
);
4671 d
->trust_flags
= dom_list
[i
].trust_flags
;
4672 d
->trust_type
= dom_list
[i
].trust_type
;
4673 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
4679 TALLOC_FREE( dom_list
);
4684 /*********************************************************************
4685 ********************************************************************/
4687 struct winbindd_tdc_domain
*
4688 wcache_tdc_fetch_domainbysid(TALLOC_CTX
*ctx
,
4689 const struct dom_sid
*sid
)
4691 struct winbindd_tdc_domain
*dom_list
= NULL
;
4692 size_t num_domains
= 0;
4694 struct winbindd_tdc_domain
*d
= NULL
;
4696 DEBUG(10,("wcache_tdc_fetch_domainbysid: Searching for domain %s\n",
4697 sid_string_dbg(sid
)));
4699 if (!init_wcache()) {
4703 /* fetch the list */
4705 wcache_tdc_fetch_list(&dom_list
, &num_domains
);
4707 for (i
= 0; i
<num_domains
; i
++) {
4708 if (dom_sid_equal(sid
, &(dom_list
[i
].sid
))) {
4709 DEBUG(10, ("wcache_tdc_fetch_domainbysid: "
4710 "Found domain %s for SID %s\n",
4711 dom_list
[i
].domain_name
,
4712 sid_string_dbg(sid
)));
4714 d
= talloc(ctx
, struct winbindd_tdc_domain
);
4718 d
->domain_name
= talloc_strdup(d
,
4719 dom_list
[i
].domain_name
);
4721 d
->dns_name
= talloc_strdup(d
, dom_list
[i
].dns_name
);
4722 sid_copy(&d
->sid
, &dom_list
[i
].sid
);
4723 d
->trust_flags
= dom_list
[i
].trust_flags
;
4724 d
->trust_type
= dom_list
[i
].trust_type
;
4725 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
4731 TALLOC_FREE(dom_list
);
4737 /*********************************************************************
4738 ********************************************************************/
4740 void wcache_tdc_clear( void )
4742 if ( !init_wcache() )
4745 wcache_tdc_store_list( NULL
, 0 );
4751 /*********************************************************************
4752 ********************************************************************/
4754 static void wcache_save_user_pwinfo(struct winbindd_domain
*domain
,
4756 const struct dom_sid
*user_sid
,
4757 const char *homedir
,
4762 struct cache_entry
*centry
;
4765 if ( (centry
= centry_start(domain
, status
)) == NULL
)
4768 centry_put_string( centry
, homedir
);
4769 centry_put_string( centry
, shell
);
4770 centry_put_string( centry
, gecos
);
4771 centry_put_uint32( centry
, gid
);
4773 centry_end(centry
, "NSS/PWINFO/%s", sid_to_fstring(tmp
, user_sid
) );
4775 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid
) ));
4777 centry_free(centry
);
4782 NTSTATUS
nss_get_info_cached( struct winbindd_domain
*domain
,
4783 const struct dom_sid
*user_sid
,
4785 const char **homedir
, const char **shell
,
4786 const char **gecos
, gid_t
*p_gid
)
4788 struct winbind_cache
*cache
= get_cache(domain
);
4789 struct cache_entry
*centry
= NULL
;
4796 centry
= wcache_fetch(cache
, domain
, "NSS/PWINFO/%s",
4797 sid_to_fstring(tmp
, user_sid
));
4802 *homedir
= centry_string( centry
, ctx
);
4803 *shell
= centry_string( centry
, ctx
);
4804 *gecos
= centry_string( centry
, ctx
);
4805 *p_gid
= centry_uint32( centry
);
4807 centry_free(centry
);
4809 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4810 sid_string_dbg(user_sid
)));
4812 return NT_STATUS_OK
;
4816 nt_status
= nss_get_info( domain
->name
, user_sid
, ctx
,
4817 homedir
, shell
, gecos
, p_gid
);
4819 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status
)));
4821 if ( NT_STATUS_IS_OK(nt_status
) ) {
4822 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir
));
4823 DEBUGADD(10, ("\tshell = '%s'\n", *shell
));
4824 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos
));
4825 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid
));
4827 wcache_save_user_pwinfo( domain
, nt_status
, user_sid
,
4828 *homedir
, *shell
, *gecos
, *p_gid
);
4831 if ( NT_STATUS_EQUAL( nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
4832 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4834 set_domain_offline( domain
);
4842 /* the cache backend methods are exposed via this structure */
4843 struct winbindd_methods cache_methods
= {
4861 static bool wcache_ndr_key(TALLOC_CTX
*mem_ctx
, char *domain_name
,
4862 uint32_t opnum
, const DATA_BLOB
*req
,
4868 key
= talloc_asprintf(mem_ctx
, "NDR/%s/%d/", domain_name
, (int)opnum
);
4872 keylen
= talloc_get_size(key
) - 1;
4874 key
= talloc_realloc(mem_ctx
, key
, char, keylen
+ req
->length
);
4878 memcpy(key
+ keylen
, req
->data
, req
->length
);
4880 pkey
->dptr
= (uint8_t *)key
;
4881 pkey
->dsize
= talloc_get_size(key
);
4885 static bool wcache_opnum_cacheable(uint32_t opnum
)
4888 case NDR_WBINT_PING
:
4889 case NDR_WBINT_QUERYSEQUENCENUMBER
:
4890 case NDR_WBINT_ALLOCATEUID
:
4891 case NDR_WBINT_ALLOCATEGID
:
4892 case NDR_WBINT_CHECKMACHINEACCOUNT
:
4893 case NDR_WBINT_CHANGEMACHINEACCOUNT
:
4894 case NDR_WBINT_PINGDC
:
4900 bool wcache_fetch_ndr(TALLOC_CTX
*mem_ctx
, struct winbindd_domain
*domain
,
4901 uint32_t opnum
, const DATA_BLOB
*req
, DATA_BLOB
*resp
)
4906 if (!wcache_opnum_cacheable(opnum
) ||
4907 is_my_own_sam_domain(domain
) ||
4908 is_builtin_domain(domain
)) {
4912 if (wcache
->tdb
== NULL
) {
4916 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4919 data
= tdb_fetch_compat(wcache
->tdb
, key
);
4920 TALLOC_FREE(key
.dptr
);
4922 if (data
.dptr
== NULL
) {
4925 if (data
.dsize
< 12) {
4929 if (!is_domain_offline(domain
)) {
4930 uint32_t entry_seqnum
, dom_seqnum
, last_check
;
4931 uint64_t entry_timeout
;
4933 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
,
4937 entry_seqnum
= IVAL(data
.dptr
, 0);
4938 if (entry_seqnum
!= dom_seqnum
) {
4939 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4940 (int)entry_seqnum
));
4943 entry_timeout
= BVAL(data
.dptr
, 4);
4944 if (time(NULL
) > entry_timeout
) {
4945 DEBUG(10, ("Entry has timed out\n"));
4950 resp
->data
= (uint8_t *)talloc_memdup(mem_ctx
, data
.dptr
+ 12,
4952 if (resp
->data
== NULL
) {
4953 DEBUG(10, ("talloc failed\n"));
4956 resp
->length
= data
.dsize
- 12;
4960 SAFE_FREE(data
.dptr
);
4964 void wcache_store_ndr(struct winbindd_domain
*domain
, uint32_t opnum
,
4965 const DATA_BLOB
*req
, const DATA_BLOB
*resp
)
4968 uint32_t dom_seqnum
, last_check
;
4971 if (!wcache_opnum_cacheable(opnum
) ||
4972 is_my_own_sam_domain(domain
) ||
4973 is_builtin_domain(domain
)) {
4977 if (wcache
->tdb
== NULL
) {
4981 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
, &last_check
)) {
4982 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4987 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4991 timeout
= time(NULL
) + lp_winbind_cache_time();
4993 data
.dsize
= resp
->length
+ 12;
4994 data
.dptr
= talloc_array(key
.dptr
, uint8_t, data
.dsize
);
4995 if (data
.dptr
== NULL
) {
4999 SIVAL(data
.dptr
, 0, dom_seqnum
);
5000 SBVAL(data
.dptr
, 4, timeout
);
5001 memcpy(data
.dptr
+ 12, resp
->data
, resp
->length
);
5003 tdb_store(wcache
->tdb
, key
, data
, 0);
5006 TALLOC_FREE(key
.dptr
);