2 Unix SMB/CIFS implementation.
4 Winbind cache backend functions
6 Copyright (C) Andrew Tridgell 2001
7 Copyright (C) Gerald Carter 2003-2007
8 Copyright (C) Volker Lendecke 2005
9 Copyright (C) Guenther Deschner 2005
10 Copyright (C) Michael Adam 2007
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include "system/filesys.h"
29 #include "tdb_validate.h"
30 #include "../libcli/auth/libcli_auth.h"
31 #include "../librpc/gen_ndr/ndr_wbint.h"
34 #include "../libcli/security/security.h"
35 #include "passdb/machine_sid.h"
39 #define DBGC_CLASS DBGC_WINBIND
41 #define WINBINDD_CACHE_VER1 1 /* initial db version */
42 #define WINBINDD_CACHE_VER2 2 /* second version with timeouts for NDR entries */
44 #define WINBINDD_CACHE_VERSION WINBINDD_CACHE_VER2
45 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
47 extern struct winbindd_methods reconnect_methods
;
49 extern struct winbindd_methods ads_methods
;
51 extern struct winbindd_methods builtin_passdb_methods
;
52 extern struct winbindd_methods sam_passdb_methods
;
55 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
56 * Here are the list of entry types that are *not* stored
57 * as form struct cache_entry in the cache.
60 static const char *non_centry_keys
[] = {
63 WINBINDD_CACHE_VERSION_KEYSTR
,
67 /************************************************************************
68 Is this key a non-centry type ?
69 ************************************************************************/
71 static bool is_non_centry_key(TDB_DATA kbuf
)
75 if (kbuf
.dptr
== NULL
|| kbuf
.dsize
== 0) {
78 for (i
= 0; non_centry_keys
[i
] != NULL
; i
++) {
79 size_t namelen
= strlen(non_centry_keys
[i
]);
80 if (kbuf
.dsize
< namelen
) {
83 if (strncmp(non_centry_keys
[i
], (const char *)kbuf
.dptr
, namelen
) == 0) {
90 /* Global online/offline state - False when online. winbindd starts up online
91 and sets this to true if the first query fails and there's an entry in
92 the cache tdb telling us to stay offline. */
94 static bool global_winbindd_offline_state
;
96 struct winbind_cache
{
102 uint32 sequence_number
;
108 void (*smb_panic_fn
)(const char *const why
) = smb_panic
;
110 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
112 static struct winbind_cache
*wcache
;
114 /* get the winbind_cache structure */
115 static struct winbind_cache
*get_cache(struct winbindd_domain
*domain
)
117 struct winbind_cache
*ret
= wcache
;
119 /* We have to know what type of domain we are dealing with first. */
121 if (domain
->internal
) {
122 domain
->backend
= &builtin_passdb_methods
;
123 domain
->initialized
= True
;
126 if (strequal(domain
->name
, get_global_sam_name()) &&
127 sid_check_is_our_sam(&domain
->sid
)) {
128 domain
->backend
= &sam_passdb_methods
;
129 domain
->initialized
= True
;
132 if ( !domain
->initialized
) {
133 init_dc_connection( domain
);
137 OK. listen up becasue I'm only going to say this once.
138 We have the following scenarios to consider
139 (a) trusted AD domains on a Samba DC,
140 (b) trusted AD domains and we are joined to a non-kerberos domain
141 (c) trusted AD domains and we are joined to a kerberos (AD) domain
143 For (a) we can always contact the trusted domain using krb5
144 since we have the domain trust account password
146 For (b) we can only use RPC since we have no way of
147 getting a krb5 ticket in our own domain
149 For (c) we can always use krb5 since we have a kerberos trust
154 if (!domain
->backend
) {
156 struct winbindd_domain
*our_domain
= domain
;
158 /* find our domain first so we can figure out if we
159 are joined to a kerberized domain */
161 if ( !domain
->primary
)
162 our_domain
= find_our_domain();
164 if ((our_domain
->active_directory
|| IS_DC
)
165 && domain
->active_directory
166 && !lp_winbind_rpc_only()) {
167 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain
->name
));
168 domain
->backend
= &ads_methods
;
170 #endif /* HAVE_ADS */
171 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain
->name
));
172 domain
->backend
= &reconnect_methods
;
175 #endif /* HAVE_ADS */
181 ret
= SMB_XMALLOC_P(struct winbind_cache
);
185 wcache_flush_cache();
191 free a centry structure
193 static void centry_free(struct cache_entry
*centry
)
197 SAFE_FREE(centry
->data
);
201 static bool centry_check_bytes(struct cache_entry
*centry
, size_t nbytes
)
203 if (centry
->len
- centry
->ofs
< nbytes
) {
204 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
205 (unsigned int)nbytes
,
206 centry
->len
- centry
->ofs
));
213 pull a uint64_t from a cache entry
215 static uint64_t centry_uint64_t(struct cache_entry
*centry
)
219 if (!centry_check_bytes(centry
, 8)) {
220 smb_panic_fn("centry_uint64_t");
222 ret
= BVAL(centry
->data
, centry
->ofs
);
228 pull a uint32 from a cache entry
230 static uint32
centry_uint32(struct cache_entry
*centry
)
234 if (!centry_check_bytes(centry
, 4)) {
235 smb_panic_fn("centry_uint32");
237 ret
= IVAL(centry
->data
, centry
->ofs
);
243 pull a uint16 from a cache entry
245 static uint16
centry_uint16(struct cache_entry
*centry
)
248 if (!centry_check_bytes(centry
, 2)) {
249 smb_panic_fn("centry_uint16");
251 ret
= SVAL(centry
->data
, centry
->ofs
);
257 pull a uint8 from a cache entry
259 static uint8
centry_uint8(struct cache_entry
*centry
)
262 if (!centry_check_bytes(centry
, 1)) {
263 smb_panic_fn("centry_uint8");
265 ret
= CVAL(centry
->data
, centry
->ofs
);
271 pull a NTTIME from a cache entry
273 static NTTIME
centry_nttime(struct cache_entry
*centry
)
276 if (!centry_check_bytes(centry
, 8)) {
277 smb_panic_fn("centry_nttime");
279 ret
= IVAL(centry
->data
, centry
->ofs
);
281 ret
+= (uint64
)IVAL(centry
->data
, centry
->ofs
) << 32;
287 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
289 static time_t centry_time(struct cache_entry
*centry
)
291 return (time_t)centry_nttime(centry
);
294 /* pull a string from a cache entry, using the supplied
297 static char *centry_string(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
302 len
= centry_uint8(centry
);
305 /* a deliberate NULL string */
309 if (!centry_check_bytes(centry
, (size_t)len
)) {
310 smb_panic_fn("centry_string");
313 ret
= talloc_array(mem_ctx
, char, len
+1);
315 smb_panic_fn("centry_string out of memory\n");
317 memcpy(ret
,centry
->data
+ centry
->ofs
, len
);
323 /* pull a hash16 from a cache entry, using the supplied
326 static char *centry_hash16(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
331 len
= centry_uint8(centry
);
334 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
339 if (!centry_check_bytes(centry
, 16)) {
343 ret
= talloc_array(mem_ctx
, char, 16);
345 smb_panic_fn("centry_hash out of memory\n");
347 memcpy(ret
,centry
->data
+ centry
->ofs
, 16);
352 /* pull a sid from a cache entry, using the supplied
355 static bool centry_sid(struct cache_entry
*centry
, struct dom_sid
*sid
)
360 sid_string
= centry_string(centry
, talloc_tos());
361 if (sid_string
== NULL
) {
364 ret
= string_to_sid(sid
, sid_string
);
365 TALLOC_FREE(sid_string
);
371 pull a NTSTATUS from a cache entry
373 static NTSTATUS
centry_ntstatus(struct cache_entry
*centry
)
377 status
= NT_STATUS(centry_uint32(centry
));
382 /* the server is considered down if it can't give us a sequence number */
383 static bool wcache_server_down(struct winbindd_domain
*domain
)
390 ret
= (domain
->sequence_number
== DOM_SEQUENCE_NONE
);
393 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
398 static bool wcache_fetch_seqnum(const char *domain_name
, uint32_t *seqnum
,
399 uint32_t *last_seq_check
)
404 if (wcache
->tdb
== NULL
) {
405 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
409 key
= talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name
);
411 DEBUG(10, ("talloc failed\n"));
415 data
= tdb_fetch_bystring(wcache
->tdb
, key
);
418 if (data
.dptr
== NULL
) {
419 DEBUG(10, ("wcache_fetch_seqnum: %s not found\n",
423 if (data
.dsize
!= 8) {
424 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
426 SAFE_FREE(data
.dptr
);
430 *seqnum
= IVAL(data
.dptr
, 0);
431 *last_seq_check
= IVAL(data
.dptr
, 4);
432 SAFE_FREE(data
.dptr
);
437 static NTSTATUS
fetch_cache_seqnum( struct winbindd_domain
*domain
, time_t now
)
439 uint32 last_check
, time_diff
;
441 if (!wcache_fetch_seqnum(domain
->name
, &domain
->sequence_number
,
443 return NT_STATUS_UNSUCCESSFUL
;
445 domain
->last_seq_check
= last_check
;
447 /* have we expired? */
449 time_diff
= now
- domain
->last_seq_check
;
450 if ( time_diff
> lp_winbind_cache_time() ) {
451 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
452 domain
->name
, domain
->sequence_number
,
453 (uint32
)domain
->last_seq_check
));
454 return NT_STATUS_UNSUCCESSFUL
;
457 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
458 domain
->name
, domain
->sequence_number
,
459 (uint32
)domain
->last_seq_check
));
464 bool wcache_store_seqnum(const char *domain_name
, uint32_t seqnum
,
465 time_t last_seq_check
)
471 if (wcache
->tdb
== NULL
) {
472 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
476 key_str
= talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name
);
477 if (key_str
== NULL
) {
478 DEBUG(10, ("talloc_asprintf failed\n"));
482 SIVAL(buf
, 0, seqnum
);
483 SIVAL(buf
, 4, last_seq_check
);
485 ret
= tdb_store_bystring(wcache
->tdb
, key_str
,
486 make_tdb_data(buf
, sizeof(buf
)), TDB_REPLACE
);
487 TALLOC_FREE(key_str
);
489 DEBUG(10, ("tdb_store_bystring failed: %s\n",
490 tdb_errorstr_compat(wcache
->tdb
)));
491 TALLOC_FREE(key_str
);
495 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
496 domain_name
, seqnum
, (unsigned)last_seq_check
));
501 static bool store_cache_seqnum( struct winbindd_domain
*domain
)
503 return wcache_store_seqnum(domain
->name
, domain
->sequence_number
,
504 domain
->last_seq_check
);
508 refresh the domain sequence number. If force is true
509 then always refresh it, no matter how recently we fetched it
512 static void refresh_sequence_number(struct winbindd_domain
*domain
, bool force
)
516 time_t t
= time(NULL
);
517 unsigned cache_time
= lp_winbind_cache_time();
519 if (is_domain_offline(domain
)) {
525 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
526 /* trying to reconnect is expensive, don't do it too often */
527 if (domain
->sequence_number
== DOM_SEQUENCE_NONE
) {
532 time_diff
= t
- domain
->last_seq_check
;
534 /* see if we have to refetch the domain sequence number */
535 if (!force
&& (time_diff
< cache_time
) &&
536 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
537 NT_STATUS_IS_OK(domain
->last_status
)) {
538 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain
->name
));
542 /* try to get the sequence number from the tdb cache first */
543 /* this will update the timestamp as well */
545 status
= fetch_cache_seqnum( domain
, t
);
546 if (NT_STATUS_IS_OK(status
) &&
547 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
548 NT_STATUS_IS_OK(domain
->last_status
)) {
552 /* important! make sure that we know if this is a native
553 mode domain or not. And that we can contact it. */
555 if ( winbindd_can_contact_domain( domain
) ) {
556 status
= domain
->backend
->sequence_number(domain
,
557 &domain
->sequence_number
);
559 /* just use the current time */
560 status
= NT_STATUS_OK
;
561 domain
->sequence_number
= time(NULL
);
565 /* the above call could have set our domain->backend to NULL when
566 * coming from offline to online mode, make sure to reinitialize the
567 * backend - Guenther */
570 if (!NT_STATUS_IS_OK(status
)) {
571 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status
)));
572 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
575 domain
->last_status
= status
;
576 domain
->last_seq_check
= time(NULL
);
578 /* save the new sequence number in the cache */
579 store_cache_seqnum( domain
);
582 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
583 domain
->name
, domain
->sequence_number
));
589 decide if a cache entry has expired
591 static bool centry_expired(struct winbindd_domain
*domain
, const char *keystr
, struct cache_entry
*centry
)
593 /* If we've been told to be offline - stay in that state... */
594 if (lp_winbind_offline_logon() && global_winbindd_offline_state
) {
595 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
596 keystr
, domain
->name
));
600 /* when the domain is offline return the cached entry.
601 * This deals with transient offline states... */
603 if (!domain
->online
) {
604 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
605 keystr
, domain
->name
));
609 /* if the server is OK and our cache entry came from when it was down then
610 the entry is invalid */
611 if ((domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
612 (centry
->sequence_number
== DOM_SEQUENCE_NONE
)) {
613 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
614 keystr
, domain
->name
));
618 /* if the server is down or the cache entry is not older than the
619 current sequence number or it did not timeout then it is OK */
620 if (wcache_server_down(domain
)
621 || ((centry
->sequence_number
== domain
->sequence_number
)
622 && (centry
->timeout
> time(NULL
)))) {
623 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
624 keystr
, domain
->name
));
628 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
629 keystr
, domain
->name
));
635 static struct cache_entry
*wcache_fetch_raw(char *kstr
)
638 struct cache_entry
*centry
;
641 key
= string_tdb_data(kstr
);
642 data
= tdb_fetch_compat(wcache
->tdb
, key
);
648 centry
= SMB_XMALLOC_P(struct cache_entry
);
649 centry
->data
= (unsigned char *)data
.dptr
;
650 centry
->len
= data
.dsize
;
653 if (centry
->len
< 16) {
654 /* huh? corrupt cache? */
655 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s "
656 "(len < 16)?\n", kstr
));
661 centry
->status
= centry_ntstatus(centry
);
662 centry
->sequence_number
= centry_uint32(centry
);
663 centry
->timeout
= centry_uint64_t(centry
);
668 static bool is_my_own_sam_domain(struct winbindd_domain
*domain
)
670 if (strequal(domain
->name
, get_global_sam_name()) &&
671 sid_check_is_our_sam(&domain
->sid
)) {
678 static bool is_builtin_domain(struct winbindd_domain
*domain
)
680 if (strequal(domain
->name
, "BUILTIN") &&
681 sid_check_is_builtin(&domain
->sid
)) {
689 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
690 number and return status
692 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
693 struct winbindd_domain
*domain
,
694 const char *format
, ...) PRINTF_ATTRIBUTE(3,4);
695 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
696 struct winbindd_domain
*domain
,
697 const char *format
, ...)
701 struct cache_entry
*centry
;
703 if (!winbindd_use_cache() ||
704 is_my_own_sam_domain(domain
) ||
705 is_builtin_domain(domain
)) {
709 refresh_sequence_number(domain
, false);
711 va_start(ap
, format
);
712 smb_xvasprintf(&kstr
, format
, ap
);
715 centry
= wcache_fetch_raw(kstr
);
716 if (centry
== NULL
) {
721 if (centry_expired(domain
, kstr
, centry
)) {
723 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
724 kstr
, domain
->name
));
731 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
732 kstr
, domain
->name
));
738 static void wcache_delete(const char *format
, ...) PRINTF_ATTRIBUTE(1,2);
739 static void wcache_delete(const char *format
, ...)
745 va_start(ap
, format
);
746 smb_xvasprintf(&kstr
, format
, ap
);
749 key
= string_tdb_data(kstr
);
751 tdb_delete(wcache
->tdb
, key
);
756 make sure we have at least len bytes available in a centry
758 static void centry_expand(struct cache_entry
*centry
, uint32 len
)
760 if (centry
->len
- centry
->ofs
>= len
)
763 centry
->data
= SMB_REALLOC_ARRAY(centry
->data
, unsigned char,
766 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry
->len
));
767 smb_panic_fn("out of memory in centry_expand");
772 push a uint64_t into a centry
774 static void centry_put_uint64_t(struct cache_entry
*centry
, uint64_t v
)
776 centry_expand(centry
, 8);
777 SBVAL(centry
->data
, centry
->ofs
, v
);
782 push a uint32 into a centry
784 static void centry_put_uint32(struct cache_entry
*centry
, uint32 v
)
786 centry_expand(centry
, 4);
787 SIVAL(centry
->data
, centry
->ofs
, v
);
792 push a uint16 into a centry
794 static void centry_put_uint16(struct cache_entry
*centry
, uint16 v
)
796 centry_expand(centry
, 2);
797 SSVAL(centry
->data
, centry
->ofs
, v
);
802 push a uint8 into a centry
804 static void centry_put_uint8(struct cache_entry
*centry
, uint8 v
)
806 centry_expand(centry
, 1);
807 SCVAL(centry
->data
, centry
->ofs
, v
);
812 push a string into a centry
814 static void centry_put_string(struct cache_entry
*centry
, const char *s
)
819 /* null strings are marked as len 0xFFFF */
820 centry_put_uint8(centry
, 0xFF);
825 /* can't handle more than 254 char strings. Truncating is probably best */
827 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len
));
830 centry_put_uint8(centry
, len
);
831 centry_expand(centry
, len
);
832 memcpy(centry
->data
+ centry
->ofs
, s
, len
);
837 push a 16 byte hash into a centry - treat as 16 byte string.
839 static void centry_put_hash16(struct cache_entry
*centry
, const uint8 val
[16])
841 centry_put_uint8(centry
, 16);
842 centry_expand(centry
, 16);
843 memcpy(centry
->data
+ centry
->ofs
, val
, 16);
847 static void centry_put_sid(struct cache_entry
*centry
, const struct dom_sid
*sid
)
850 centry_put_string(centry
, sid_to_fstring(sid_string
, sid
));
855 put NTSTATUS into a centry
857 static void centry_put_ntstatus(struct cache_entry
*centry
, NTSTATUS status
)
859 uint32 status_value
= NT_STATUS_V(status
);
860 centry_put_uint32(centry
, status_value
);
865 push a NTTIME into a centry
867 static void centry_put_nttime(struct cache_entry
*centry
, NTTIME nt
)
869 centry_expand(centry
, 8);
870 SIVAL(centry
->data
, centry
->ofs
, nt
& 0xFFFFFFFF);
872 SIVAL(centry
->data
, centry
->ofs
, nt
>> 32);
877 push a time_t into a centry - use a 64 bit size.
878 NTTIME here is being used as a convenient 64-bit size.
880 static void centry_put_time(struct cache_entry
*centry
, time_t t
)
882 NTTIME nt
= (NTTIME
)t
;
883 centry_put_nttime(centry
, nt
);
887 start a centry for output. When finished, call centry_end()
889 struct cache_entry
*centry_start(struct winbindd_domain
*domain
, NTSTATUS status
)
891 struct cache_entry
*centry
;
896 centry
= SMB_XMALLOC_P(struct cache_entry
);
898 centry
->len
= 8192; /* reasonable default */
899 centry
->data
= SMB_XMALLOC_ARRAY(uint8
, centry
->len
);
901 centry
->sequence_number
= domain
->sequence_number
;
902 centry
->timeout
= lp_winbind_cache_time() + time(NULL
);
903 centry_put_ntstatus(centry
, status
);
904 centry_put_uint32(centry
, centry
->sequence_number
);
905 centry_put_uint64_t(centry
, centry
->timeout
);
910 finish a centry and write it to the tdb
912 static void centry_end(struct cache_entry
*centry
, const char *format
, ...) PRINTF_ATTRIBUTE(2,3);
913 static void centry_end(struct cache_entry
*centry
, const char *format
, ...)
919 if (!winbindd_use_cache()) {
923 va_start(ap
, format
);
924 smb_xvasprintf(&kstr
, format
, ap
);
927 key
= string_tdb_data(kstr
);
928 data
.dptr
= centry
->data
;
929 data
.dsize
= centry
->ofs
;
931 tdb_store(wcache
->tdb
, key
, data
, TDB_REPLACE
);
935 static void wcache_save_name_to_sid(struct winbindd_domain
*domain
,
936 NTSTATUS status
, const char *domain_name
,
937 const char *name
, const struct dom_sid
*sid
,
938 enum lsa_SidType type
)
940 struct cache_entry
*centry
;
943 centry
= centry_start(domain
, status
);
946 centry_put_uint32(centry
, type
);
947 centry_put_sid(centry
, sid
);
948 fstrcpy(uname
, name
);
949 (void)strupper_m(uname
);
950 centry_end(centry
, "NS/%s/%s", domain_name
, uname
);
951 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name
,
952 uname
, sid_string_dbg(sid
), nt_errstr(status
)));
956 static void wcache_save_sid_to_name(struct winbindd_domain
*domain
, NTSTATUS status
,
957 const struct dom_sid
*sid
, const char *domain_name
, const char *name
, enum lsa_SidType type
)
959 struct cache_entry
*centry
;
962 centry
= centry_start(domain
, status
);
966 if (NT_STATUS_IS_OK(status
)) {
967 centry_put_uint32(centry
, type
);
968 centry_put_string(centry
, domain_name
);
969 centry_put_string(centry
, name
);
972 centry_end(centry
, "SN/%s", sid_to_fstring(sid_string
, sid
));
973 DEBUG(10,("wcache_save_sid_to_name: %s -> %s\\%s (%s)\n", sid_string
,
974 domain_name
, name
, nt_errstr(status
)));
979 static void wcache_save_user(struct winbindd_domain
*domain
, NTSTATUS status
,
980 struct wbint_userinfo
*info
)
982 struct cache_entry
*centry
;
985 if (is_null_sid(&info
->user_sid
)) {
989 centry
= centry_start(domain
, status
);
992 centry_put_string(centry
, info
->acct_name
);
993 centry_put_string(centry
, info
->full_name
);
994 centry_put_string(centry
, info
->homedir
);
995 centry_put_string(centry
, info
->shell
);
996 centry_put_uint32(centry
, info
->primary_gid
);
997 centry_put_sid(centry
, &info
->user_sid
);
998 centry_put_sid(centry
, &info
->group_sid
);
999 centry_end(centry
, "U/%s", sid_to_fstring(sid_string
,
1001 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string
, info
->acct_name
));
1002 centry_free(centry
);
1005 static void wcache_save_lockout_policy(struct winbindd_domain
*domain
,
1007 struct samr_DomInfo12
*lockout_policy
)
1009 struct cache_entry
*centry
;
1011 centry
= centry_start(domain
, status
);
1015 centry_put_nttime(centry
, lockout_policy
->lockout_duration
);
1016 centry_put_nttime(centry
, lockout_policy
->lockout_window
);
1017 centry_put_uint16(centry
, lockout_policy
->lockout_threshold
);
1019 centry_end(centry
, "LOC_POL/%s", domain
->name
);
1021 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain
->name
));
1023 centry_free(centry
);
1028 static void wcache_save_password_policy(struct winbindd_domain
*domain
,
1030 struct samr_DomInfo1
*policy
)
1032 struct cache_entry
*centry
;
1034 centry
= centry_start(domain
, status
);
1038 centry_put_uint16(centry
, policy
->min_password_length
);
1039 centry_put_uint16(centry
, policy
->password_history_length
);
1040 centry_put_uint32(centry
, policy
->password_properties
);
1041 centry_put_nttime(centry
, policy
->max_password_age
);
1042 centry_put_nttime(centry
, policy
->min_password_age
);
1044 centry_end(centry
, "PWD_POL/%s", domain
->name
);
1046 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
1048 centry_free(centry
);
1051 /***************************************************************************
1052 ***************************************************************************/
1054 static void wcache_save_username_alias(struct winbindd_domain
*domain
,
1056 const char *name
, const char *alias
)
1058 struct cache_entry
*centry
;
1061 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1064 centry_put_string( centry
, alias
);
1066 fstrcpy(uname
, name
);
1067 (void)strupper_m(uname
);
1068 centry_end(centry
, "NSS/NA/%s", uname
);
1070 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name
, alias
));
1072 centry_free(centry
);
1075 static void wcache_save_alias_username(struct winbindd_domain
*domain
,
1077 const char *alias
, const char *name
)
1079 struct cache_entry
*centry
;
1082 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1085 centry_put_string( centry
, name
);
1087 fstrcpy(uname
, alias
);
1088 (void)strupper_m(uname
);
1089 centry_end(centry
, "NSS/AN/%s", uname
);
1091 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias
, name
));
1093 centry_free(centry
);
1096 /***************************************************************************
1097 ***************************************************************************/
1099 NTSTATUS
resolve_username_to_alias( TALLOC_CTX
*mem_ctx
,
1100 struct winbindd_domain
*domain
,
1101 const char *name
, char **alias
)
1103 struct winbind_cache
*cache
= get_cache(domain
);
1104 struct cache_entry
*centry
= NULL
;
1108 if ( domain
->internal
)
1109 return NT_STATUS_NOT_SUPPORTED
;
1114 if ( (upper_name
= SMB_STRDUP(name
)) == NULL
)
1115 return NT_STATUS_NO_MEMORY
;
1116 if (!strupper_m(upper_name
)) {
1117 SAFE_FREE(upper_name
);
1118 return NT_STATUS_INVALID_PARAMETER
;
1121 centry
= wcache_fetch(cache
, domain
, "NSS/NA/%s", upper_name
);
1123 SAFE_FREE( upper_name
);
1128 status
= centry
->status
;
1130 if (!NT_STATUS_IS_OK(status
)) {
1131 centry_free(centry
);
1135 *alias
= centry_string( centry
, mem_ctx
);
1137 centry_free(centry
);
1139 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1140 name
, *alias
? *alias
: "(none)"));
1142 return (*alias
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1146 /* If its not in cache and we are offline, then fail */
1148 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1149 DEBUG(8,("resolve_username_to_alias: rejecting query "
1150 "in offline mode\n"));
1151 return NT_STATUS_NOT_FOUND
;
1154 status
= nss_map_to_alias( mem_ctx
, domain
->name
, name
, alias
);
1156 if ( NT_STATUS_IS_OK( status
) ) {
1157 wcache_save_username_alias(domain
, status
, name
, *alias
);
1160 if ( NT_STATUS_EQUAL( status
, NT_STATUS_NONE_MAPPED
) ) {
1161 wcache_save_username_alias(domain
, status
, name
, "(NULL)");
1164 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1165 nt_errstr(status
)));
1167 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1168 set_domain_offline( domain
);
1174 /***************************************************************************
1175 ***************************************************************************/
1177 NTSTATUS
resolve_alias_to_username( TALLOC_CTX
*mem_ctx
,
1178 struct winbindd_domain
*domain
,
1179 const char *alias
, char **name
)
1181 struct winbind_cache
*cache
= get_cache(domain
);
1182 struct cache_entry
*centry
= NULL
;
1186 if ( domain
->internal
)
1187 return NT_STATUS_NOT_SUPPORTED
;
1192 if ( (upper_name
= SMB_STRDUP(alias
)) == NULL
)
1193 return NT_STATUS_NO_MEMORY
;
1194 if (!strupper_m(upper_name
)) {
1195 SAFE_FREE(upper_name
);
1196 return NT_STATUS_INVALID_PARAMETER
;
1199 centry
= wcache_fetch(cache
, domain
, "NSS/AN/%s", upper_name
);
1201 SAFE_FREE( upper_name
);
1206 status
= centry
->status
;
1208 if (!NT_STATUS_IS_OK(status
)) {
1209 centry_free(centry
);
1213 *name
= centry_string( centry
, mem_ctx
);
1215 centry_free(centry
);
1217 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1218 alias
, *name
? *name
: "(none)"));
1220 return (*name
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1224 /* If its not in cache and we are offline, then fail */
1226 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1227 DEBUG(8,("resolve_alias_to_username: rejecting query "
1228 "in offline mode\n"));
1229 return NT_STATUS_NOT_FOUND
;
1232 /* an alias cannot contain a domain prefix or '@' */
1234 if (strchr(alias
, '\\') || strchr(alias
, '@')) {
1235 DEBUG(10,("resolve_alias_to_username: skipping fully "
1236 "qualified name %s\n", alias
));
1237 return NT_STATUS_OBJECT_NAME_INVALID
;
1240 status
= nss_map_from_alias( mem_ctx
, domain
->name
, alias
, name
);
1242 if ( NT_STATUS_IS_OK( status
) ) {
1243 wcache_save_alias_username( domain
, status
, alias
, *name
);
1246 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1247 wcache_save_alias_username(domain
, status
, alias
, "(NULL)");
1250 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1251 nt_errstr(status
)));
1253 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1254 set_domain_offline( domain
);
1260 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
1262 struct winbind_cache
*cache
= get_cache(domain
);
1264 fstring key_str
, tmp
;
1268 return NT_STATUS_INTERNAL_DB_ERROR
;
1271 if (is_null_sid(sid
)) {
1272 return NT_STATUS_INVALID_SID
;
1275 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1276 return NT_STATUS_INVALID_SID
;
1279 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
1281 data
= tdb_fetch_compat(cache
->tdb
, string_tdb_data(key_str
));
1283 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1286 SAFE_FREE(data
.dptr
);
1287 return NT_STATUS_OK
;
1290 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1291 as new salted ones. */
1293 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
1294 TALLOC_CTX
*mem_ctx
,
1295 const struct dom_sid
*sid
,
1296 const uint8
**cached_nt_pass
,
1297 const uint8
**cached_salt
)
1299 struct winbind_cache
*cache
= get_cache(domain
);
1300 struct cache_entry
*centry
= NULL
;
1306 return NT_STATUS_INTERNAL_DB_ERROR
;
1309 if (is_null_sid(sid
)) {
1310 return NT_STATUS_INVALID_SID
;
1313 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1314 return NT_STATUS_INVALID_SID
;
1317 /* Try and get a salted cred first. If we can't
1318 fall back to an unsalted cred. */
1320 centry
= wcache_fetch(cache
, domain
, "CRED/%s",
1321 sid_to_fstring(tmp
, sid
));
1323 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1324 sid_string_dbg(sid
)));
1325 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1329 * We don't use the time element at this moment,
1330 * but we have to consume it, so that we don't
1331 * neet to change the disk format of the cache.
1333 (void)centry_time(centry
);
1335 /* In the salted case this isn't actually the nt_hash itself,
1336 but the MD5 of the salt + nt_hash. Let the caller
1337 sort this out. It can tell as we only return the cached_salt
1338 if we are returning a salted cred. */
1340 *cached_nt_pass
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1341 if (*cached_nt_pass
== NULL
) {
1344 sid_to_fstring(sidstr
, sid
);
1346 /* Bad (old) cred cache. Delete and pretend we
1348 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1350 wcache_delete("CRED/%s", sidstr
);
1351 centry_free(centry
);
1352 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1355 /* We only have 17 bytes more data in the salted cred case. */
1356 if (centry
->len
- centry
->ofs
== 17) {
1357 *cached_salt
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1359 *cached_salt
= NULL
;
1362 dump_data_pw("cached_nt_pass", *cached_nt_pass
, NT_HASH_LEN
);
1364 dump_data_pw("cached_salt", *cached_salt
, NT_HASH_LEN
);
1367 status
= centry
->status
;
1369 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1370 sid_string_dbg(sid
), nt_errstr(status
) ));
1372 centry_free(centry
);
1376 /* Store creds for a SID - only writes out new salted ones. */
1378 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1379 const struct dom_sid
*sid
,
1380 const uint8 nt_pass
[NT_HASH_LEN
])
1382 struct cache_entry
*centry
;
1385 uint8 cred_salt
[NT_HASH_LEN
];
1386 uint8 salted_hash
[NT_HASH_LEN
];
1388 if (is_null_sid(sid
)) {
1389 return NT_STATUS_INVALID_SID
;
1392 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1393 return NT_STATUS_INVALID_SID
;
1396 centry
= centry_start(domain
, NT_STATUS_OK
);
1398 return NT_STATUS_INTERNAL_DB_ERROR
;
1401 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1403 centry_put_time(centry
, time(NULL
));
1405 /* Create a salt and then salt the hash. */
1406 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1407 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1409 centry_put_hash16(centry
, salted_hash
);
1410 centry_put_hash16(centry
, cred_salt
);
1411 centry_end(centry
, "CRED/%s", sid_to_fstring(sid_string
, sid
));
1413 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1415 centry_free(centry
);
1417 return NT_STATUS_OK
;
1421 /* Query display info. This is the basic user list fn */
1422 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
1423 TALLOC_CTX
*mem_ctx
,
1424 uint32
*num_entries
,
1425 struct wbint_userinfo
**info
)
1427 struct winbind_cache
*cache
= get_cache(domain
);
1428 struct cache_entry
*centry
= NULL
;
1430 unsigned int i
, retry
;
1431 bool old_status
= domain
->online
;
1436 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1441 *num_entries
= centry_uint32(centry
);
1443 if (*num_entries
== 0)
1446 (*info
) = talloc_array(mem_ctx
, struct wbint_userinfo
, *num_entries
);
1448 smb_panic_fn("query_user_list out of memory");
1450 for (i
=0; i
<(*num_entries
); i
++) {
1451 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
1452 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
1453 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
1454 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
1455 centry_sid(centry
, &(*info
)[i
].user_sid
);
1456 centry_sid(centry
, &(*info
)[i
].group_sid
);
1460 status
= centry
->status
;
1462 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1463 domain
->name
, nt_errstr(status
) ));
1465 centry_free(centry
);
1472 /* Return status value returned by seq number check */
1474 if (!NT_STATUS_IS_OK(domain
->last_status
))
1475 return domain
->last_status
;
1477 /* Put the query_user_list() in a retry loop. There appears to be
1478 * some bug either with Windows 2000 or Samba's handling of large
1479 * rpc replies. This manifests itself as sudden disconnection
1480 * at a random point in the enumeration of a large (60k) user list.
1481 * The retry loop simply tries the operation again. )-: It's not
1482 * pretty but an acceptable workaround until we work out what the
1483 * real problem is. */
1488 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1491 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
1492 if (!NT_STATUS_IS_OK(status
)) {
1493 DEBUG(3, ("query_user_list: returned 0x%08x, "
1494 "retrying\n", NT_STATUS_V(status
)));
1496 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1497 DEBUG(3, ("query_user_list: flushing "
1498 "connection cache\n"));
1499 invalidate_cm_connection(&domain
->conn
);
1501 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1502 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1503 if (!domain
->internal
&& old_status
) {
1504 set_domain_offline(domain
);
1506 /* store partial response. */
1507 if (*num_entries
> 0) {
1509 * humm, what about the status used for cache?
1510 * Should it be NT_STATUS_OK?
1515 * domain is offline now, and there is no user entries,
1516 * try to fetch from cache again.
1518 if (cache
->tdb
&& !domain
->online
&& !domain
->internal
&& old_status
) {
1519 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1520 /* partial response... */
1524 goto do_fetch_cache
;
1531 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1535 refresh_sequence_number(domain
, false);
1536 if (!NT_STATUS_IS_OK(status
)) {
1539 centry
= centry_start(domain
, status
);
1542 centry_put_uint32(centry
, *num_entries
);
1543 for (i
=0; i
<(*num_entries
); i
++) {
1544 centry_put_string(centry
, (*info
)[i
].acct_name
);
1545 centry_put_string(centry
, (*info
)[i
].full_name
);
1546 centry_put_string(centry
, (*info
)[i
].homedir
);
1547 centry_put_string(centry
, (*info
)[i
].shell
);
1548 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1549 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1550 if (domain
->backend
&& domain
->backend
->consistent
) {
1551 /* when the backend is consistent we can pre-prime some mappings */
1552 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1554 (*info
)[i
].acct_name
,
1555 &(*info
)[i
].user_sid
,
1557 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1558 &(*info
)[i
].user_sid
,
1560 (*info
)[i
].acct_name
,
1562 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1565 centry_end(centry
, "UL/%s", domain
->name
);
1566 centry_free(centry
);
1572 /* list all domain groups */
1573 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
1574 TALLOC_CTX
*mem_ctx
,
1575 uint32
*num_entries
,
1576 struct wb_acct_info
**info
)
1578 struct winbind_cache
*cache
= get_cache(domain
);
1579 struct cache_entry
*centry
= NULL
;
1584 old_status
= domain
->online
;
1588 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1593 *num_entries
= centry_uint32(centry
);
1595 if (*num_entries
== 0)
1598 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1600 smb_panic_fn("enum_dom_groups out of memory");
1602 for (i
=0; i
<(*num_entries
); i
++) {
1603 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1604 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1605 (*info
)[i
].rid
= centry_uint32(centry
);
1609 status
= centry
->status
;
1611 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1612 domain
->name
, nt_errstr(status
) ));
1614 centry_free(centry
);
1621 /* Return status value returned by seq number check */
1623 if (!NT_STATUS_IS_OK(domain
->last_status
))
1624 return domain
->last_status
;
1626 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1629 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1631 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1632 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1633 if (!domain
->internal
&& old_status
) {
1634 set_domain_offline(domain
);
1638 !domain
->internal
&&
1640 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1642 goto do_fetch_cache
;
1647 refresh_sequence_number(domain
, false);
1648 if (!NT_STATUS_IS_OK(status
)) {
1651 centry
= centry_start(domain
, status
);
1654 centry_put_uint32(centry
, *num_entries
);
1655 for (i
=0; i
<(*num_entries
); i
++) {
1656 centry_put_string(centry
, (*info
)[i
].acct_name
);
1657 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1658 centry_put_uint32(centry
, (*info
)[i
].rid
);
1660 centry_end(centry
, "GL/%s/domain", domain
->name
);
1661 centry_free(centry
);
1667 /* list all domain groups */
1668 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
1669 TALLOC_CTX
*mem_ctx
,
1670 uint32
*num_entries
,
1671 struct wb_acct_info
**info
)
1673 struct winbind_cache
*cache
= get_cache(domain
);
1674 struct cache_entry
*centry
= NULL
;
1679 old_status
= domain
->online
;
1683 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1688 *num_entries
= centry_uint32(centry
);
1690 if (*num_entries
== 0)
1693 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1695 smb_panic_fn("enum_dom_groups out of memory");
1697 for (i
=0; i
<(*num_entries
); i
++) {
1698 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1699 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1700 (*info
)[i
].rid
= centry_uint32(centry
);
1705 /* If we are returning cached data and the domain controller
1706 is down then we don't know whether the data is up to date
1707 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1710 if (wcache_server_down(domain
)) {
1711 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1712 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1714 status
= centry
->status
;
1716 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1717 domain
->name
, nt_errstr(status
) ));
1719 centry_free(centry
);
1726 /* Return status value returned by seq number check */
1728 if (!NT_STATUS_IS_OK(domain
->last_status
))
1729 return domain
->last_status
;
1731 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1734 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1736 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1737 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1738 if (!domain
->internal
&& old_status
) {
1739 set_domain_offline(domain
);
1742 !domain
->internal
&&
1745 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1747 goto do_fetch_cache
;
1752 refresh_sequence_number(domain
, false);
1753 if (!NT_STATUS_IS_OK(status
)) {
1756 centry
= centry_start(domain
, status
);
1759 centry_put_uint32(centry
, *num_entries
);
1760 for (i
=0; i
<(*num_entries
); i
++) {
1761 centry_put_string(centry
, (*info
)[i
].acct_name
);
1762 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1763 centry_put_uint32(centry
, (*info
)[i
].rid
);
1765 centry_end(centry
, "GL/%s/local", domain
->name
);
1766 centry_free(centry
);
1772 NTSTATUS
wcache_name_to_sid(struct winbindd_domain
*domain
,
1773 const char *domain_name
,
1775 struct dom_sid
*sid
,
1776 enum lsa_SidType
*type
)
1778 struct winbind_cache
*cache
= get_cache(domain
);
1779 struct cache_entry
*centry
;
1783 if (cache
->tdb
== NULL
) {
1784 return NT_STATUS_NOT_FOUND
;
1787 uname
= talloc_strdup_upper(talloc_tos(), name
);
1788 if (uname
== NULL
) {
1789 return NT_STATUS_NO_MEMORY
;
1792 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1794 if (centry
== NULL
) {
1795 return NT_STATUS_NOT_FOUND
;
1798 status
= centry
->status
;
1799 if (NT_STATUS_IS_OK(status
)) {
1800 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1801 centry_sid(centry
, sid
);
1804 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1805 "%s\n", domain
->name
, nt_errstr(status
) ));
1807 centry_free(centry
);
1811 /* convert a single name to a sid in a domain */
1812 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
1813 TALLOC_CTX
*mem_ctx
,
1814 const char *domain_name
,
1817 struct dom_sid
*sid
,
1818 enum lsa_SidType
*type
)
1823 old_status
= domain
->online
;
1825 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1826 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1832 /* If the seq number check indicated that there is a problem
1833 * with this DC, then return that status... except for
1834 * access_denied. This is special because the dc may be in
1835 * "restrict anonymous = 1" mode, in which case it will deny
1836 * most unauthenticated operations, but *will* allow the LSA
1837 * name-to-sid that we try as a fallback. */
1839 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1840 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1841 return domain
->last_status
;
1843 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1846 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
,
1847 name
, flags
, sid
, type
);
1849 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1850 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1851 if (!domain
->internal
&& old_status
) {
1852 set_domain_offline(domain
);
1854 if (!domain
->internal
&&
1857 NTSTATUS cache_status
;
1858 cache_status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1859 return cache_status
;
1863 refresh_sequence_number(domain
, false);
1865 if (domain
->online
&&
1866 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1867 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1869 /* Only save the reverse mapping if this was not a UPN */
1870 if (!strchr(name
, '@')) {
1871 if (!strupper_m(discard_const_p(char, domain_name
))) {
1872 return NT_STATUS_INVALID_PARAMETER
;
1874 (void)strlower_m(discard_const_p(char, name
));
1875 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1882 NTSTATUS
wcache_sid_to_name(struct winbindd_domain
*domain
,
1883 const struct dom_sid
*sid
,
1884 TALLOC_CTX
*mem_ctx
,
1887 enum lsa_SidType
*type
)
1889 struct winbind_cache
*cache
= get_cache(domain
);
1890 struct cache_entry
*centry
;
1894 if (cache
->tdb
== NULL
) {
1895 return NT_STATUS_NOT_FOUND
;
1898 sid_string
= sid_string_tos(sid
);
1899 if (sid_string
== NULL
) {
1900 return NT_STATUS_NO_MEMORY
;
1903 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_string
);
1904 TALLOC_FREE(sid_string
);
1905 if (centry
== NULL
) {
1906 return NT_STATUS_NOT_FOUND
;
1909 if (NT_STATUS_IS_OK(centry
->status
)) {
1910 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1911 *domain_name
= centry_string(centry
, mem_ctx
);
1912 *name
= centry_string(centry
, mem_ctx
);
1915 status
= centry
->status
;
1916 centry_free(centry
);
1918 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1919 "%s\n", domain
->name
, nt_errstr(status
) ));
1924 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1926 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1927 TALLOC_CTX
*mem_ctx
,
1928 const struct dom_sid
*sid
,
1931 enum lsa_SidType
*type
)
1936 old_status
= domain
->online
;
1937 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
1939 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1944 *domain_name
= NULL
;
1946 /* If the seq number check indicated that there is a problem
1947 * with this DC, then return that status... except for
1948 * access_denied. This is special because the dc may be in
1949 * "restrict anonymous = 1" mode, in which case it will deny
1950 * most unauthenticated operations, but *will* allow the LSA
1951 * sid-to-name that we try as a fallback. */
1953 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1954 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1955 return domain
->last_status
;
1957 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1960 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1962 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1963 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1964 if (!domain
->internal
&& old_status
) {
1965 set_domain_offline(domain
);
1967 if (!domain
->internal
&&
1970 NTSTATUS cache_status
;
1971 cache_status
= wcache_sid_to_name(domain
, sid
, mem_ctx
,
1972 domain_name
, name
, type
);
1973 return cache_status
;
1977 refresh_sequence_number(domain
, false);
1978 if (!NT_STATUS_IS_OK(status
)) {
1981 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
1983 /* We can't save the name to sid mapping here, as with sid history a
1984 * later name2sid would give the wrong sid. */
1989 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
1990 TALLOC_CTX
*mem_ctx
,
1991 const struct dom_sid
*domain_sid
,
1996 enum lsa_SidType
**types
)
1998 struct winbind_cache
*cache
= get_cache(domain
);
2000 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
2005 old_status
= domain
->online
;
2006 *domain_name
= NULL
;
2014 if (num_rids
== 0) {
2015 return NT_STATUS_OK
;
2018 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2019 *types
= talloc_array(mem_ctx
, enum lsa_SidType
, num_rids
);
2021 if ((*names
== NULL
) || (*types
== NULL
)) {
2022 result
= NT_STATUS_NO_MEMORY
;
2026 have_mapped
= have_unmapped
= false;
2028 for (i
=0; i
<num_rids
; i
++) {
2030 struct cache_entry
*centry
;
2033 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2034 result
= NT_STATUS_INTERNAL_ERROR
;
2038 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2039 sid_to_fstring(tmp
, &sid
));
2044 (*types
)[i
] = SID_NAME_UNKNOWN
;
2045 (*names
)[i
] = talloc_strdup(*names
, "");
2047 if (NT_STATUS_IS_OK(centry
->status
)) {
2050 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2052 dom
= centry_string(centry
, mem_ctx
);
2053 if (*domain_name
== NULL
) {
2059 (*names
)[i
] = centry_string(centry
, *names
);
2061 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)
2062 || NT_STATUS_EQUAL(centry
->status
, STATUS_SOME_UNMAPPED
)) {
2063 have_unmapped
= true;
2066 /* something's definitely wrong */
2067 result
= centry
->status
;
2071 centry_free(centry
);
2075 return NT_STATUS_NONE_MAPPED
;
2077 if (!have_unmapped
) {
2078 return NT_STATUS_OK
;
2080 return STATUS_SOME_UNMAPPED
;
2084 TALLOC_FREE(*names
);
2085 TALLOC_FREE(*types
);
2087 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
2088 rids
, num_rids
, domain_name
,
2091 if (NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
2092 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2093 if (!domain
->internal
&& old_status
) {
2094 set_domain_offline(domain
);
2097 !domain
->internal
&&
2100 have_mapped
= have_unmapped
= false;
2102 for (i
=0; i
<num_rids
; i
++) {
2104 struct cache_entry
*centry
;
2107 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2108 result
= NT_STATUS_INTERNAL_ERROR
;
2112 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2113 sid_to_fstring(tmp
, &sid
));
2115 (*types
)[i
] = SID_NAME_UNKNOWN
;
2116 (*names
)[i
] = talloc_strdup(*names
, "");
2120 (*types
)[i
] = SID_NAME_UNKNOWN
;
2121 (*names
)[i
] = talloc_strdup(*names
, "");
2123 if (NT_STATUS_IS_OK(centry
->status
)) {
2126 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2128 dom
= centry_string(centry
, mem_ctx
);
2129 if (*domain_name
== NULL
) {
2135 (*names
)[i
] = centry_string(centry
, *names
);
2137 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)) {
2138 have_unmapped
= true;
2141 /* something's definitely wrong */
2142 result
= centry
->status
;
2146 centry_free(centry
);
2150 return NT_STATUS_NONE_MAPPED
;
2152 if (!have_unmapped
) {
2153 return NT_STATUS_OK
;
2155 return STATUS_SOME_UNMAPPED
;
2159 None of the queried rids has been found so save all negative entries
2161 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
2162 for (i
= 0; i
< num_rids
; i
++) {
2164 const char *name
= "";
2165 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
2166 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
2168 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2169 return NT_STATUS_INTERNAL_ERROR
;
2172 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2180 Some or all of the queried rids have been found.
2182 if (!NT_STATUS_IS_OK(result
) &&
2183 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
2187 refresh_sequence_number(domain
, false);
2189 for (i
=0; i
<num_rids
; i
++) {
2193 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2194 result
= NT_STATUS_INTERNAL_ERROR
;
2198 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
2199 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
2201 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2202 (*names
)[i
], (*types
)[i
]);
2208 TALLOC_FREE(*names
);
2209 TALLOC_FREE(*types
);
2213 NTSTATUS
wcache_query_user(struct winbindd_domain
*domain
,
2214 TALLOC_CTX
*mem_ctx
,
2215 const struct dom_sid
*user_sid
,
2216 struct wbint_userinfo
*info
)
2218 struct winbind_cache
*cache
= get_cache(domain
);
2219 struct cache_entry
*centry
= NULL
;
2223 if (cache
->tdb
== NULL
) {
2224 return NT_STATUS_NOT_FOUND
;
2227 sid_string
= sid_string_tos(user_sid
);
2228 if (sid_string
== NULL
) {
2229 return NT_STATUS_NO_MEMORY
;
2232 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string
);
2233 TALLOC_FREE(sid_string
);
2234 if (centry
== NULL
) {
2235 return NT_STATUS_NOT_FOUND
;
2239 * If we have an access denied cache entry and a cached info3
2240 * in the samlogon cache then do a query. This will force the
2241 * rpc back end to return the info3 data.
2244 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
) &&
2245 netsamlogon_cache_have(user_sid
)) {
2246 DEBUG(10, ("query_user: cached access denied and have cached "
2248 domain
->last_status
= NT_STATUS_OK
;
2249 centry_free(centry
);
2250 return NT_STATUS_NOT_FOUND
;
2253 /* if status is not ok then this is a negative hit
2254 and the rest of the data doesn't matter */
2255 status
= centry
->status
;
2256 if (NT_STATUS_IS_OK(status
)) {
2257 info
->acct_name
= centry_string(centry
, mem_ctx
);
2258 info
->full_name
= centry_string(centry
, mem_ctx
);
2259 info
->homedir
= centry_string(centry
, mem_ctx
);
2260 info
->shell
= centry_string(centry
, mem_ctx
);
2261 info
->primary_gid
= centry_uint32(centry
);
2262 centry_sid(centry
, &info
->user_sid
);
2263 centry_sid(centry
, &info
->group_sid
);
2266 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2267 "%s\n", domain
->name
, nt_errstr(status
) ));
2269 centry_free(centry
);
2273 /* Lookup user information from a rid */
2274 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
2275 TALLOC_CTX
*mem_ctx
,
2276 const struct dom_sid
*user_sid
,
2277 struct wbint_userinfo
*info
)
2282 old_status
= domain
->online
;
2283 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2284 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2290 /* Return status value returned by seq number check */
2292 if (!NT_STATUS_IS_OK(domain
->last_status
))
2293 return domain
->last_status
;
2295 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2298 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
2300 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2301 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2302 if (!domain
->internal
&& old_status
) {
2303 set_domain_offline(domain
);
2305 if (!domain
->internal
&&
2308 NTSTATUS cache_status
;
2309 cache_status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2310 return cache_status
;
2314 refresh_sequence_number(domain
, false);
2315 if (!NT_STATUS_IS_OK(status
)) {
2318 wcache_save_user(domain
, status
, info
);
2323 NTSTATUS
wcache_lookup_usergroups(struct winbindd_domain
*domain
,
2324 TALLOC_CTX
*mem_ctx
,
2325 const struct dom_sid
*user_sid
,
2326 uint32_t *pnum_sids
,
2327 struct dom_sid
**psids
)
2329 struct winbind_cache
*cache
= get_cache(domain
);
2330 struct cache_entry
*centry
= NULL
;
2332 uint32_t i
, num_sids
;
2333 struct dom_sid
*sids
;
2336 if (cache
->tdb
== NULL
) {
2337 return NT_STATUS_NOT_FOUND
;
2340 centry
= wcache_fetch(cache
, domain
, "UG/%s",
2341 sid_to_fstring(sid_string
, user_sid
));
2342 if (centry
== NULL
) {
2343 return NT_STATUS_NOT_FOUND
;
2346 /* If we have an access denied cache entry and a cached info3 in the
2347 samlogon cache then do a query. This will force the rpc back end
2348 to return the info3 data. */
2350 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)
2351 && netsamlogon_cache_have(user_sid
)) {
2352 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2354 domain
->last_status
= NT_STATUS_OK
;
2355 centry_free(centry
);
2356 return NT_STATUS_NOT_FOUND
;
2359 num_sids
= centry_uint32(centry
);
2360 sids
= talloc_array(mem_ctx
, struct dom_sid
, num_sids
);
2362 centry_free(centry
);
2363 return NT_STATUS_NO_MEMORY
;
2366 for (i
=0; i
<num_sids
; i
++) {
2367 centry_sid(centry
, &sids
[i
]);
2370 status
= centry
->status
;
2372 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2373 "status: %s\n", domain
->name
, nt_errstr(status
)));
2375 centry_free(centry
);
2377 *pnum_sids
= num_sids
;
2382 /* Lookup groups a user is a member of. */
2383 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
2384 TALLOC_CTX
*mem_ctx
,
2385 const struct dom_sid
*user_sid
,
2386 uint32
*num_groups
, struct dom_sid
**user_gids
)
2388 struct cache_entry
*centry
= NULL
;
2394 old_status
= domain
->online
;
2395 status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2396 num_groups
, user_gids
);
2397 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2402 (*user_gids
) = NULL
;
2404 /* Return status value returned by seq number check */
2406 if (!NT_STATUS_IS_OK(domain
->last_status
))
2407 return domain
->last_status
;
2409 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2412 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
2414 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2415 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2416 if (!domain
->internal
&& old_status
) {
2417 set_domain_offline(domain
);
2419 if (!domain
->internal
&&
2422 NTSTATUS cache_status
;
2423 cache_status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2424 num_groups
, user_gids
);
2425 return cache_status
;
2428 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
2432 refresh_sequence_number(domain
, false);
2433 if (!NT_STATUS_IS_OK(status
)) {
2436 centry
= centry_start(domain
, status
);
2440 centry_put_uint32(centry
, *num_groups
);
2441 for (i
=0; i
<(*num_groups
); i
++) {
2442 centry_put_sid(centry
, &(*user_gids
)[i
]);
2445 centry_end(centry
, "UG/%s", sid_to_fstring(sid_string
, user_sid
));
2446 centry_free(centry
);
2452 static char *wcache_make_sidlist(TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2453 const struct dom_sid
*sids
)
2458 sidlist
= talloc_strdup(mem_ctx
, "");
2459 if (sidlist
== NULL
) {
2462 for (i
=0; i
<num_sids
; i
++) {
2464 sidlist
= talloc_asprintf_append_buffer(
2465 sidlist
, "/%s", sid_to_fstring(tmp
, &sids
[i
]));
2466 if (sidlist
== NULL
) {
2473 NTSTATUS
wcache_lookup_useraliases(struct winbindd_domain
*domain
,
2474 TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2475 const struct dom_sid
*sids
,
2476 uint32_t *pnum_aliases
, uint32_t **paliases
)
2478 struct winbind_cache
*cache
= get_cache(domain
);
2479 struct cache_entry
*centry
= NULL
;
2480 uint32_t num_aliases
;
2486 if (cache
->tdb
== NULL
) {
2487 return NT_STATUS_NOT_FOUND
;
2490 if (num_sids
== 0) {
2493 return NT_STATUS_OK
;
2496 /* We need to cache indexed by the whole list of SIDs, the aliases
2497 * resulting might come from any of the SIDs. */
2499 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2500 if (sidlist
== NULL
) {
2501 return NT_STATUS_NO_MEMORY
;
2504 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2505 TALLOC_FREE(sidlist
);
2506 if (centry
== NULL
) {
2507 return NT_STATUS_NOT_FOUND
;
2510 num_aliases
= centry_uint32(centry
);
2511 aliases
= talloc_array(mem_ctx
, uint32_t, num_aliases
);
2512 if (aliases
== NULL
) {
2513 centry_free(centry
);
2514 return NT_STATUS_NO_MEMORY
;
2517 for (i
=0; i
<num_aliases
; i
++) {
2518 aliases
[i
] = centry_uint32(centry
);
2521 status
= centry
->status
;
2523 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2524 "status %s\n", domain
->name
, nt_errstr(status
)));
2526 centry_free(centry
);
2528 *pnum_aliases
= num_aliases
;
2529 *paliases
= aliases
;
2534 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
2535 TALLOC_CTX
*mem_ctx
,
2536 uint32 num_sids
, const struct dom_sid
*sids
,
2537 uint32
*num_aliases
, uint32
**alias_rids
)
2539 struct cache_entry
*centry
= NULL
;
2545 old_status
= domain
->online
;
2546 status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
2547 num_aliases
, alias_rids
);
2548 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2553 (*alias_rids
) = NULL
;
2555 if (!NT_STATUS_IS_OK(domain
->last_status
))
2556 return domain
->last_status
;
2558 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2559 "for domain %s\n", domain
->name
));
2561 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2562 if (sidlist
== NULL
) {
2563 return NT_STATUS_NO_MEMORY
;
2566 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2568 num_aliases
, alias_rids
);
2570 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2571 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2572 if (!domain
->internal
&& old_status
) {
2573 set_domain_offline(domain
);
2575 if (!domain
->internal
&&
2578 NTSTATUS cache_status
;
2579 cache_status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
,
2580 sids
, num_aliases
, alias_rids
);
2581 return cache_status
;
2585 refresh_sequence_number(domain
, false);
2586 if (!NT_STATUS_IS_OK(status
)) {
2589 centry
= centry_start(domain
, status
);
2592 centry_put_uint32(centry
, *num_aliases
);
2593 for (i
=0; i
<(*num_aliases
); i
++)
2594 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2595 centry_end(centry
, "UA%s", sidlist
);
2596 centry_free(centry
);
2602 NTSTATUS
wcache_lookup_groupmem(struct winbindd_domain
*domain
,
2603 TALLOC_CTX
*mem_ctx
,
2604 const struct dom_sid
*group_sid
,
2605 uint32_t *num_names
,
2606 struct dom_sid
**sid_mem
, char ***names
,
2607 uint32_t **name_types
)
2609 struct winbind_cache
*cache
= get_cache(domain
);
2610 struct cache_entry
*centry
= NULL
;
2615 if (cache
->tdb
== NULL
) {
2616 return NT_STATUS_NOT_FOUND
;
2619 sid_string
= sid_string_tos(group_sid
);
2620 if (sid_string
== NULL
) {
2621 return NT_STATUS_NO_MEMORY
;
2624 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_string
);
2625 TALLOC_FREE(sid_string
);
2626 if (centry
== NULL
) {
2627 return NT_STATUS_NOT_FOUND
;
2634 *num_names
= centry_uint32(centry
);
2635 if (*num_names
== 0) {
2636 centry_free(centry
);
2637 return NT_STATUS_OK
;
2640 *sid_mem
= talloc_array(mem_ctx
, struct dom_sid
, *num_names
);
2641 *names
= talloc_array(mem_ctx
, char *, *num_names
);
2642 *name_types
= talloc_array(mem_ctx
, uint32
, *num_names
);
2644 if ((*sid_mem
== NULL
) || (*names
== NULL
) || (*name_types
== NULL
)) {
2645 TALLOC_FREE(*sid_mem
);
2646 TALLOC_FREE(*names
);
2647 TALLOC_FREE(*name_types
);
2648 centry_free(centry
);
2649 return NT_STATUS_NO_MEMORY
;
2652 for (i
=0; i
<(*num_names
); i
++) {
2653 centry_sid(centry
, &(*sid_mem
)[i
]);
2654 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2655 (*name_types
)[i
] = centry_uint32(centry
);
2658 status
= centry
->status
;
2660 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2661 "status: %s\n", domain
->name
, nt_errstr(status
)));
2663 centry_free(centry
);
2667 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
2668 TALLOC_CTX
*mem_ctx
,
2669 const struct dom_sid
*group_sid
,
2670 enum lsa_SidType type
,
2672 struct dom_sid
**sid_mem
, char ***names
,
2673 uint32
**name_types
)
2675 struct cache_entry
*centry
= NULL
;
2681 old_status
= domain
->online
;
2682 status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2683 sid_mem
, names
, name_types
);
2684 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2691 (*name_types
) = NULL
;
2693 /* Return status value returned by seq number check */
2695 if (!NT_STATUS_IS_OK(domain
->last_status
))
2696 return domain
->last_status
;
2698 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2701 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
,
2703 sid_mem
, names
, name_types
);
2705 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2706 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2707 if (!domain
->internal
&& old_status
) {
2708 set_domain_offline(domain
);
2710 if (!domain
->internal
&&
2713 NTSTATUS cache_status
;
2714 cache_status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
,
2715 num_names
, sid_mem
, names
,
2717 return cache_status
;
2721 refresh_sequence_number(domain
, false);
2722 if (!NT_STATUS_IS_OK(status
)) {
2725 centry
= centry_start(domain
, status
);
2728 centry_put_uint32(centry
, *num_names
);
2729 for (i
=0; i
<(*num_names
); i
++) {
2730 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2731 centry_put_string(centry
, (*names
)[i
]);
2732 centry_put_uint32(centry
, (*name_types
)[i
]);
2734 centry_end(centry
, "GM/%s", sid_to_fstring(sid_string
, group_sid
));
2735 centry_free(centry
);
2741 /* find the sequence number for a domain */
2742 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
2744 refresh_sequence_number(domain
, false);
2746 *seq
= domain
->sequence_number
;
2748 return NT_STATUS_OK
;
2751 /* enumerate trusted domains
2752 * (we need to have the list of trustdoms in the cache when we go offline) -
2754 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
2755 TALLOC_CTX
*mem_ctx
,
2756 struct netr_DomainTrustList
*trusts
)
2759 struct winbind_cache
*cache
;
2760 struct winbindd_tdc_domain
*dom_list
= NULL
;
2761 size_t num_domains
= 0;
2762 bool retval
= false;
2766 old_status
= domain
->online
;
2768 trusts
->array
= NULL
;
2770 cache
= get_cache(domain
);
2771 if (!cache
|| !cache
->tdb
) {
2775 if (domain
->online
) {
2779 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2780 if (!retval
|| !num_domains
|| !dom_list
) {
2781 TALLOC_FREE(dom_list
);
2786 trusts
->array
= talloc_zero_array(mem_ctx
, struct netr_DomainTrust
, num_domains
);
2787 if (!trusts
->array
) {
2788 TALLOC_FREE(dom_list
);
2789 return NT_STATUS_NO_MEMORY
;
2792 for (i
= 0; i
< num_domains
; i
++) {
2793 struct netr_DomainTrust
*trust
;
2794 struct dom_sid
*sid
;
2795 struct winbindd_domain
*dom
;
2797 dom
= find_domain_from_name_noinit(dom_list
[i
].domain_name
);
2798 if (dom
&& dom
->internal
) {
2802 trust
= &trusts
->array
[trusts
->count
];
2803 trust
->netbios_name
= talloc_strdup(trusts
->array
, dom_list
[i
].domain_name
);
2804 trust
->dns_name
= talloc_strdup(trusts
->array
, dom_list
[i
].dns_name
);
2805 sid
= talloc(trusts
->array
, struct dom_sid
);
2806 if (!trust
->netbios_name
|| !trust
->dns_name
||
2808 TALLOC_FREE(dom_list
);
2809 TALLOC_FREE(trusts
->array
);
2810 return NT_STATUS_NO_MEMORY
;
2813 trust
->trust_flags
= dom_list
[i
].trust_flags
;
2814 trust
->trust_attributes
= dom_list
[i
].trust_attribs
;
2815 trust
->trust_type
= dom_list
[i
].trust_type
;
2816 sid_copy(sid
, &dom_list
[i
].sid
);
2821 TALLOC_FREE(dom_list
);
2822 return NT_STATUS_OK
;
2825 /* Return status value returned by seq number check */
2827 if (!NT_STATUS_IS_OK(domain
->last_status
))
2828 return domain
->last_status
;
2830 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2833 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, trusts
);
2835 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2836 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2837 if (!domain
->internal
&& old_status
) {
2838 set_domain_offline(domain
);
2840 if (!domain
->internal
&&
2843 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2844 if (retval
&& num_domains
&& dom_list
) {
2845 TALLOC_FREE(trusts
->array
);
2847 goto do_fetch_cache
;
2851 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2852 * so that the generic centry handling still applies correctly -
2855 if (!NT_STATUS_IS_ERR(status
)) {
2856 status
= NT_STATUS_OK
;
2861 /* get lockout policy */
2862 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
2863 TALLOC_CTX
*mem_ctx
,
2864 struct samr_DomInfo12
*policy
)
2866 struct winbind_cache
*cache
= get_cache(domain
);
2867 struct cache_entry
*centry
= NULL
;
2871 old_status
= domain
->online
;
2875 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2881 policy
->lockout_duration
= centry_nttime(centry
);
2882 policy
->lockout_window
= centry_nttime(centry
);
2883 policy
->lockout_threshold
= centry_uint16(centry
);
2885 status
= centry
->status
;
2887 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2888 domain
->name
, nt_errstr(status
) ));
2890 centry_free(centry
);
2894 ZERO_STRUCTP(policy
);
2896 /* Return status value returned by seq number check */
2898 if (!NT_STATUS_IS_OK(domain
->last_status
))
2899 return domain
->last_status
;
2901 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2904 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2906 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2907 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2908 if (!domain
->internal
&& old_status
) {
2909 set_domain_offline(domain
);
2912 !domain
->internal
&&
2915 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2917 goto do_fetch_cache
;
2922 refresh_sequence_number(domain
, false);
2923 if (!NT_STATUS_IS_OK(status
)) {
2926 wcache_save_lockout_policy(domain
, status
, policy
);
2931 /* get password policy */
2932 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
2933 TALLOC_CTX
*mem_ctx
,
2934 struct samr_DomInfo1
*policy
)
2936 struct winbind_cache
*cache
= get_cache(domain
);
2937 struct cache_entry
*centry
= NULL
;
2941 old_status
= domain
->online
;
2945 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2951 policy
->min_password_length
= centry_uint16(centry
);
2952 policy
->password_history_length
= centry_uint16(centry
);
2953 policy
->password_properties
= centry_uint32(centry
);
2954 policy
->max_password_age
= centry_nttime(centry
);
2955 policy
->min_password_age
= centry_nttime(centry
);
2957 status
= centry
->status
;
2959 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2960 domain
->name
, nt_errstr(status
) ));
2962 centry_free(centry
);
2966 ZERO_STRUCTP(policy
);
2968 /* Return status value returned by seq number check */
2970 if (!NT_STATUS_IS_OK(domain
->last_status
))
2971 return domain
->last_status
;
2973 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2976 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
2978 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2979 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2980 if (!domain
->internal
&& old_status
) {
2981 set_domain_offline(domain
);
2984 !domain
->internal
&&
2987 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2989 goto do_fetch_cache
;
2994 refresh_sequence_number(domain
, false);
2995 if (!NT_STATUS_IS_OK(status
)) {
2998 wcache_save_password_policy(domain
, status
, policy
);
3004 /* Invalidate cached user and group lists coherently */
3006 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3009 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
3010 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
3011 tdb_delete(the_tdb
, kbuf
);
3016 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3018 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
3019 const struct dom_sid
*sid
)
3021 fstring key_str
, sid_string
;
3022 struct winbind_cache
*cache
;
3024 /* dont clear cached U/SID and UG/SID entries when we want to logon
3027 if (lp_winbind_offline_logon()) {
3034 cache
= get_cache(domain
);
3040 /* Clear U/SID cache entry */
3041 fstr_sprintf(key_str
, "U/%s", sid_to_fstring(sid_string
, sid
));
3042 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3043 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3045 /* Clear UG/SID cache entry */
3046 fstr_sprintf(key_str
, "UG/%s", sid_to_fstring(sid_string
, sid
));
3047 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3048 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3050 /* Samba/winbindd never needs this. */
3051 netsamlogon_clear_cached_user(sid
);
3054 bool wcache_invalidate_cache(void)
3056 struct winbindd_domain
*domain
;
3058 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3059 struct winbind_cache
*cache
= get_cache(domain
);
3061 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3062 "entries for %s\n", domain
->name
));
3065 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3074 bool wcache_invalidate_cache_noinit(void)
3076 struct winbindd_domain
*domain
;
3078 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3079 struct winbind_cache
*cache
;
3081 /* Skip uninitialized domains. */
3082 if (!domain
->initialized
&& !domain
->internal
) {
3086 cache
= get_cache(domain
);
3088 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3089 "entries for %s\n", domain
->name
));
3092 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3094 * Flushing cache has nothing to with domains.
3095 * return here if we successfully flushed once.
3096 * To avoid unnecessary traversing the cache.
3107 bool init_wcache(void)
3109 if (wcache
== NULL
) {
3110 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
3111 ZERO_STRUCTP(wcache
);
3114 if (wcache
->tdb
!= NULL
)
3117 /* when working offline we must not clear the cache on restart */
3118 wcache
->tdb
= tdb_open_log(state_path("winbindd_cache.tdb"),
3119 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3120 TDB_INCOMPATIBLE_HASH
|
3121 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3122 O_RDWR
|O_CREAT
, 0600);
3124 if (wcache
->tdb
== NULL
) {
3125 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3132 /************************************************************************
3133 This is called by the parent to initialize the cache file.
3134 We don't need sophisticated locking here as we know we're the
3136 ************************************************************************/
3138 bool initialize_winbindd_cache(void)
3140 bool cache_bad
= true;
3143 if (!init_wcache()) {
3144 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3148 /* Check version number. */
3149 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
3150 vers
== WINBINDD_CACHE_VERSION
) {
3155 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3156 "and re-creating with version number %d\n",
3157 WINBINDD_CACHE_VERSION
));
3159 tdb_close(wcache
->tdb
);
3162 if (unlink(state_path("winbindd_cache.tdb")) == -1) {
3163 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3164 state_path("winbindd_cache.tdb"),
3168 if (!init_wcache()) {
3169 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3170 "init_wcache failed.\n"));
3174 /* Write the version. */
3175 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
3176 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3177 tdb_errorstr_compat(wcache
->tdb
) ));
3182 tdb_close(wcache
->tdb
);
3187 void close_winbindd_cache(void)
3193 tdb_close(wcache
->tdb
);
3198 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*sid
,
3199 char **domain_name
, char **name
,
3200 enum lsa_SidType
*type
)
3202 struct winbindd_domain
*domain
;
3205 domain
= find_lookup_domain_from_sid(sid
);
3206 if (domain
== NULL
) {
3209 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
3211 return NT_STATUS_IS_OK(status
);
3214 bool lookup_cached_name(const char *domain_name
,
3216 struct dom_sid
*sid
,
3217 enum lsa_SidType
*type
)
3219 struct winbindd_domain
*domain
;
3221 bool original_online_state
;
3223 domain
= find_lookup_domain_from_name(domain_name
);
3224 if (domain
== NULL
) {
3228 /* If we are doing a cached logon, temporarily set the domain
3229 offline so the cache won't expire the entry */
3231 original_online_state
= domain
->online
;
3232 domain
->online
= false;
3233 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
3234 domain
->online
= original_online_state
;
3236 return NT_STATUS_IS_OK(status
);
3239 void cache_name2sid(struct winbindd_domain
*domain
,
3240 const char *domain_name
, const char *name
,
3241 enum lsa_SidType type
, const struct dom_sid
*sid
)
3243 refresh_sequence_number(domain
, false);
3244 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
3249 * The original idea that this cache only contains centries has
3250 * been blurred - now other stuff gets put in here. Ensure we
3251 * ignore these things on cleanup.
3254 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
3255 TDB_DATA dbuf
, void *state
)
3257 struct cache_entry
*centry
;
3259 if (is_non_centry_key(kbuf
)) {
3263 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
3268 if (!NT_STATUS_IS_OK(centry
->status
)) {
3269 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
3270 tdb_delete(the_tdb
, kbuf
);
3273 centry_free(centry
);
3277 /* flush the cache */
3278 void wcache_flush_cache(void)
3283 tdb_close(wcache
->tdb
);
3286 if (!winbindd_use_cache()) {
3290 /* when working offline we must not clear the cache on restart */
3291 wcache
->tdb
= tdb_open_log(state_path("winbindd_cache.tdb"),
3292 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3293 TDB_INCOMPATIBLE_HASH
|
3294 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3295 O_RDWR
|O_CREAT
, 0600);
3298 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3302 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
3304 DEBUG(10,("wcache_flush_cache success\n"));
3307 /* Count cached creds */
3309 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3312 int *cred_count
= (int*)state
;
3314 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3320 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
3322 struct winbind_cache
*cache
= get_cache(domain
);
3327 return NT_STATUS_INTERNAL_DB_ERROR
;
3330 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
3332 return NT_STATUS_OK
;
3336 struct cred_list
*prev
, *next
;
3341 static struct cred_list
*wcache_cred_list
;
3343 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3346 struct cred_list
*cred
;
3348 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3350 cred
= SMB_MALLOC_P(struct cred_list
);
3352 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3358 /* save a copy of the key */
3360 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
3361 DLIST_ADD(wcache_cred_list
, cred
);
3367 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
3369 struct winbind_cache
*cache
= get_cache(domain
);
3372 struct cred_list
*cred
, *oldest
= NULL
;
3375 return NT_STATUS_INTERNAL_DB_ERROR
;
3378 /* we possibly already have an entry */
3379 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
3381 fstring key_str
, tmp
;
3383 DEBUG(11,("we already have an entry, deleting that\n"));
3385 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
3387 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3389 return NT_STATUS_OK
;
3392 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
3394 return NT_STATUS_OK
;
3395 } else if ((ret
< 0) || (wcache_cred_list
== NULL
)) {
3396 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3399 ZERO_STRUCTP(oldest
);
3401 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
3406 data
= tdb_fetch_compat(cache
->tdb
, string_tdb_data(cred
->name
));
3408 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3410 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3414 t
= IVAL(data
.dptr
, 0);
3415 SAFE_FREE(data
.dptr
);
3418 oldest
= SMB_MALLOC_P(struct cred_list
);
3419 if (oldest
== NULL
) {
3420 status
= NT_STATUS_NO_MEMORY
;
3424 fstrcpy(oldest
->name
, cred
->name
);
3425 oldest
->created
= t
;
3429 if (t
< oldest
->created
) {
3430 fstrcpy(oldest
->name
, cred
->name
);
3431 oldest
->created
= t
;
3435 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3436 status
= NT_STATUS_OK
;
3438 status
= NT_STATUS_UNSUCCESSFUL
;
3441 SAFE_FREE(wcache_cred_list
);
3447 /* Change the global online/offline state. */
3448 bool set_global_winbindd_state_offline(void)
3452 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3454 /* Only go offline if someone has created
3455 the key "WINBINDD_OFFLINE" in the cache tdb. */
3457 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3458 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3462 if (!lp_winbind_offline_logon()) {
3463 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3467 if (global_winbindd_offline_state
) {
3468 /* Already offline. */
3472 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
3474 if (!data
.dptr
|| data
.dsize
!= 4) {
3475 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3476 SAFE_FREE(data
.dptr
);
3479 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3480 global_winbindd_offline_state
= true;
3481 SAFE_FREE(data
.dptr
);
3486 void set_global_winbindd_state_online(void)
3488 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3490 if (!lp_winbind_offline_logon()) {
3491 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3495 if (!global_winbindd_offline_state
) {
3496 /* Already online. */
3499 global_winbindd_offline_state
= false;
3505 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3506 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3509 bool get_global_winbindd_state_offline(void)
3511 return global_winbindd_offline_state
;
3514 /***********************************************************************
3515 Validate functions for all possible cache tdb keys.
3516 ***********************************************************************/
3518 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3519 struct tdb_validation_status
*state
)
3521 struct cache_entry
*centry
;
3523 centry
= SMB_XMALLOC_P(struct cache_entry
);
3524 centry
->data
= (unsigned char *)memdup(data
.dptr
, data
.dsize
);
3525 if (!centry
->data
) {
3529 centry
->len
= data
.dsize
;
3532 if (centry
->len
< 16) {
3533 /* huh? corrupt cache? */
3534 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3535 "(len < 16) ?\n", kstr
));
3536 centry_free(centry
);
3537 state
->bad_entry
= true;
3538 state
->success
= false;
3542 centry
->status
= NT_STATUS(centry_uint32(centry
));
3543 centry
->sequence_number
= centry_uint32(centry
);
3544 centry
->timeout
= centry_uint64_t(centry
);
3548 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3549 struct tdb_validation_status
*state
)
3551 if (dbuf
.dsize
!= 8) {
3552 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3553 keystr
, (unsigned int)dbuf
.dsize
));
3554 state
->bad_entry
= true;
3560 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3561 struct tdb_validation_status
*state
)
3563 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3568 (void)centry_uint32(centry
);
3569 if (NT_STATUS_IS_OK(centry
->status
)) {
3571 (void)centry_sid(centry
, &sid
);
3574 centry_free(centry
);
3576 if (!(state
->success
)) {
3579 DEBUG(10,("validate_ns: %s ok\n", keystr
));
3583 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3584 struct tdb_validation_status
*state
)
3586 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3591 if (NT_STATUS_IS_OK(centry
->status
)) {
3592 (void)centry_uint32(centry
);
3593 (void)centry_string(centry
, mem_ctx
);
3594 (void)centry_string(centry
, mem_ctx
);
3597 centry_free(centry
);
3599 if (!(state
->success
)) {
3602 DEBUG(10,("validate_sn: %s ok\n", keystr
));
3606 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3607 struct tdb_validation_status
*state
)
3609 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3616 (void)centry_string(centry
, mem_ctx
);
3617 (void)centry_string(centry
, mem_ctx
);
3618 (void)centry_string(centry
, mem_ctx
);
3619 (void)centry_string(centry
, mem_ctx
);
3620 (void)centry_uint32(centry
);
3621 (void)centry_sid(centry
, &sid
);
3622 (void)centry_sid(centry
, &sid
);
3624 centry_free(centry
);
3626 if (!(state
->success
)) {
3629 DEBUG(10,("validate_u: %s ok\n", keystr
));
3633 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3634 struct tdb_validation_status
*state
)
3636 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3642 (void)centry_nttime(centry
);
3643 (void)centry_nttime(centry
);
3644 (void)centry_uint16(centry
);
3646 centry_free(centry
);
3648 if (!(state
->success
)) {
3651 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3655 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3656 struct tdb_validation_status
*state
)
3658 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3664 (void)centry_uint16(centry
);
3665 (void)centry_uint16(centry
);
3666 (void)centry_uint32(centry
);
3667 (void)centry_nttime(centry
);
3668 (void)centry_nttime(centry
);
3670 centry_free(centry
);
3672 if (!(state
->success
)) {
3675 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3679 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3680 struct tdb_validation_status
*state
)
3682 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3688 (void)centry_time(centry
);
3689 (void)centry_hash16(centry
, mem_ctx
);
3691 /* We only have 17 bytes more data in the salted cred case. */
3692 if (centry
->len
- centry
->ofs
== 17) {
3693 (void)centry_hash16(centry
, mem_ctx
);
3696 centry_free(centry
);
3698 if (!(state
->success
)) {
3701 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3705 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3706 struct tdb_validation_status
*state
)
3708 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3709 int32 num_entries
, i
;
3715 num_entries
= (int32
)centry_uint32(centry
);
3717 for (i
=0; i
< num_entries
; i
++) {
3719 (void)centry_string(centry
, mem_ctx
);
3720 (void)centry_string(centry
, mem_ctx
);
3721 (void)centry_string(centry
, mem_ctx
);
3722 (void)centry_string(centry
, mem_ctx
);
3723 (void)centry_sid(centry
, &sid
);
3724 (void)centry_sid(centry
, &sid
);
3727 centry_free(centry
);
3729 if (!(state
->success
)) {
3732 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3736 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3737 struct tdb_validation_status
*state
)
3739 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3740 int32 num_entries
, i
;
3746 num_entries
= centry_uint32(centry
);
3748 for (i
=0; i
< num_entries
; i
++) {
3749 (void)centry_string(centry
, mem_ctx
);
3750 (void)centry_string(centry
, mem_ctx
);
3751 (void)centry_uint32(centry
);
3754 centry_free(centry
);
3756 if (!(state
->success
)) {
3759 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3763 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3764 struct tdb_validation_status
*state
)
3766 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3767 int32 num_groups
, i
;
3773 num_groups
= centry_uint32(centry
);
3775 for (i
=0; i
< num_groups
; i
++) {
3777 centry_sid(centry
, &sid
);
3780 centry_free(centry
);
3782 if (!(state
->success
)) {
3785 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3789 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3790 struct tdb_validation_status
*state
)
3792 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3793 int32 num_aliases
, i
;
3799 num_aliases
= centry_uint32(centry
);
3801 for (i
=0; i
< num_aliases
; i
++) {
3802 (void)centry_uint32(centry
);
3805 centry_free(centry
);
3807 if (!(state
->success
)) {
3810 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3814 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3815 struct tdb_validation_status
*state
)
3817 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3824 num_names
= centry_uint32(centry
);
3826 for (i
=0; i
< num_names
; i
++) {
3828 centry_sid(centry
, &sid
);
3829 (void)centry_string(centry
, mem_ctx
);
3830 (void)centry_uint32(centry
);
3833 centry_free(centry
);
3835 if (!(state
->success
)) {
3838 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3842 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3843 struct tdb_validation_status
*state
)
3845 /* Can't say anything about this other than must be nonzero. */
3846 if (dbuf
.dsize
== 0) {
3847 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3849 state
->bad_entry
= true;
3850 state
->success
= false;
3854 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3858 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3859 struct tdb_validation_status
*state
)
3861 /* Can't say anything about this other than must be nonzero. */
3862 if (dbuf
.dsize
== 0) {
3863 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3865 state
->bad_entry
= true;
3866 state
->success
= false;
3870 DEBUG(10,("validate_de: %s ok\n", keystr
));
3874 static int validate_pwinfo(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3875 TDB_DATA dbuf
, struct tdb_validation_status
*state
)
3877 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3883 (void)centry_string(centry
, mem_ctx
);
3884 (void)centry_string(centry
, mem_ctx
);
3885 (void)centry_string(centry
, mem_ctx
);
3886 (void)centry_uint32(centry
);
3888 centry_free(centry
);
3890 if (!(state
->success
)) {
3893 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3897 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3899 struct tdb_validation_status
*state
)
3901 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3907 (void)centry_string( centry
, mem_ctx
);
3909 centry_free(centry
);
3911 if (!(state
->success
)) {
3914 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3918 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3920 struct tdb_validation_status
*state
)
3922 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3928 (void)centry_string( centry
, mem_ctx
);
3930 centry_free(centry
);
3932 if (!(state
->success
)) {
3935 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3939 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3941 struct tdb_validation_status
*state
)
3943 if (dbuf
.dsize
== 0) {
3944 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3945 "key %s (len ==0) ?\n", keystr
));
3946 state
->bad_entry
= true;
3947 state
->success
= false;
3951 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3952 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3956 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3957 struct tdb_validation_status
*state
)
3959 if (dbuf
.dsize
!= 4) {
3960 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3961 keystr
, (unsigned int)dbuf
.dsize
));
3962 state
->bad_entry
= true;
3963 state
->success
= false;
3966 DEBUG(10,("validate_offline: %s ok\n", keystr
));
3970 static int validate_ndr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3971 struct tdb_validation_status
*state
)
3974 * Ignore validation for now. The proper way to do this is with a
3975 * checksum. Just pure parsing does not really catch much.
3980 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3981 struct tdb_validation_status
*state
)
3983 if (dbuf
.dsize
!= 4) {
3984 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3985 "key %s (len %u != 4) ?\n",
3986 keystr
, (unsigned int)dbuf
.dsize
));
3987 state
->bad_entry
= true;
3988 state
->success
= false;
3992 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
3996 /***********************************************************************
3997 A list of all possible cache tdb keys with associated validation
3999 ***********************************************************************/
4001 struct key_val_struct
{
4002 const char *keyname
;
4003 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
4005 {"SEQNUM/", validate_seqnum
},
4006 {"NS/", validate_ns
},
4007 {"SN/", validate_sn
},
4009 {"LOC_POL/", validate_loc_pol
},
4010 {"PWD_POL/", validate_pwd_pol
},
4011 {"CRED/", validate_cred
},
4012 {"UL/", validate_ul
},
4013 {"GL/", validate_gl
},
4014 {"UG/", validate_ug
},
4015 {"UA", validate_ua
},
4016 {"GM/", validate_gm
},
4017 {"DR/", validate_dr
},
4018 {"DE/", validate_de
},
4019 {"NSS/PWINFO/", validate_pwinfo
},
4020 {"TRUSTDOMCACHE/", validate_trustdomcache
},
4021 {"NSS/NA/", validate_nss_na
},
4022 {"NSS/AN/", validate_nss_an
},
4023 {"WINBINDD_OFFLINE", validate_offline
},
4024 {"NDR/", validate_ndr
},
4025 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
4029 /***********************************************************************
4030 Function to look at every entry in the tdb and validate it as far as
4032 ***********************************************************************/
4034 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
4037 unsigned int max_key_len
= 1024;
4038 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
4040 /* Paranoia check. */
4041 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0) {
4042 max_key_len
= 1024 * 1024;
4044 if (kbuf
.dsize
> max_key_len
) {
4045 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4047 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
4051 for (i
= 0; key_val
[i
].keyname
; i
++) {
4052 size_t namelen
= strlen(key_val
[i
].keyname
);
4053 if (kbuf
.dsize
>= namelen
&& (
4054 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
4055 TALLOC_CTX
*mem_ctx
;
4059 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
4063 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
4064 keystr
[kbuf
.dsize
] = '\0';
4066 mem_ctx
= talloc_init("validate_ctx");
4072 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
4076 talloc_destroy(mem_ctx
);
4081 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4082 dump_data(0, (uint8
*)kbuf
.dptr
, kbuf
.dsize
);
4083 DEBUG(0,("data :\n"));
4084 dump_data(0, (uint8
*)dbuf
.dptr
, dbuf
.dsize
);
4085 v_state
->unknown_key
= true;
4086 v_state
->success
= false;
4087 return 1; /* terminate. */
4090 static void validate_panic(const char *const why
)
4092 DEBUG(0,("validating cache: would panic %s\n", why
));
4093 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4097 static int wbcache_update_centry_fn(TDB_CONTEXT
*tdb
,
4105 if (is_non_centry_key(key
)) {
4109 if (data
.dptr
== NULL
|| data
.dsize
== 0) {
4110 if (tdb_delete(tdb
, key
) < 0) {
4111 DEBUG(0, ("tdb_delete for [%s] failed!\n",
4117 /* add timeout to blob (uint64_t) */
4118 blob
.dsize
= data
.dsize
+ 8;
4120 blob
.dptr
= SMB_XMALLOC_ARRAY(uint8_t, blob
.dsize
);
4121 if (blob
.dptr
== NULL
) {
4124 memset(blob
.dptr
, 0, blob
.dsize
);
4126 /* copy status and seqnum */
4127 memcpy(blob
.dptr
, data
.dptr
, 8);
4130 ctimeout
= lp_winbind_cache_time() + time(NULL
);
4131 SBVAL(blob
.dptr
, 8, ctimeout
);
4134 memcpy(blob
.dptr
+ 16, data
.dptr
+ 8, data
.dsize
- 8);
4136 if (tdb_store(tdb
, key
, blob
, TDB_REPLACE
) < 0) {
4137 DEBUG(0, ("tdb_store to update [%s] failed!\n",
4139 SAFE_FREE(blob
.dptr
);
4143 SAFE_FREE(blob
.dptr
);
4147 static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT
*tdb
)
4151 DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
4153 rc
= tdb_traverse(tdb
, wbcache_update_centry_fn
, NULL
);
4161 /***********************************************************************
4162 Try and validate every entry in the winbindd cache. If we fail here,
4163 delete the cache tdb and return non-zero.
4164 ***********************************************************************/
4166 int winbindd_validate_cache(void)
4169 const char *tdb_path
= state_path("winbindd_cache.tdb");
4170 TDB_CONTEXT
*tdb
= NULL
;
4174 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4175 smb_panic_fn
= validate_panic
;
4177 tdb
= tdb_open_log(tdb_path
,
4178 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
4179 TDB_INCOMPATIBLE_HASH
|
4180 ( lp_winbind_offline_logon()
4182 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
4186 DEBUG(0, ("winbindd_validate_cache: "
4187 "error opening/initializing tdb\n"));
4191 /* Version check and upgrade code. */
4192 if (!tdb_fetch_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers_id
)) {
4193 DEBUG(10, ("Fresh database\n"));
4194 tdb_store_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
);
4195 vers_id
= WINBINDD_CACHE_VERSION
;
4198 if (vers_id
!= WINBINDD_CACHE_VERSION
) {
4199 if (vers_id
== WINBINDD_CACHE_VER1
) {
4200 ok
= wbcache_upgrade_v1_to_v2(tdb
);
4202 DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
4207 tdb_store_uint32(tdb
,
4208 WINBINDD_CACHE_VERSION_KEYSTR
,
4209 WINBINDD_CACHE_VERSION
);
4210 vers_id
= WINBINDD_CACHE_VER2
;
4216 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
4219 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4220 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
4225 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4226 smb_panic_fn
= smb_panic
;
4230 /***********************************************************************
4231 Try and validate every entry in the winbindd cache.
4232 ***********************************************************************/
4234 int winbindd_validate_cache_nobackup(void)
4237 const char *tdb_path
= state_path("winbindd_cache.tdb");
4239 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4240 smb_panic_fn
= validate_panic
;
4243 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
4244 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
4246 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
4250 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4254 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4256 smb_panic_fn
= smb_panic
;
4260 bool winbindd_cache_validate_and_initialize(void)
4262 close_winbindd_cache();
4264 if (lp_winbind_offline_logon()) {
4265 if (winbindd_validate_cache() < 0) {
4266 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4267 "could be restored.\n"));
4271 return initialize_winbindd_cache();
4274 /*********************************************************************
4275 ********************************************************************/
4277 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
4278 struct winbindd_tdc_domain
**domains
,
4279 size_t *num_domains
)
4281 struct winbindd_tdc_domain
*list
= NULL
;
4284 bool set_only
= false;
4286 /* don't allow duplicates */
4291 for ( i
=0; i
< (*num_domains
); i
++ ) {
4292 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
4293 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4304 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, 1 );
4307 list
= talloc_realloc( *domains
, *domains
,
4308 struct winbindd_tdc_domain
,
4313 ZERO_STRUCT( list
[idx
] );
4319 list
[idx
].domain_name
= talloc_strdup( list
, new_dom
->name
);
4320 list
[idx
].dns_name
= talloc_strdup( list
, new_dom
->alt_name
);
4322 if ( !is_null_sid( &new_dom
->sid
) ) {
4323 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
4325 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
4328 if ( new_dom
->domain_flags
!= 0x0 )
4329 list
[idx
].trust_flags
= new_dom
->domain_flags
;
4331 if ( new_dom
->domain_type
!= 0x0 )
4332 list
[idx
].trust_type
= new_dom
->domain_type
;
4334 if ( new_dom
->domain_trust_attribs
!= 0x0 )
4335 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
4339 *num_domains
= idx
+ 1;
4345 /*********************************************************************
4346 ********************************************************************/
4348 static TDB_DATA
make_tdc_key( const char *domain_name
)
4350 char *keystr
= NULL
;
4351 TDB_DATA key
= { NULL
, 0 };
4353 if ( !domain_name
) {
4354 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4358 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
4361 key
= string_term_tdb_data(keystr
);
4366 /*********************************************************************
4367 ********************************************************************/
4369 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
4371 unsigned char **buf
)
4373 unsigned char *buffer
= NULL
;
4378 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4386 /* Store the number of array items first */
4387 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
4390 /* now pack each domain trust record */
4391 for ( i
=0; i
<num_domains
; i
++ ) {
4396 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4397 domains
[i
].domain_name
,
4398 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
4401 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
4402 domains
[i
].domain_name
,
4403 domains
[i
].dns_name
,
4404 sid_to_fstring(tmp
, &domains
[i
].sid
),
4405 domains
[i
].trust_flags
,
4406 domains
[i
].trust_attribs
,
4407 domains
[i
].trust_type
);
4410 if ( buflen
< len
) {
4412 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
4413 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4427 /*********************************************************************
4428 ********************************************************************/
4430 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
4431 struct winbindd_tdc_domain
**domains
)
4433 fstring domain_name
, dns_name
, sid_string
;
4434 uint32 type
, attribs
, flags
;
4438 struct winbindd_tdc_domain
*list
= NULL
;
4440 /* get the number of domains */
4441 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
4443 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4447 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, num_domains
);
4449 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4453 for ( i
=0; i
<num_domains
; i
++ ) {
4454 len
+= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
4463 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4464 TALLOC_FREE( list
);
4468 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4469 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4470 domain_name
, dns_name
, sid_string
,
4471 flags
, attribs
, type
));
4473 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
4474 list
[i
].dns_name
= talloc_strdup( list
, dns_name
);
4475 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
4476 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4479 list
[i
].trust_flags
= flags
;
4480 list
[i
].trust_attribs
= attribs
;
4481 list
[i
].trust_type
= type
;
4489 /*********************************************************************
4490 ********************************************************************/
4492 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
4494 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4495 TDB_DATA data
= { NULL
, 0 };
4501 /* See if we were asked to delete the cache entry */
4504 ret
= tdb_delete( wcache
->tdb
, key
);
4508 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4515 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4518 SAFE_FREE( data
.dptr
);
4519 SAFE_FREE( key
.dptr
);
4521 return ( ret
== 0 );
4524 /*********************************************************************
4525 ********************************************************************/
4527 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4529 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4530 TDB_DATA data
= { NULL
, 0 };
4538 data
= tdb_fetch_compat( wcache
->tdb
, key
);
4540 SAFE_FREE( key
.dptr
);
4545 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4547 SAFE_FREE( data
.dptr
);
4555 /*********************************************************************
4556 ********************************************************************/
4558 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4560 struct winbindd_tdc_domain
*dom_list
= NULL
;
4561 size_t num_domains
= 0;
4564 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4565 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4566 domain
->name
, domain
->alt_name
,
4567 sid_string_dbg(&domain
->sid
),
4568 domain
->domain_flags
,
4569 domain
->domain_trust_attribs
,
4570 domain
->domain_type
));
4572 if ( !init_wcache() ) {
4576 /* fetch the list */
4578 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4580 /* add the new domain */
4582 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4586 /* pack the domain */
4588 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4596 TALLOC_FREE( dom_list
);
4601 /*********************************************************************
4602 ********************************************************************/
4604 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4606 struct winbindd_tdc_domain
*dom_list
= NULL
;
4607 size_t num_domains
= 0;
4609 struct winbindd_tdc_domain
*d
= NULL
;
4611 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4613 if ( !init_wcache() ) {
4617 /* fetch the list */
4619 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4621 for ( i
=0; i
<num_domains
; i
++ ) {
4622 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4623 strequal(name
, dom_list
[i
].dns_name
) )
4625 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4628 d
= talloc( ctx
, struct winbindd_tdc_domain
);
4632 d
->domain_name
= talloc_strdup( d
, dom_list
[i
].domain_name
);
4633 d
->dns_name
= talloc_strdup( d
, dom_list
[i
].dns_name
);
4634 sid_copy( &d
->sid
, &dom_list
[i
].sid
);
4635 d
->trust_flags
= dom_list
[i
].trust_flags
;
4636 d
->trust_type
= dom_list
[i
].trust_type
;
4637 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
4643 TALLOC_FREE( dom_list
);
4648 /*********************************************************************
4649 ********************************************************************/
4651 struct winbindd_tdc_domain
*
4652 wcache_tdc_fetch_domainbysid(TALLOC_CTX
*ctx
,
4653 const struct dom_sid
*sid
)
4655 struct winbindd_tdc_domain
*dom_list
= NULL
;
4656 size_t num_domains
= 0;
4658 struct winbindd_tdc_domain
*d
= NULL
;
4660 DEBUG(10,("wcache_tdc_fetch_domainbysid: Searching for domain %s\n",
4661 sid_string_dbg(sid
)));
4663 if (!init_wcache()) {
4667 /* fetch the list */
4669 wcache_tdc_fetch_list(&dom_list
, &num_domains
);
4671 for (i
= 0; i
<num_domains
; i
++) {
4672 if (dom_sid_equal(sid
, &(dom_list
[i
].sid
))) {
4673 DEBUG(10, ("wcache_tdc_fetch_domainbysid: "
4674 "Found domain %s for SID %s\n",
4675 dom_list
[i
].domain_name
,
4676 sid_string_dbg(sid
)));
4678 d
= talloc(ctx
, struct winbindd_tdc_domain
);
4682 d
->domain_name
= talloc_strdup(d
,
4683 dom_list
[i
].domain_name
);
4685 d
->dns_name
= talloc_strdup(d
, dom_list
[i
].dns_name
);
4686 sid_copy(&d
->sid
, &dom_list
[i
].sid
);
4687 d
->trust_flags
= dom_list
[i
].trust_flags
;
4688 d
->trust_type
= dom_list
[i
].trust_type
;
4689 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
4695 TALLOC_FREE(dom_list
);
4701 /*********************************************************************
4702 ********************************************************************/
4704 void wcache_tdc_clear( void )
4706 if ( !init_wcache() )
4709 wcache_tdc_store_list( NULL
, 0 );
4715 /*********************************************************************
4716 ********************************************************************/
4718 static void wcache_save_user_pwinfo(struct winbindd_domain
*domain
,
4720 const struct dom_sid
*user_sid
,
4721 const char *homedir
,
4726 struct cache_entry
*centry
;
4729 if ( (centry
= centry_start(domain
, status
)) == NULL
)
4732 centry_put_string( centry
, homedir
);
4733 centry_put_string( centry
, shell
);
4734 centry_put_string( centry
, gecos
);
4735 centry_put_uint32( centry
, gid
);
4737 centry_end(centry
, "NSS/PWINFO/%s", sid_to_fstring(tmp
, user_sid
) );
4739 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid
) ));
4741 centry_free(centry
);
4746 NTSTATUS
nss_get_info_cached( struct winbindd_domain
*domain
,
4747 const struct dom_sid
*user_sid
,
4749 const char **homedir
, const char **shell
,
4750 const char **gecos
, gid_t
*p_gid
)
4752 struct winbind_cache
*cache
= get_cache(domain
);
4753 struct cache_entry
*centry
= NULL
;
4760 centry
= wcache_fetch(cache
, domain
, "NSS/PWINFO/%s",
4761 sid_to_fstring(tmp
, user_sid
));
4766 *homedir
= centry_string( centry
, ctx
);
4767 *shell
= centry_string( centry
, ctx
);
4768 *gecos
= centry_string( centry
, ctx
);
4769 *p_gid
= centry_uint32( centry
);
4771 centry_free(centry
);
4773 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4774 sid_string_dbg(user_sid
)));
4776 return NT_STATUS_OK
;
4780 nt_status
= nss_get_info( domain
->name
, user_sid
, ctx
,
4781 homedir
, shell
, gecos
, p_gid
);
4783 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status
)));
4785 if ( NT_STATUS_IS_OK(nt_status
) ) {
4786 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir
));
4787 DEBUGADD(10, ("\tshell = '%s'\n", *shell
));
4788 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos
));
4789 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid
));
4791 wcache_save_user_pwinfo( domain
, nt_status
, user_sid
,
4792 *homedir
, *shell
, *gecos
, *p_gid
);
4795 if ( NT_STATUS_EQUAL( nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
4796 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4798 set_domain_offline( domain
);
4806 /* the cache backend methods are exposed via this structure */
4807 struct winbindd_methods cache_methods
= {
4825 static bool wcache_ndr_key(TALLOC_CTX
*mem_ctx
, char *domain_name
,
4826 uint32_t opnum
, const DATA_BLOB
*req
,
4832 key
= talloc_asprintf(mem_ctx
, "NDR/%s/%d/", domain_name
, (int)opnum
);
4836 keylen
= talloc_get_size(key
) - 1;
4838 key
= talloc_realloc(mem_ctx
, key
, char, keylen
+ req
->length
);
4842 memcpy(key
+ keylen
, req
->data
, req
->length
);
4844 pkey
->dptr
= (uint8_t *)key
;
4845 pkey
->dsize
= talloc_get_size(key
);
4849 static bool wcache_opnum_cacheable(uint32_t opnum
)
4852 case NDR_WBINT_PING
:
4853 case NDR_WBINT_QUERYSEQUENCENUMBER
:
4854 case NDR_WBINT_ALLOCATEUID
:
4855 case NDR_WBINT_ALLOCATEGID
:
4856 case NDR_WBINT_CHECKMACHINEACCOUNT
:
4857 case NDR_WBINT_CHANGEMACHINEACCOUNT
:
4858 case NDR_WBINT_PINGDC
:
4864 bool wcache_fetch_ndr(TALLOC_CTX
*mem_ctx
, struct winbindd_domain
*domain
,
4865 uint32_t opnum
, const DATA_BLOB
*req
, DATA_BLOB
*resp
)
4870 if (!wcache_opnum_cacheable(opnum
) ||
4871 is_my_own_sam_domain(domain
) ||
4872 is_builtin_domain(domain
)) {
4876 if (wcache
->tdb
== NULL
) {
4880 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4883 data
= tdb_fetch_compat(wcache
->tdb
, key
);
4884 TALLOC_FREE(key
.dptr
);
4886 if (data
.dptr
== NULL
) {
4889 if (data
.dsize
< 12) {
4893 if (!is_domain_offline(domain
)) {
4894 uint32_t entry_seqnum
, dom_seqnum
, last_check
;
4895 uint64_t entry_timeout
;
4897 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
,
4901 entry_seqnum
= IVAL(data
.dptr
, 0);
4902 if (entry_seqnum
!= dom_seqnum
) {
4903 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4904 (int)entry_seqnum
));
4907 entry_timeout
= BVAL(data
.dptr
, 4);
4908 if (time(NULL
) > entry_timeout
) {
4909 DEBUG(10, ("Entry has timed out\n"));
4914 resp
->data
= (uint8_t *)talloc_memdup(mem_ctx
, data
.dptr
+ 12,
4916 if (resp
->data
== NULL
) {
4917 DEBUG(10, ("talloc failed\n"));
4920 resp
->length
= data
.dsize
- 12;
4924 SAFE_FREE(data
.dptr
);
4928 void wcache_store_ndr(struct winbindd_domain
*domain
, uint32_t opnum
,
4929 const DATA_BLOB
*req
, const DATA_BLOB
*resp
)
4932 uint32_t dom_seqnum
, last_check
;
4935 if (!wcache_opnum_cacheable(opnum
) ||
4936 is_my_own_sam_domain(domain
) ||
4937 is_builtin_domain(domain
)) {
4941 if (wcache
->tdb
== NULL
) {
4945 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
, &last_check
)) {
4946 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4951 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4955 timeout
= time(NULL
) + lp_winbind_cache_time();
4957 data
.dsize
= resp
->length
+ 12;
4958 data
.dptr
= talloc_array(key
.dptr
, uint8_t, data
.dsize
);
4959 if (data
.dptr
== NULL
) {
4963 SIVAL(data
.dptr
, 0, dom_seqnum
);
4964 SBVAL(data
.dptr
, 4, timeout
);
4965 memcpy(data
.dptr
+ 12, resp
->data
, resp
->length
);
4967 tdb_store(wcache
->tdb
, key
, data
, 0);
4970 TALLOC_FREE(key
.dptr
);