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_domain(&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_domain(&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
);
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
);
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
);
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 strupper_m(upper_name
);
1118 centry
= wcache_fetch(cache
, domain
, "NSS/NA/%s", upper_name
);
1120 SAFE_FREE( upper_name
);
1125 status
= centry
->status
;
1127 if (!NT_STATUS_IS_OK(status
)) {
1128 centry_free(centry
);
1132 *alias
= centry_string( centry
, mem_ctx
);
1134 centry_free(centry
);
1136 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1137 name
, *alias
? *alias
: "(none)"));
1139 return (*alias
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1143 /* If its not in cache and we are offline, then fail */
1145 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1146 DEBUG(8,("resolve_username_to_alias: rejecting query "
1147 "in offline mode\n"));
1148 return NT_STATUS_NOT_FOUND
;
1151 status
= nss_map_to_alias( mem_ctx
, domain
->name
, name
, alias
);
1153 if ( NT_STATUS_IS_OK( status
) ) {
1154 wcache_save_username_alias(domain
, status
, name
, *alias
);
1157 if ( NT_STATUS_EQUAL( status
, NT_STATUS_NONE_MAPPED
) ) {
1158 wcache_save_username_alias(domain
, status
, name
, "(NULL)");
1161 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1162 nt_errstr(status
)));
1164 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1165 set_domain_offline( domain
);
1171 /***************************************************************************
1172 ***************************************************************************/
1174 NTSTATUS
resolve_alias_to_username( TALLOC_CTX
*mem_ctx
,
1175 struct winbindd_domain
*domain
,
1176 const char *alias
, char **name
)
1178 struct winbind_cache
*cache
= get_cache(domain
);
1179 struct cache_entry
*centry
= NULL
;
1183 if ( domain
->internal
)
1184 return NT_STATUS_NOT_SUPPORTED
;
1189 if ( (upper_name
= SMB_STRDUP(alias
)) == NULL
)
1190 return NT_STATUS_NO_MEMORY
;
1191 strupper_m(upper_name
);
1193 centry
= wcache_fetch(cache
, domain
, "NSS/AN/%s", upper_name
);
1195 SAFE_FREE( upper_name
);
1200 status
= centry
->status
;
1202 if (!NT_STATUS_IS_OK(status
)) {
1203 centry_free(centry
);
1207 *name
= centry_string( centry
, mem_ctx
);
1209 centry_free(centry
);
1211 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1212 alias
, *name
? *name
: "(none)"));
1214 return (*name
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1218 /* If its not in cache and we are offline, then fail */
1220 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1221 DEBUG(8,("resolve_alias_to_username: rejecting query "
1222 "in offline mode\n"));
1223 return NT_STATUS_NOT_FOUND
;
1226 /* an alias cannot contain a domain prefix or '@' */
1228 if (strchr(alias
, '\\') || strchr(alias
, '@')) {
1229 DEBUG(10,("resolve_alias_to_username: skipping fully "
1230 "qualified name %s\n", alias
));
1231 return NT_STATUS_OBJECT_NAME_INVALID
;
1234 status
= nss_map_from_alias( mem_ctx
, domain
->name
, alias
, name
);
1236 if ( NT_STATUS_IS_OK( status
) ) {
1237 wcache_save_alias_username( domain
, status
, alias
, *name
);
1240 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1241 wcache_save_alias_username(domain
, status
, alias
, "(NULL)");
1244 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1245 nt_errstr(status
)));
1247 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1248 set_domain_offline( domain
);
1254 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
1256 struct winbind_cache
*cache
= get_cache(domain
);
1258 fstring key_str
, tmp
;
1262 return NT_STATUS_INTERNAL_DB_ERROR
;
1265 if (is_null_sid(sid
)) {
1266 return NT_STATUS_INVALID_SID
;
1269 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1270 return NT_STATUS_INVALID_SID
;
1273 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
1275 data
= tdb_fetch_compat(cache
->tdb
, string_tdb_data(key_str
));
1277 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1280 SAFE_FREE(data
.dptr
);
1281 return NT_STATUS_OK
;
1284 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1285 as new salted ones. */
1287 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
1288 TALLOC_CTX
*mem_ctx
,
1289 const struct dom_sid
*sid
,
1290 const uint8
**cached_nt_pass
,
1291 const uint8
**cached_salt
)
1293 struct winbind_cache
*cache
= get_cache(domain
);
1294 struct cache_entry
*centry
= NULL
;
1300 if (!winbindd_use_cache()) {
1301 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1305 return NT_STATUS_INTERNAL_DB_ERROR
;
1308 if (is_null_sid(sid
)) {
1309 return NT_STATUS_INVALID_SID
;
1312 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1313 return NT_STATUS_INVALID_SID
;
1316 /* Try and get a salted cred first. If we can't
1317 fall back to an unsalted cred. */
1319 centry
= wcache_fetch(cache
, domain
, "CRED/%s",
1320 sid_to_fstring(tmp
, sid
));
1322 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1323 sid_string_dbg(sid
)));
1324 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1327 t
= centry_time(centry
);
1329 /* In the salted case this isn't actually the nt_hash itself,
1330 but the MD5 of the salt + nt_hash. Let the caller
1331 sort this out. It can tell as we only return the cached_salt
1332 if we are returning a salted cred. */
1334 *cached_nt_pass
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1335 if (*cached_nt_pass
== NULL
) {
1338 sid_to_fstring(sidstr
, sid
);
1340 /* Bad (old) cred cache. Delete and pretend we
1342 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1344 wcache_delete("CRED/%s", sidstr
);
1345 centry_free(centry
);
1346 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1349 /* We only have 17 bytes more data in the salted cred case. */
1350 if (centry
->len
- centry
->ofs
== 17) {
1351 *cached_salt
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1353 *cached_salt
= NULL
;
1356 dump_data_pw("cached_nt_pass", *cached_nt_pass
, NT_HASH_LEN
);
1358 dump_data_pw("cached_salt", *cached_salt
, NT_HASH_LEN
);
1361 status
= centry
->status
;
1363 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1364 sid_string_dbg(sid
), nt_errstr(status
) ));
1366 centry_free(centry
);
1370 /* Store creds for a SID - only writes out new salted ones. */
1372 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1373 const struct dom_sid
*sid
,
1374 const uint8 nt_pass
[NT_HASH_LEN
])
1376 struct cache_entry
*centry
;
1379 uint8 cred_salt
[NT_HASH_LEN
];
1380 uint8 salted_hash
[NT_HASH_LEN
];
1382 if (is_null_sid(sid
)) {
1383 return NT_STATUS_INVALID_SID
;
1386 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1387 return NT_STATUS_INVALID_SID
;
1390 centry
= centry_start(domain
, NT_STATUS_OK
);
1392 return NT_STATUS_INTERNAL_DB_ERROR
;
1395 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1397 centry_put_time(centry
, time(NULL
));
1399 /* Create a salt and then salt the hash. */
1400 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1401 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1403 centry_put_hash16(centry
, salted_hash
);
1404 centry_put_hash16(centry
, cred_salt
);
1405 centry_end(centry
, "CRED/%s", sid_to_fstring(sid_string
, sid
));
1407 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1409 centry_free(centry
);
1411 return NT_STATUS_OK
;
1415 /* Query display info. This is the basic user list fn */
1416 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
1417 TALLOC_CTX
*mem_ctx
,
1418 uint32
*num_entries
,
1419 struct wbint_userinfo
**info
)
1421 struct winbind_cache
*cache
= get_cache(domain
);
1422 struct cache_entry
*centry
= NULL
;
1424 unsigned int i
, retry
;
1425 bool old_status
= domain
->online
;
1430 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1435 *num_entries
= centry_uint32(centry
);
1437 if (*num_entries
== 0)
1440 (*info
) = talloc_array(mem_ctx
, struct wbint_userinfo
, *num_entries
);
1442 smb_panic_fn("query_user_list out of memory");
1444 for (i
=0; i
<(*num_entries
); i
++) {
1445 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
1446 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
1447 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
1448 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
1449 centry_sid(centry
, &(*info
)[i
].user_sid
);
1450 centry_sid(centry
, &(*info
)[i
].group_sid
);
1454 status
= centry
->status
;
1456 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1457 domain
->name
, nt_errstr(status
) ));
1459 centry_free(centry
);
1466 /* Return status value returned by seq number check */
1468 if (!NT_STATUS_IS_OK(domain
->last_status
))
1469 return domain
->last_status
;
1471 /* Put the query_user_list() in a retry loop. There appears to be
1472 * some bug either with Windows 2000 or Samba's handling of large
1473 * rpc replies. This manifests itself as sudden disconnection
1474 * at a random point in the enumeration of a large (60k) user list.
1475 * The retry loop simply tries the operation again. )-: It's not
1476 * pretty but an acceptable workaround until we work out what the
1477 * real problem is. */
1482 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1485 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
1486 if (!NT_STATUS_IS_OK(status
)) {
1487 DEBUG(3, ("query_user_list: returned 0x%08x, "
1488 "retrying\n", NT_STATUS_V(status
)));
1490 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1491 DEBUG(3, ("query_user_list: flushing "
1492 "connection cache\n"));
1493 invalidate_cm_connection(&domain
->conn
);
1495 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1496 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1497 if (!domain
->internal
&& old_status
) {
1498 set_domain_offline(domain
);
1500 /* store partial response. */
1501 if (*num_entries
> 0) {
1503 * humm, what about the status used for cache?
1504 * Should it be NT_STATUS_OK?
1509 * domain is offline now, and there is no user entries,
1510 * try to fetch from cache again.
1512 if (cache
->tdb
&& !domain
->online
&& !domain
->internal
&& old_status
) {
1513 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1514 /* partial response... */
1518 goto do_fetch_cache
;
1525 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1529 refresh_sequence_number(domain
, false);
1530 if (!NT_STATUS_IS_OK(status
)) {
1533 centry
= centry_start(domain
, status
);
1536 centry_put_uint32(centry
, *num_entries
);
1537 for (i
=0; i
<(*num_entries
); i
++) {
1538 centry_put_string(centry
, (*info
)[i
].acct_name
);
1539 centry_put_string(centry
, (*info
)[i
].full_name
);
1540 centry_put_string(centry
, (*info
)[i
].homedir
);
1541 centry_put_string(centry
, (*info
)[i
].shell
);
1542 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1543 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1544 if (domain
->backend
&& domain
->backend
->consistent
) {
1545 /* when the backend is consistent we can pre-prime some mappings */
1546 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1548 (*info
)[i
].acct_name
,
1549 &(*info
)[i
].user_sid
,
1551 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1552 &(*info
)[i
].user_sid
,
1554 (*info
)[i
].acct_name
,
1556 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1559 centry_end(centry
, "UL/%s", domain
->name
);
1560 centry_free(centry
);
1566 /* list all domain groups */
1567 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
1568 TALLOC_CTX
*mem_ctx
,
1569 uint32
*num_entries
,
1570 struct wb_acct_info
**info
)
1572 struct winbind_cache
*cache
= get_cache(domain
);
1573 struct cache_entry
*centry
= NULL
;
1578 old_status
= domain
->online
;
1582 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1587 *num_entries
= centry_uint32(centry
);
1589 if (*num_entries
== 0)
1592 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1594 smb_panic_fn("enum_dom_groups out of memory");
1596 for (i
=0; i
<(*num_entries
); i
++) {
1597 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1598 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1599 (*info
)[i
].rid
= centry_uint32(centry
);
1603 status
= centry
->status
;
1605 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1606 domain
->name
, nt_errstr(status
) ));
1608 centry_free(centry
);
1615 /* Return status value returned by seq number check */
1617 if (!NT_STATUS_IS_OK(domain
->last_status
))
1618 return domain
->last_status
;
1620 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1623 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1625 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1626 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1627 if (!domain
->internal
&& old_status
) {
1628 set_domain_offline(domain
);
1632 !domain
->internal
&&
1634 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1636 goto do_fetch_cache
;
1641 refresh_sequence_number(domain
, false);
1642 if (!NT_STATUS_IS_OK(status
)) {
1645 centry
= centry_start(domain
, status
);
1648 centry_put_uint32(centry
, *num_entries
);
1649 for (i
=0; i
<(*num_entries
); i
++) {
1650 centry_put_string(centry
, (*info
)[i
].acct_name
);
1651 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1652 centry_put_uint32(centry
, (*info
)[i
].rid
);
1654 centry_end(centry
, "GL/%s/domain", domain
->name
);
1655 centry_free(centry
);
1661 /* list all domain groups */
1662 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
1663 TALLOC_CTX
*mem_ctx
,
1664 uint32
*num_entries
,
1665 struct wb_acct_info
**info
)
1667 struct winbind_cache
*cache
= get_cache(domain
);
1668 struct cache_entry
*centry
= NULL
;
1673 old_status
= domain
->online
;
1677 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1682 *num_entries
= centry_uint32(centry
);
1684 if (*num_entries
== 0)
1687 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1689 smb_panic_fn("enum_dom_groups out of memory");
1691 for (i
=0; i
<(*num_entries
); i
++) {
1692 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1693 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1694 (*info
)[i
].rid
= centry_uint32(centry
);
1699 /* If we are returning cached data and the domain controller
1700 is down then we don't know whether the data is up to date
1701 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1704 if (wcache_server_down(domain
)) {
1705 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1706 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1708 status
= centry
->status
;
1710 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1711 domain
->name
, nt_errstr(status
) ));
1713 centry_free(centry
);
1720 /* Return status value returned by seq number check */
1722 if (!NT_STATUS_IS_OK(domain
->last_status
))
1723 return domain
->last_status
;
1725 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1728 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1730 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1731 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1732 if (!domain
->internal
&& old_status
) {
1733 set_domain_offline(domain
);
1736 !domain
->internal
&&
1739 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1741 goto do_fetch_cache
;
1746 refresh_sequence_number(domain
, false);
1747 if (!NT_STATUS_IS_OK(status
)) {
1750 centry
= centry_start(domain
, status
);
1753 centry_put_uint32(centry
, *num_entries
);
1754 for (i
=0; i
<(*num_entries
); i
++) {
1755 centry_put_string(centry
, (*info
)[i
].acct_name
);
1756 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1757 centry_put_uint32(centry
, (*info
)[i
].rid
);
1759 centry_end(centry
, "GL/%s/local", domain
->name
);
1760 centry_free(centry
);
1766 NTSTATUS
wcache_name_to_sid(struct winbindd_domain
*domain
,
1767 const char *domain_name
,
1769 struct dom_sid
*sid
,
1770 enum lsa_SidType
*type
)
1772 struct winbind_cache
*cache
= get_cache(domain
);
1773 struct cache_entry
*centry
;
1777 if (cache
->tdb
== NULL
) {
1778 return NT_STATUS_NOT_FOUND
;
1781 uname
= talloc_strdup_upper(talloc_tos(), name
);
1782 if (uname
== NULL
) {
1783 return NT_STATUS_NO_MEMORY
;
1786 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1788 if (centry
== NULL
) {
1789 return NT_STATUS_NOT_FOUND
;
1792 status
= centry
->status
;
1793 if (NT_STATUS_IS_OK(status
)) {
1794 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1795 centry_sid(centry
, sid
);
1798 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1799 "%s\n", domain
->name
, nt_errstr(status
) ));
1801 centry_free(centry
);
1805 /* convert a single name to a sid in a domain */
1806 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
1807 TALLOC_CTX
*mem_ctx
,
1808 const char *domain_name
,
1811 struct dom_sid
*sid
,
1812 enum lsa_SidType
*type
)
1817 old_status
= domain
->online
;
1819 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1820 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1826 /* If the seq number check indicated that there is a problem
1827 * with this DC, then return that status... except for
1828 * access_denied. This is special because the dc may be in
1829 * "restrict anonymous = 1" mode, in which case it will deny
1830 * most unauthenticated operations, but *will* allow the LSA
1831 * name-to-sid that we try as a fallback. */
1833 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1834 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1835 return domain
->last_status
;
1837 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1840 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
,
1841 name
, flags
, sid
, type
);
1843 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1844 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1845 if (!domain
->internal
&& old_status
) {
1846 set_domain_offline(domain
);
1848 if (!domain
->internal
&&
1851 NTSTATUS cache_status
;
1852 cache_status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1853 return cache_status
;
1857 refresh_sequence_number(domain
, false);
1859 if (domain
->online
&&
1860 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1861 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1863 /* Only save the reverse mapping if this was not a UPN */
1864 if (!strchr(name
, '@')) {
1865 strupper_m(discard_const_p(char, domain_name
));
1866 strlower_m(discard_const_p(char, name
));
1867 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1874 NTSTATUS
wcache_sid_to_name(struct winbindd_domain
*domain
,
1875 const struct dom_sid
*sid
,
1876 TALLOC_CTX
*mem_ctx
,
1879 enum lsa_SidType
*type
)
1881 struct winbind_cache
*cache
= get_cache(domain
);
1882 struct cache_entry
*centry
;
1886 if (cache
->tdb
== NULL
) {
1887 return NT_STATUS_NOT_FOUND
;
1890 sid_string
= sid_string_tos(sid
);
1891 if (sid_string
== NULL
) {
1892 return NT_STATUS_NO_MEMORY
;
1895 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_string
);
1896 TALLOC_FREE(sid_string
);
1897 if (centry
== NULL
) {
1898 return NT_STATUS_NOT_FOUND
;
1901 if (NT_STATUS_IS_OK(centry
->status
)) {
1902 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1903 *domain_name
= centry_string(centry
, mem_ctx
);
1904 *name
= centry_string(centry
, mem_ctx
);
1907 status
= centry
->status
;
1908 centry_free(centry
);
1910 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1911 "%s\n", domain
->name
, nt_errstr(status
) ));
1916 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1918 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1919 TALLOC_CTX
*mem_ctx
,
1920 const struct dom_sid
*sid
,
1923 enum lsa_SidType
*type
)
1928 old_status
= domain
->online
;
1929 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
1931 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1936 *domain_name
= NULL
;
1938 /* If the seq number check indicated that there is a problem
1939 * with this DC, then return that status... except for
1940 * access_denied. This is special because the dc may be in
1941 * "restrict anonymous = 1" mode, in which case it will deny
1942 * most unauthenticated operations, but *will* allow the LSA
1943 * sid-to-name that we try as a fallback. */
1945 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1946 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1947 return domain
->last_status
;
1949 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1952 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1954 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1955 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1956 if (!domain
->internal
&& old_status
) {
1957 set_domain_offline(domain
);
1959 if (!domain
->internal
&&
1962 NTSTATUS cache_status
;
1963 cache_status
= wcache_sid_to_name(domain
, sid
, mem_ctx
,
1964 domain_name
, name
, type
);
1965 return cache_status
;
1969 refresh_sequence_number(domain
, false);
1970 if (!NT_STATUS_IS_OK(status
)) {
1973 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
1975 /* We can't save the name to sid mapping here, as with sid history a
1976 * later name2sid would give the wrong sid. */
1981 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
1982 TALLOC_CTX
*mem_ctx
,
1983 const struct dom_sid
*domain_sid
,
1988 enum lsa_SidType
**types
)
1990 struct winbind_cache
*cache
= get_cache(domain
);
1992 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1997 old_status
= domain
->online
;
1998 *domain_name
= NULL
;
2006 if (num_rids
== 0) {
2007 return NT_STATUS_OK
;
2010 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2011 *types
= talloc_array(mem_ctx
, enum lsa_SidType
, num_rids
);
2013 if ((*names
== NULL
) || (*types
== NULL
)) {
2014 result
= NT_STATUS_NO_MEMORY
;
2018 have_mapped
= have_unmapped
= false;
2020 for (i
=0; i
<num_rids
; i
++) {
2022 struct cache_entry
*centry
;
2025 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2026 result
= NT_STATUS_INTERNAL_ERROR
;
2030 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2031 sid_to_fstring(tmp
, &sid
));
2036 (*types
)[i
] = SID_NAME_UNKNOWN
;
2037 (*names
)[i
] = talloc_strdup(*names
, "");
2039 if (NT_STATUS_IS_OK(centry
->status
)) {
2042 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2044 dom
= centry_string(centry
, mem_ctx
);
2045 if (*domain_name
== NULL
) {
2051 (*names
)[i
] = centry_string(centry
, *names
);
2053 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)
2054 || NT_STATUS_EQUAL(centry
->status
, STATUS_SOME_UNMAPPED
)) {
2055 have_unmapped
= true;
2058 /* something's definitely wrong */
2059 result
= centry
->status
;
2063 centry_free(centry
);
2067 return NT_STATUS_NONE_MAPPED
;
2069 if (!have_unmapped
) {
2070 return NT_STATUS_OK
;
2072 return STATUS_SOME_UNMAPPED
;
2076 TALLOC_FREE(*names
);
2077 TALLOC_FREE(*types
);
2079 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
2080 rids
, num_rids
, domain_name
,
2083 if (NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
2084 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2085 if (!domain
->internal
&& old_status
) {
2086 set_domain_offline(domain
);
2089 !domain
->internal
&&
2092 have_mapped
= have_unmapped
= false;
2094 for (i
=0; i
<num_rids
; i
++) {
2096 struct cache_entry
*centry
;
2099 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2100 result
= NT_STATUS_INTERNAL_ERROR
;
2104 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2105 sid_to_fstring(tmp
, &sid
));
2107 (*types
)[i
] = SID_NAME_UNKNOWN
;
2108 (*names
)[i
] = talloc_strdup(*names
, "");
2112 (*types
)[i
] = SID_NAME_UNKNOWN
;
2113 (*names
)[i
] = talloc_strdup(*names
, "");
2115 if (NT_STATUS_IS_OK(centry
->status
)) {
2118 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2120 dom
= centry_string(centry
, mem_ctx
);
2121 if (*domain_name
== NULL
) {
2127 (*names
)[i
] = centry_string(centry
, *names
);
2129 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)) {
2130 have_unmapped
= true;
2133 /* something's definitely wrong */
2134 result
= centry
->status
;
2138 centry_free(centry
);
2142 return NT_STATUS_NONE_MAPPED
;
2144 if (!have_unmapped
) {
2145 return NT_STATUS_OK
;
2147 return STATUS_SOME_UNMAPPED
;
2151 None of the queried rids has been found so save all negative entries
2153 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
2154 for (i
= 0; i
< num_rids
; i
++) {
2156 const char *name
= "";
2157 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
2158 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
2160 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2161 return NT_STATUS_INTERNAL_ERROR
;
2164 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2172 Some or all of the queried rids have been found.
2174 if (!NT_STATUS_IS_OK(result
) &&
2175 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
2179 refresh_sequence_number(domain
, false);
2181 for (i
=0; i
<num_rids
; i
++) {
2185 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2186 result
= NT_STATUS_INTERNAL_ERROR
;
2190 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
2191 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
2193 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2194 (*names
)[i
], (*types
)[i
]);
2200 TALLOC_FREE(*names
);
2201 TALLOC_FREE(*types
);
2205 NTSTATUS
wcache_query_user(struct winbindd_domain
*domain
,
2206 TALLOC_CTX
*mem_ctx
,
2207 const struct dom_sid
*user_sid
,
2208 struct wbint_userinfo
*info
)
2210 struct winbind_cache
*cache
= get_cache(domain
);
2211 struct cache_entry
*centry
= NULL
;
2215 if (cache
->tdb
== NULL
) {
2216 return NT_STATUS_NOT_FOUND
;
2219 sid_string
= sid_string_tos(user_sid
);
2220 if (sid_string
== NULL
) {
2221 return NT_STATUS_NO_MEMORY
;
2224 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string
);
2225 TALLOC_FREE(sid_string
);
2226 if (centry
== NULL
) {
2227 return NT_STATUS_NOT_FOUND
;
2231 * If we have an access denied cache entry and a cached info3
2232 * in the samlogon cache then do a query. This will force the
2233 * rpc back end to return the info3 data.
2236 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
) &&
2237 netsamlogon_cache_have(user_sid
)) {
2238 DEBUG(10, ("query_user: cached access denied and have cached "
2240 domain
->last_status
= NT_STATUS_OK
;
2241 centry_free(centry
);
2242 return NT_STATUS_NOT_FOUND
;
2245 /* if status is not ok then this is a negative hit
2246 and the rest of the data doesn't matter */
2247 status
= centry
->status
;
2248 if (NT_STATUS_IS_OK(status
)) {
2249 info
->acct_name
= centry_string(centry
, mem_ctx
);
2250 info
->full_name
= centry_string(centry
, mem_ctx
);
2251 info
->homedir
= centry_string(centry
, mem_ctx
);
2252 info
->shell
= centry_string(centry
, mem_ctx
);
2253 info
->primary_gid
= centry_uint32(centry
);
2254 centry_sid(centry
, &info
->user_sid
);
2255 centry_sid(centry
, &info
->group_sid
);
2258 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2259 "%s\n", domain
->name
, nt_errstr(status
) ));
2261 centry_free(centry
);
2265 /* Lookup user information from a rid */
2266 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
2267 TALLOC_CTX
*mem_ctx
,
2268 const struct dom_sid
*user_sid
,
2269 struct wbint_userinfo
*info
)
2274 old_status
= domain
->online
;
2275 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2276 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2282 /* Return status value returned by seq number check */
2284 if (!NT_STATUS_IS_OK(domain
->last_status
))
2285 return domain
->last_status
;
2287 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2290 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
2292 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2293 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2294 if (!domain
->internal
&& old_status
) {
2295 set_domain_offline(domain
);
2297 if (!domain
->internal
&&
2300 NTSTATUS cache_status
;
2301 cache_status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2302 return cache_status
;
2306 refresh_sequence_number(domain
, false);
2307 if (!NT_STATUS_IS_OK(status
)) {
2310 wcache_save_user(domain
, status
, info
);
2315 NTSTATUS
wcache_lookup_usergroups(struct winbindd_domain
*domain
,
2316 TALLOC_CTX
*mem_ctx
,
2317 const struct dom_sid
*user_sid
,
2318 uint32_t *pnum_sids
,
2319 struct dom_sid
**psids
)
2321 struct winbind_cache
*cache
= get_cache(domain
);
2322 struct cache_entry
*centry
= NULL
;
2324 uint32_t i
, num_sids
;
2325 struct dom_sid
*sids
;
2328 if (cache
->tdb
== NULL
) {
2329 return NT_STATUS_NOT_FOUND
;
2332 centry
= wcache_fetch(cache
, domain
, "UG/%s",
2333 sid_to_fstring(sid_string
, user_sid
));
2334 if (centry
== NULL
) {
2335 return NT_STATUS_NOT_FOUND
;
2338 /* If we have an access denied cache entry and a cached info3 in the
2339 samlogon cache then do a query. This will force the rpc back end
2340 to return the info3 data. */
2342 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)
2343 && netsamlogon_cache_have(user_sid
)) {
2344 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2346 domain
->last_status
= NT_STATUS_OK
;
2347 centry_free(centry
);
2348 return NT_STATUS_NOT_FOUND
;
2351 num_sids
= centry_uint32(centry
);
2352 sids
= talloc_array(mem_ctx
, struct dom_sid
, num_sids
);
2354 centry_free(centry
);
2355 return NT_STATUS_NO_MEMORY
;
2358 for (i
=0; i
<num_sids
; i
++) {
2359 centry_sid(centry
, &sids
[i
]);
2362 status
= centry
->status
;
2364 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2365 "status: %s\n", domain
->name
, nt_errstr(status
)));
2367 centry_free(centry
);
2369 *pnum_sids
= num_sids
;
2374 /* Lookup groups a user is a member of. */
2375 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
2376 TALLOC_CTX
*mem_ctx
,
2377 const struct dom_sid
*user_sid
,
2378 uint32
*num_groups
, struct dom_sid
**user_gids
)
2380 struct cache_entry
*centry
= NULL
;
2386 old_status
= domain
->online
;
2387 status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2388 num_groups
, user_gids
);
2389 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2394 (*user_gids
) = NULL
;
2396 /* Return status value returned by seq number check */
2398 if (!NT_STATUS_IS_OK(domain
->last_status
))
2399 return domain
->last_status
;
2401 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2404 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
2406 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2407 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2408 if (!domain
->internal
&& old_status
) {
2409 set_domain_offline(domain
);
2411 if (!domain
->internal
&&
2414 NTSTATUS cache_status
;
2415 cache_status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2416 num_groups
, user_gids
);
2417 return cache_status
;
2420 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
2424 refresh_sequence_number(domain
, false);
2425 if (!NT_STATUS_IS_OK(status
)) {
2428 centry
= centry_start(domain
, status
);
2432 centry_put_uint32(centry
, *num_groups
);
2433 for (i
=0; i
<(*num_groups
); i
++) {
2434 centry_put_sid(centry
, &(*user_gids
)[i
]);
2437 centry_end(centry
, "UG/%s", sid_to_fstring(sid_string
, user_sid
));
2438 centry_free(centry
);
2444 static char *wcache_make_sidlist(TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2445 const struct dom_sid
*sids
)
2450 sidlist
= talloc_strdup(mem_ctx
, "");
2451 if (sidlist
== NULL
) {
2454 for (i
=0; i
<num_sids
; i
++) {
2456 sidlist
= talloc_asprintf_append_buffer(
2457 sidlist
, "/%s", sid_to_fstring(tmp
, &sids
[i
]));
2458 if (sidlist
== NULL
) {
2465 NTSTATUS
wcache_lookup_useraliases(struct winbindd_domain
*domain
,
2466 TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2467 const struct dom_sid
*sids
,
2468 uint32_t *pnum_aliases
, uint32_t **paliases
)
2470 struct winbind_cache
*cache
= get_cache(domain
);
2471 struct cache_entry
*centry
= NULL
;
2472 uint32_t num_aliases
;
2478 if (cache
->tdb
== NULL
) {
2479 return NT_STATUS_NOT_FOUND
;
2482 if (num_sids
== 0) {
2485 return NT_STATUS_OK
;
2488 /* We need to cache indexed by the whole list of SIDs, the aliases
2489 * resulting might come from any of the SIDs. */
2491 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2492 if (sidlist
== NULL
) {
2493 return NT_STATUS_NO_MEMORY
;
2496 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2497 TALLOC_FREE(sidlist
);
2498 if (centry
== NULL
) {
2499 return NT_STATUS_NOT_FOUND
;
2502 num_aliases
= centry_uint32(centry
);
2503 aliases
= talloc_array(mem_ctx
, uint32_t, num_aliases
);
2504 if (aliases
== NULL
) {
2505 centry_free(centry
);
2506 return NT_STATUS_NO_MEMORY
;
2509 for (i
=0; i
<num_aliases
; i
++) {
2510 aliases
[i
] = centry_uint32(centry
);
2513 status
= centry
->status
;
2515 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2516 "status %s\n", domain
->name
, nt_errstr(status
)));
2518 centry_free(centry
);
2520 *pnum_aliases
= num_aliases
;
2521 *paliases
= aliases
;
2526 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
2527 TALLOC_CTX
*mem_ctx
,
2528 uint32 num_sids
, const struct dom_sid
*sids
,
2529 uint32
*num_aliases
, uint32
**alias_rids
)
2531 struct cache_entry
*centry
= NULL
;
2537 old_status
= domain
->online
;
2538 status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
2539 num_aliases
, alias_rids
);
2540 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2545 (*alias_rids
) = NULL
;
2547 if (!NT_STATUS_IS_OK(domain
->last_status
))
2548 return domain
->last_status
;
2550 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2551 "for domain %s\n", domain
->name
));
2553 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2554 if (sidlist
== NULL
) {
2555 return NT_STATUS_NO_MEMORY
;
2558 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2560 num_aliases
, alias_rids
);
2562 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2563 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2564 if (!domain
->internal
&& old_status
) {
2565 set_domain_offline(domain
);
2567 if (!domain
->internal
&&
2570 NTSTATUS cache_status
;
2571 cache_status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
,
2572 sids
, num_aliases
, alias_rids
);
2573 return cache_status
;
2577 refresh_sequence_number(domain
, false);
2578 if (!NT_STATUS_IS_OK(status
)) {
2581 centry
= centry_start(domain
, status
);
2584 centry_put_uint32(centry
, *num_aliases
);
2585 for (i
=0; i
<(*num_aliases
); i
++)
2586 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2587 centry_end(centry
, "UA%s", sidlist
);
2588 centry_free(centry
);
2594 NTSTATUS
wcache_lookup_groupmem(struct winbindd_domain
*domain
,
2595 TALLOC_CTX
*mem_ctx
,
2596 const struct dom_sid
*group_sid
,
2597 uint32_t *num_names
,
2598 struct dom_sid
**sid_mem
, char ***names
,
2599 uint32_t **name_types
)
2601 struct winbind_cache
*cache
= get_cache(domain
);
2602 struct cache_entry
*centry
= NULL
;
2607 if (cache
->tdb
== NULL
) {
2608 return NT_STATUS_NOT_FOUND
;
2611 sid_string
= sid_string_tos(group_sid
);
2612 if (sid_string
== NULL
) {
2613 return NT_STATUS_NO_MEMORY
;
2616 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_string
);
2617 TALLOC_FREE(sid_string
);
2618 if (centry
== NULL
) {
2619 return NT_STATUS_NOT_FOUND
;
2626 *num_names
= centry_uint32(centry
);
2627 if (*num_names
== 0) {
2628 centry_free(centry
);
2629 return NT_STATUS_OK
;
2632 *sid_mem
= talloc_array(mem_ctx
, struct dom_sid
, *num_names
);
2633 *names
= talloc_array(mem_ctx
, char *, *num_names
);
2634 *name_types
= talloc_array(mem_ctx
, uint32
, *num_names
);
2636 if ((*sid_mem
== NULL
) || (*names
== NULL
) || (*name_types
== NULL
)) {
2637 TALLOC_FREE(*sid_mem
);
2638 TALLOC_FREE(*names
);
2639 TALLOC_FREE(*name_types
);
2640 centry_free(centry
);
2641 return NT_STATUS_NO_MEMORY
;
2644 for (i
=0; i
<(*num_names
); i
++) {
2645 centry_sid(centry
, &(*sid_mem
)[i
]);
2646 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2647 (*name_types
)[i
] = centry_uint32(centry
);
2650 status
= centry
->status
;
2652 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2653 "status: %s\n", domain
->name
, nt_errstr(status
)));
2655 centry_free(centry
);
2659 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
2660 TALLOC_CTX
*mem_ctx
,
2661 const struct dom_sid
*group_sid
,
2662 enum lsa_SidType type
,
2664 struct dom_sid
**sid_mem
, char ***names
,
2665 uint32
**name_types
)
2667 struct cache_entry
*centry
= NULL
;
2673 old_status
= domain
->online
;
2674 status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2675 sid_mem
, names
, name_types
);
2676 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2683 (*name_types
) = NULL
;
2685 /* Return status value returned by seq number check */
2687 if (!NT_STATUS_IS_OK(domain
->last_status
))
2688 return domain
->last_status
;
2690 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2693 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
,
2695 sid_mem
, names
, name_types
);
2697 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2698 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2699 if (!domain
->internal
&& old_status
) {
2700 set_domain_offline(domain
);
2702 if (!domain
->internal
&&
2705 NTSTATUS cache_status
;
2706 cache_status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
,
2707 num_names
, sid_mem
, names
,
2709 return cache_status
;
2713 refresh_sequence_number(domain
, false);
2714 if (!NT_STATUS_IS_OK(status
)) {
2717 centry
= centry_start(domain
, status
);
2720 centry_put_uint32(centry
, *num_names
);
2721 for (i
=0; i
<(*num_names
); i
++) {
2722 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2723 centry_put_string(centry
, (*names
)[i
]);
2724 centry_put_uint32(centry
, (*name_types
)[i
]);
2726 centry_end(centry
, "GM/%s", sid_to_fstring(sid_string
, group_sid
));
2727 centry_free(centry
);
2733 /* find the sequence number for a domain */
2734 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
2736 refresh_sequence_number(domain
, false);
2738 *seq
= domain
->sequence_number
;
2740 return NT_STATUS_OK
;
2743 /* enumerate trusted domains
2744 * (we need to have the list of trustdoms in the cache when we go offline) -
2746 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
2747 TALLOC_CTX
*mem_ctx
,
2748 struct netr_DomainTrustList
*trusts
)
2751 struct winbind_cache
*cache
;
2752 struct winbindd_tdc_domain
*dom_list
= NULL
;
2753 size_t num_domains
= 0;
2754 bool retval
= false;
2758 old_status
= domain
->online
;
2760 trusts
->array
= NULL
;
2762 cache
= get_cache(domain
);
2763 if (!cache
|| !cache
->tdb
) {
2767 if (domain
->online
) {
2771 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2772 if (!retval
|| !num_domains
|| !dom_list
) {
2773 TALLOC_FREE(dom_list
);
2778 trusts
->array
= talloc_zero_array(mem_ctx
, struct netr_DomainTrust
, num_domains
);
2779 if (!trusts
->array
) {
2780 TALLOC_FREE(dom_list
);
2781 return NT_STATUS_NO_MEMORY
;
2784 for (i
= 0; i
< num_domains
; i
++) {
2785 struct netr_DomainTrust
*trust
;
2786 struct dom_sid
*sid
;
2787 struct winbindd_domain
*dom
;
2789 dom
= find_domain_from_name_noinit(dom_list
[i
].domain_name
);
2790 if (dom
&& dom
->internal
) {
2794 trust
= &trusts
->array
[trusts
->count
];
2795 trust
->netbios_name
= talloc_strdup(trusts
->array
, dom_list
[i
].domain_name
);
2796 trust
->dns_name
= talloc_strdup(trusts
->array
, dom_list
[i
].dns_name
);
2797 sid
= talloc(trusts
->array
, struct dom_sid
);
2798 if (!trust
->netbios_name
|| !trust
->dns_name
||
2800 TALLOC_FREE(dom_list
);
2801 TALLOC_FREE(trusts
->array
);
2802 return NT_STATUS_NO_MEMORY
;
2805 trust
->trust_flags
= dom_list
[i
].trust_flags
;
2806 trust
->trust_attributes
= dom_list
[i
].trust_attribs
;
2807 trust
->trust_type
= dom_list
[i
].trust_type
;
2808 sid_copy(sid
, &dom_list
[i
].sid
);
2813 TALLOC_FREE(dom_list
);
2814 return NT_STATUS_OK
;
2817 /* Return status value returned by seq number check */
2819 if (!NT_STATUS_IS_OK(domain
->last_status
))
2820 return domain
->last_status
;
2822 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2825 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, trusts
);
2827 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2828 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2829 if (!domain
->internal
&& old_status
) {
2830 set_domain_offline(domain
);
2832 if (!domain
->internal
&&
2835 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2836 if (retval
&& num_domains
&& dom_list
) {
2837 TALLOC_FREE(trusts
->array
);
2839 goto do_fetch_cache
;
2843 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2844 * so that the generic centry handling still applies correctly -
2847 if (!NT_STATUS_IS_ERR(status
)) {
2848 status
= NT_STATUS_OK
;
2853 /* get lockout policy */
2854 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
2855 TALLOC_CTX
*mem_ctx
,
2856 struct samr_DomInfo12
*policy
)
2858 struct winbind_cache
*cache
= get_cache(domain
);
2859 struct cache_entry
*centry
= NULL
;
2863 old_status
= domain
->online
;
2867 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2873 policy
->lockout_duration
= centry_nttime(centry
);
2874 policy
->lockout_window
= centry_nttime(centry
);
2875 policy
->lockout_threshold
= centry_uint16(centry
);
2877 status
= centry
->status
;
2879 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2880 domain
->name
, nt_errstr(status
) ));
2882 centry_free(centry
);
2886 ZERO_STRUCTP(policy
);
2888 /* Return status value returned by seq number check */
2890 if (!NT_STATUS_IS_OK(domain
->last_status
))
2891 return domain
->last_status
;
2893 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2896 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2898 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2899 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2900 if (!domain
->internal
&& old_status
) {
2901 set_domain_offline(domain
);
2904 !domain
->internal
&&
2907 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2909 goto do_fetch_cache
;
2914 refresh_sequence_number(domain
, false);
2915 if (!NT_STATUS_IS_OK(status
)) {
2918 wcache_save_lockout_policy(domain
, status
, policy
);
2923 /* get password policy */
2924 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
2925 TALLOC_CTX
*mem_ctx
,
2926 struct samr_DomInfo1
*policy
)
2928 struct winbind_cache
*cache
= get_cache(domain
);
2929 struct cache_entry
*centry
= NULL
;
2933 old_status
= domain
->online
;
2937 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2943 policy
->min_password_length
= centry_uint16(centry
);
2944 policy
->password_history_length
= centry_uint16(centry
);
2945 policy
->password_properties
= centry_uint32(centry
);
2946 policy
->max_password_age
= centry_nttime(centry
);
2947 policy
->min_password_age
= centry_nttime(centry
);
2949 status
= centry
->status
;
2951 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2952 domain
->name
, nt_errstr(status
) ));
2954 centry_free(centry
);
2958 ZERO_STRUCTP(policy
);
2960 /* Return status value returned by seq number check */
2962 if (!NT_STATUS_IS_OK(domain
->last_status
))
2963 return domain
->last_status
;
2965 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2968 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
2970 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2971 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2972 if (!domain
->internal
&& old_status
) {
2973 set_domain_offline(domain
);
2976 !domain
->internal
&&
2979 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2981 goto do_fetch_cache
;
2986 refresh_sequence_number(domain
, false);
2987 if (!NT_STATUS_IS_OK(status
)) {
2990 wcache_save_password_policy(domain
, status
, policy
);
2996 /* Invalidate cached user and group lists coherently */
2998 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3001 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
3002 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
3003 tdb_delete(the_tdb
, kbuf
);
3008 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3010 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
3011 const struct dom_sid
*sid
)
3013 fstring key_str
, sid_string
;
3014 struct winbind_cache
*cache
;
3016 /* dont clear cached U/SID and UG/SID entries when we want to logon
3019 if (lp_winbind_offline_logon()) {
3026 cache
= get_cache(domain
);
3032 /* Clear U/SID cache entry */
3033 fstr_sprintf(key_str
, "U/%s", sid_to_fstring(sid_string
, sid
));
3034 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3035 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3037 /* Clear UG/SID cache entry */
3038 fstr_sprintf(key_str
, "UG/%s", sid_to_fstring(sid_string
, sid
));
3039 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3040 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3042 /* Samba/winbindd never needs this. */
3043 netsamlogon_clear_cached_user(sid
);
3046 bool wcache_invalidate_cache(void)
3048 struct winbindd_domain
*domain
;
3050 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3051 struct winbind_cache
*cache
= get_cache(domain
);
3053 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3054 "entries for %s\n", domain
->name
));
3057 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3066 bool wcache_invalidate_cache_noinit(void)
3068 struct winbindd_domain
*domain
;
3070 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3071 struct winbind_cache
*cache
;
3073 /* Skip uninitialized domains. */
3074 if (!domain
->initialized
&& !domain
->internal
) {
3078 cache
= get_cache(domain
);
3080 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3081 "entries for %s\n", domain
->name
));
3084 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3086 * Flushing cache has nothing to with domains.
3087 * return here if we successfully flushed once.
3088 * To avoid unnecessary traversing the cache.
3099 bool init_wcache(void)
3101 if (wcache
== NULL
) {
3102 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
3103 ZERO_STRUCTP(wcache
);
3106 if (wcache
->tdb
!= NULL
)
3109 /* when working offline we must not clear the cache on restart */
3110 wcache
->tdb
= tdb_open_log(state_path("winbindd_cache.tdb"),
3111 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3112 TDB_INCOMPATIBLE_HASH
|
3113 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3114 O_RDWR
|O_CREAT
, 0600);
3116 if (wcache
->tdb
== NULL
) {
3117 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3124 /************************************************************************
3125 This is called by the parent to initialize the cache file.
3126 We don't need sophisticated locking here as we know we're the
3128 ************************************************************************/
3130 bool initialize_winbindd_cache(void)
3132 bool cache_bad
= true;
3135 if (!init_wcache()) {
3136 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3140 /* Check version number. */
3141 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
3142 vers
== WINBINDD_CACHE_VERSION
) {
3147 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3148 "and re-creating with version number %d\n",
3149 WINBINDD_CACHE_VERSION
));
3151 tdb_close(wcache
->tdb
);
3154 if (unlink(state_path("winbindd_cache.tdb")) == -1) {
3155 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3156 state_path("winbindd_cache.tdb"),
3160 if (!init_wcache()) {
3161 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3162 "init_wcache failed.\n"));
3166 /* Write the version. */
3167 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
3168 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3169 tdb_errorstr_compat(wcache
->tdb
) ));
3174 tdb_close(wcache
->tdb
);
3179 void close_winbindd_cache(void)
3185 tdb_close(wcache
->tdb
);
3190 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*sid
,
3191 char **domain_name
, char **name
,
3192 enum lsa_SidType
*type
)
3194 struct winbindd_domain
*domain
;
3197 domain
= find_lookup_domain_from_sid(sid
);
3198 if (domain
== NULL
) {
3201 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
3203 return NT_STATUS_IS_OK(status
);
3206 bool lookup_cached_name(const char *domain_name
,
3208 struct dom_sid
*sid
,
3209 enum lsa_SidType
*type
)
3211 struct winbindd_domain
*domain
;
3213 bool original_online_state
;
3215 domain
= find_lookup_domain_from_name(domain_name
);
3216 if (domain
== NULL
) {
3220 /* If we are doing a cached logon, temporarily set the domain
3221 offline so the cache won't expire the entry */
3223 original_online_state
= domain
->online
;
3224 domain
->online
= false;
3225 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
3226 domain
->online
= original_online_state
;
3228 return NT_STATUS_IS_OK(status
);
3231 void cache_name2sid(struct winbindd_domain
*domain
,
3232 const char *domain_name
, const char *name
,
3233 enum lsa_SidType type
, const struct dom_sid
*sid
)
3235 refresh_sequence_number(domain
, false);
3236 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
3241 * The original idea that this cache only contains centries has
3242 * been blurred - now other stuff gets put in here. Ensure we
3243 * ignore these things on cleanup.
3246 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
3247 TDB_DATA dbuf
, void *state
)
3249 struct cache_entry
*centry
;
3251 if (is_non_centry_key(kbuf
)) {
3255 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
3260 if (!NT_STATUS_IS_OK(centry
->status
)) {
3261 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
3262 tdb_delete(the_tdb
, kbuf
);
3265 centry_free(centry
);
3269 /* flush the cache */
3270 void wcache_flush_cache(void)
3275 tdb_close(wcache
->tdb
);
3278 if (!winbindd_use_cache()) {
3282 /* when working offline we must not clear the cache on restart */
3283 wcache
->tdb
= tdb_open_log(state_path("winbindd_cache.tdb"),
3284 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3285 TDB_INCOMPATIBLE_HASH
|
3286 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3287 O_RDWR
|O_CREAT
, 0600);
3290 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3294 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
3296 DEBUG(10,("wcache_flush_cache success\n"));
3299 /* Count cached creds */
3301 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3304 int *cred_count
= (int*)state
;
3306 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3312 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
3314 struct winbind_cache
*cache
= get_cache(domain
);
3319 return NT_STATUS_INTERNAL_DB_ERROR
;
3322 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
3324 return NT_STATUS_OK
;
3328 struct cred_list
*prev
, *next
;
3333 static struct cred_list
*wcache_cred_list
;
3335 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3338 struct cred_list
*cred
;
3340 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3342 cred
= SMB_MALLOC_P(struct cred_list
);
3344 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3350 /* save a copy of the key */
3352 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
3353 DLIST_ADD(wcache_cred_list
, cred
);
3359 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
3361 struct winbind_cache
*cache
= get_cache(domain
);
3364 struct cred_list
*cred
, *oldest
= NULL
;
3367 return NT_STATUS_INTERNAL_DB_ERROR
;
3370 /* we possibly already have an entry */
3371 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
3373 fstring key_str
, tmp
;
3375 DEBUG(11,("we already have an entry, deleting that\n"));
3377 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
3379 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3381 return NT_STATUS_OK
;
3384 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
3386 return NT_STATUS_OK
;
3387 } else if ((ret
< 0) || (wcache_cred_list
== NULL
)) {
3388 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3391 ZERO_STRUCTP(oldest
);
3393 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
3398 data
= tdb_fetch_compat(cache
->tdb
, string_tdb_data(cred
->name
));
3400 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3402 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3406 t
= IVAL(data
.dptr
, 0);
3407 SAFE_FREE(data
.dptr
);
3410 oldest
= SMB_MALLOC_P(struct cred_list
);
3411 if (oldest
== NULL
) {
3412 status
= NT_STATUS_NO_MEMORY
;
3416 fstrcpy(oldest
->name
, cred
->name
);
3417 oldest
->created
= t
;
3421 if (t
< oldest
->created
) {
3422 fstrcpy(oldest
->name
, cred
->name
);
3423 oldest
->created
= t
;
3427 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3428 status
= NT_STATUS_OK
;
3430 status
= NT_STATUS_UNSUCCESSFUL
;
3433 SAFE_FREE(wcache_cred_list
);
3439 /* Change the global online/offline state. */
3440 bool set_global_winbindd_state_offline(void)
3444 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3446 /* Only go offline if someone has created
3447 the key "WINBINDD_OFFLINE" in the cache tdb. */
3449 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3450 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3454 if (!lp_winbind_offline_logon()) {
3455 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3459 if (global_winbindd_offline_state
) {
3460 /* Already offline. */
3464 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
3466 if (!data
.dptr
|| data
.dsize
!= 4) {
3467 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3468 SAFE_FREE(data
.dptr
);
3471 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3472 global_winbindd_offline_state
= true;
3473 SAFE_FREE(data
.dptr
);
3478 void set_global_winbindd_state_online(void)
3480 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3482 if (!lp_winbind_offline_logon()) {
3483 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3487 if (!global_winbindd_offline_state
) {
3488 /* Already online. */
3491 global_winbindd_offline_state
= false;
3497 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3498 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3501 bool get_global_winbindd_state_offline(void)
3503 return global_winbindd_offline_state
;
3506 /***********************************************************************
3507 Validate functions for all possible cache tdb keys.
3508 ***********************************************************************/
3510 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3511 struct tdb_validation_status
*state
)
3513 struct cache_entry
*centry
;
3515 centry
= SMB_XMALLOC_P(struct cache_entry
);
3516 centry
->data
= (unsigned char *)memdup(data
.dptr
, data
.dsize
);
3517 if (!centry
->data
) {
3521 centry
->len
= data
.dsize
;
3524 if (centry
->len
< 16) {
3525 /* huh? corrupt cache? */
3526 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3527 "(len < 16) ?\n", kstr
));
3528 centry_free(centry
);
3529 state
->bad_entry
= true;
3530 state
->success
= false;
3534 centry
->status
= NT_STATUS(centry_uint32(centry
));
3535 centry
->sequence_number
= centry_uint32(centry
);
3536 centry
->timeout
= centry_uint64_t(centry
);
3540 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3541 struct tdb_validation_status
*state
)
3543 if (dbuf
.dsize
!= 8) {
3544 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3545 keystr
, (unsigned int)dbuf
.dsize
));
3546 state
->bad_entry
= true;
3552 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3553 struct tdb_validation_status
*state
)
3555 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3560 (void)centry_uint32(centry
);
3561 if (NT_STATUS_IS_OK(centry
->status
)) {
3563 (void)centry_sid(centry
, &sid
);
3566 centry_free(centry
);
3568 if (!(state
->success
)) {
3571 DEBUG(10,("validate_ns: %s ok\n", keystr
));
3575 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3576 struct tdb_validation_status
*state
)
3578 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3583 if (NT_STATUS_IS_OK(centry
->status
)) {
3584 (void)centry_uint32(centry
);
3585 (void)centry_string(centry
, mem_ctx
);
3586 (void)centry_string(centry
, mem_ctx
);
3589 centry_free(centry
);
3591 if (!(state
->success
)) {
3594 DEBUG(10,("validate_sn: %s ok\n", keystr
));
3598 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3599 struct tdb_validation_status
*state
)
3601 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3608 (void)centry_string(centry
, mem_ctx
);
3609 (void)centry_string(centry
, mem_ctx
);
3610 (void)centry_string(centry
, mem_ctx
);
3611 (void)centry_string(centry
, mem_ctx
);
3612 (void)centry_uint32(centry
);
3613 (void)centry_sid(centry
, &sid
);
3614 (void)centry_sid(centry
, &sid
);
3616 centry_free(centry
);
3618 if (!(state
->success
)) {
3621 DEBUG(10,("validate_u: %s ok\n", keystr
));
3625 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3626 struct tdb_validation_status
*state
)
3628 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3634 (void)centry_nttime(centry
);
3635 (void)centry_nttime(centry
);
3636 (void)centry_uint16(centry
);
3638 centry_free(centry
);
3640 if (!(state
->success
)) {
3643 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3647 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3648 struct tdb_validation_status
*state
)
3650 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3656 (void)centry_uint16(centry
);
3657 (void)centry_uint16(centry
);
3658 (void)centry_uint32(centry
);
3659 (void)centry_nttime(centry
);
3660 (void)centry_nttime(centry
);
3662 centry_free(centry
);
3664 if (!(state
->success
)) {
3667 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3671 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3672 struct tdb_validation_status
*state
)
3674 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3680 (void)centry_time(centry
);
3681 (void)centry_hash16(centry
, mem_ctx
);
3683 /* We only have 17 bytes more data in the salted cred case. */
3684 if (centry
->len
- centry
->ofs
== 17) {
3685 (void)centry_hash16(centry
, mem_ctx
);
3688 centry_free(centry
);
3690 if (!(state
->success
)) {
3693 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3697 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3698 struct tdb_validation_status
*state
)
3700 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3701 int32 num_entries
, i
;
3707 num_entries
= (int32
)centry_uint32(centry
);
3709 for (i
=0; i
< num_entries
; i
++) {
3711 (void)centry_string(centry
, mem_ctx
);
3712 (void)centry_string(centry
, mem_ctx
);
3713 (void)centry_string(centry
, mem_ctx
);
3714 (void)centry_string(centry
, mem_ctx
);
3715 (void)centry_sid(centry
, &sid
);
3716 (void)centry_sid(centry
, &sid
);
3719 centry_free(centry
);
3721 if (!(state
->success
)) {
3724 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3728 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3729 struct tdb_validation_status
*state
)
3731 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3732 int32 num_entries
, i
;
3738 num_entries
= centry_uint32(centry
);
3740 for (i
=0; i
< num_entries
; i
++) {
3741 (void)centry_string(centry
, mem_ctx
);
3742 (void)centry_string(centry
, mem_ctx
);
3743 (void)centry_uint32(centry
);
3746 centry_free(centry
);
3748 if (!(state
->success
)) {
3751 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3755 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3756 struct tdb_validation_status
*state
)
3758 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3759 int32 num_groups
, i
;
3765 num_groups
= centry_uint32(centry
);
3767 for (i
=0; i
< num_groups
; i
++) {
3769 centry_sid(centry
, &sid
);
3772 centry_free(centry
);
3774 if (!(state
->success
)) {
3777 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3781 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3782 struct tdb_validation_status
*state
)
3784 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3785 int32 num_aliases
, i
;
3791 num_aliases
= centry_uint32(centry
);
3793 for (i
=0; i
< num_aliases
; i
++) {
3794 (void)centry_uint32(centry
);
3797 centry_free(centry
);
3799 if (!(state
->success
)) {
3802 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3806 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3807 struct tdb_validation_status
*state
)
3809 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3816 num_names
= centry_uint32(centry
);
3818 for (i
=0; i
< num_names
; i
++) {
3820 centry_sid(centry
, &sid
);
3821 (void)centry_string(centry
, mem_ctx
);
3822 (void)centry_uint32(centry
);
3825 centry_free(centry
);
3827 if (!(state
->success
)) {
3830 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3834 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3835 struct tdb_validation_status
*state
)
3837 /* Can't say anything about this other than must be nonzero. */
3838 if (dbuf
.dsize
== 0) {
3839 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3841 state
->bad_entry
= true;
3842 state
->success
= false;
3846 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3850 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3851 struct tdb_validation_status
*state
)
3853 /* Can't say anything about this other than must be nonzero. */
3854 if (dbuf
.dsize
== 0) {
3855 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3857 state
->bad_entry
= true;
3858 state
->success
= false;
3862 DEBUG(10,("validate_de: %s ok\n", keystr
));
3866 static int validate_pwinfo(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3867 TDB_DATA dbuf
, struct tdb_validation_status
*state
)
3869 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3875 (void)centry_string(centry
, mem_ctx
);
3876 (void)centry_string(centry
, mem_ctx
);
3877 (void)centry_string(centry
, mem_ctx
);
3878 (void)centry_uint32(centry
);
3880 centry_free(centry
);
3882 if (!(state
->success
)) {
3885 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3889 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3891 struct tdb_validation_status
*state
)
3893 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3899 (void)centry_string( centry
, mem_ctx
);
3901 centry_free(centry
);
3903 if (!(state
->success
)) {
3906 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3910 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3912 struct tdb_validation_status
*state
)
3914 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3920 (void)centry_string( centry
, mem_ctx
);
3922 centry_free(centry
);
3924 if (!(state
->success
)) {
3927 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3931 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3933 struct tdb_validation_status
*state
)
3935 if (dbuf
.dsize
== 0) {
3936 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3937 "key %s (len ==0) ?\n", keystr
));
3938 state
->bad_entry
= true;
3939 state
->success
= false;
3943 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3944 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3948 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3949 struct tdb_validation_status
*state
)
3951 if (dbuf
.dsize
!= 4) {
3952 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3953 keystr
, (unsigned int)dbuf
.dsize
));
3954 state
->bad_entry
= true;
3955 state
->success
= false;
3958 DEBUG(10,("validate_offline: %s ok\n", keystr
));
3962 static int validate_ndr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3963 struct tdb_validation_status
*state
)
3966 * Ignore validation for now. The proper way to do this is with a
3967 * checksum. Just pure parsing does not really catch much.
3972 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3973 struct tdb_validation_status
*state
)
3975 if (dbuf
.dsize
!= 4) {
3976 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3977 "key %s (len %u != 4) ?\n",
3978 keystr
, (unsigned int)dbuf
.dsize
));
3979 state
->bad_entry
= true;
3980 state
->success
= false;
3984 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
3988 /***********************************************************************
3989 A list of all possible cache tdb keys with associated validation
3991 ***********************************************************************/
3993 struct key_val_struct
{
3994 const char *keyname
;
3995 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
3997 {"SEQNUM/", validate_seqnum
},
3998 {"NS/", validate_ns
},
3999 {"SN/", validate_sn
},
4001 {"LOC_POL/", validate_loc_pol
},
4002 {"PWD_POL/", validate_pwd_pol
},
4003 {"CRED/", validate_cred
},
4004 {"UL/", validate_ul
},
4005 {"GL/", validate_gl
},
4006 {"UG/", validate_ug
},
4007 {"UA", validate_ua
},
4008 {"GM/", validate_gm
},
4009 {"DR/", validate_dr
},
4010 {"DE/", validate_de
},
4011 {"NSS/PWINFO/", validate_pwinfo
},
4012 {"TRUSTDOMCACHE/", validate_trustdomcache
},
4013 {"NSS/NA/", validate_nss_na
},
4014 {"NSS/AN/", validate_nss_an
},
4015 {"WINBINDD_OFFLINE", validate_offline
},
4016 {"NDR/", validate_ndr
},
4017 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
4021 /***********************************************************************
4022 Function to look at every entry in the tdb and validate it as far as
4024 ***********************************************************************/
4026 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
4029 unsigned int max_key_len
= 1024;
4030 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
4032 /* Paranoia check. */
4033 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0) {
4034 max_key_len
= 1024 * 1024;
4036 if (kbuf
.dsize
> max_key_len
) {
4037 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4039 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
4043 for (i
= 0; key_val
[i
].keyname
; i
++) {
4044 size_t namelen
= strlen(key_val
[i
].keyname
);
4045 if (kbuf
.dsize
>= namelen
&& (
4046 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
4047 TALLOC_CTX
*mem_ctx
;
4051 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
4055 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
4056 keystr
[kbuf
.dsize
] = '\0';
4058 mem_ctx
= talloc_init("validate_ctx");
4064 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
4068 talloc_destroy(mem_ctx
);
4073 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4074 dump_data(0, (uint8
*)kbuf
.dptr
, kbuf
.dsize
);
4075 DEBUG(0,("data :\n"));
4076 dump_data(0, (uint8
*)dbuf
.dptr
, dbuf
.dsize
);
4077 v_state
->unknown_key
= true;
4078 v_state
->success
= false;
4079 return 1; /* terminate. */
4082 static void validate_panic(const char *const why
)
4084 DEBUG(0,("validating cache: would panic %s\n", why
));
4085 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4089 static int wbcache_update_centry_fn(TDB_CONTEXT
*tdb
,
4097 if (is_non_centry_key(key
)) {
4101 if (data
.dptr
== NULL
|| data
.dsize
== 0) {
4102 if (tdb_delete(tdb
, key
) < 0) {
4103 DEBUG(0, ("tdb_delete for [%s] failed!\n",
4109 /* add timeout to blob (uint64_t) */
4110 blob
.dsize
= data
.dsize
+ 8;
4112 blob
.dptr
= SMB_XMALLOC_ARRAY(uint8_t, blob
.dsize
);
4113 if (blob
.dptr
== NULL
) {
4116 memset(blob
.dptr
, 0, blob
.dsize
);
4118 /* copy status and seqnum */
4119 memcpy(blob
.dptr
, data
.dptr
, 8);
4122 ctimeout
= lp_winbind_cache_time() + time(NULL
);
4123 SBVAL(blob
.dptr
, 8, ctimeout
);
4126 memcpy(blob
.dptr
+ 16, data
.dptr
+ 8, data
.dsize
- 8);
4128 if (tdb_store(tdb
, key
, blob
, TDB_REPLACE
) < 0) {
4129 DEBUG(0, ("tdb_store to update [%s] failed!\n",
4131 SAFE_FREE(blob
.dptr
);
4135 SAFE_FREE(blob
.dptr
);
4139 static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT
*tdb
)
4143 DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
4145 rc
= tdb_traverse(tdb
, wbcache_update_centry_fn
, NULL
);
4153 /***********************************************************************
4154 Try and validate every entry in the winbindd cache. If we fail here,
4155 delete the cache tdb and return non-zero.
4156 ***********************************************************************/
4158 int winbindd_validate_cache(void)
4161 const char *tdb_path
= state_path("winbindd_cache.tdb");
4162 TDB_CONTEXT
*tdb
= NULL
;
4166 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4167 smb_panic_fn
= validate_panic
;
4169 tdb
= tdb_open_log(tdb_path
,
4170 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
4171 TDB_INCOMPATIBLE_HASH
|
4172 ( lp_winbind_offline_logon()
4174 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
4178 DEBUG(0, ("winbindd_validate_cache: "
4179 "error opening/initializing tdb\n"));
4183 /* Version check and upgrade code. */
4184 if (!tdb_fetch_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers_id
)) {
4185 DEBUG(10, ("Fresh database\n"));
4186 tdb_store_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
);
4187 vers_id
= WINBINDD_CACHE_VERSION
;
4190 if (vers_id
!= WINBINDD_CACHE_VERSION
) {
4191 if (vers_id
== WINBINDD_CACHE_VER1
) {
4192 ok
= wbcache_upgrade_v1_to_v2(tdb
);
4194 DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
4199 tdb_store_uint32(tdb
,
4200 WINBINDD_CACHE_VERSION_KEYSTR
,
4201 WINBINDD_CACHE_VERSION
);
4202 vers_id
= WINBINDD_CACHE_VER2
;
4208 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
4211 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4212 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
4217 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4218 smb_panic_fn
= smb_panic
;
4222 /***********************************************************************
4223 Try and validate every entry in the winbindd cache.
4224 ***********************************************************************/
4226 int winbindd_validate_cache_nobackup(void)
4229 const char *tdb_path
= state_path("winbindd_cache.tdb");
4231 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4232 smb_panic_fn
= validate_panic
;
4235 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
4236 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
4238 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
4242 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4246 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4248 smb_panic_fn
= smb_panic
;
4252 bool winbindd_cache_validate_and_initialize(void)
4254 close_winbindd_cache();
4256 if (lp_winbind_offline_logon()) {
4257 if (winbindd_validate_cache() < 0) {
4258 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4259 "could be restored.\n"));
4263 return initialize_winbindd_cache();
4266 /*********************************************************************
4267 ********************************************************************/
4269 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
4270 struct winbindd_tdc_domain
**domains
,
4271 size_t *num_domains
)
4273 struct winbindd_tdc_domain
*list
= NULL
;
4276 bool set_only
= false;
4278 /* don't allow duplicates */
4283 for ( i
=0; i
< (*num_domains
); i
++ ) {
4284 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
4285 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4296 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, 1 );
4299 list
= talloc_realloc( *domains
, *domains
,
4300 struct winbindd_tdc_domain
,
4305 ZERO_STRUCT( list
[idx
] );
4311 list
[idx
].domain_name
= talloc_strdup( list
, new_dom
->name
);
4312 list
[idx
].dns_name
= talloc_strdup( list
, new_dom
->alt_name
);
4314 if ( !is_null_sid( &new_dom
->sid
) ) {
4315 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
4317 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
4320 if ( new_dom
->domain_flags
!= 0x0 )
4321 list
[idx
].trust_flags
= new_dom
->domain_flags
;
4323 if ( new_dom
->domain_type
!= 0x0 )
4324 list
[idx
].trust_type
= new_dom
->domain_type
;
4326 if ( new_dom
->domain_trust_attribs
!= 0x0 )
4327 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
4331 *num_domains
= idx
+ 1;
4337 /*********************************************************************
4338 ********************************************************************/
4340 static TDB_DATA
make_tdc_key( const char *domain_name
)
4342 char *keystr
= NULL
;
4343 TDB_DATA key
= { NULL
, 0 };
4345 if ( !domain_name
) {
4346 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4350 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
4353 key
= string_term_tdb_data(keystr
);
4358 /*********************************************************************
4359 ********************************************************************/
4361 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
4363 unsigned char **buf
)
4365 unsigned char *buffer
= NULL
;
4370 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4378 /* Store the number of array items first */
4379 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
4382 /* now pack each domain trust record */
4383 for ( i
=0; i
<num_domains
; i
++ ) {
4388 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4389 domains
[i
].domain_name
,
4390 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
4393 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
4394 domains
[i
].domain_name
,
4395 domains
[i
].dns_name
,
4396 sid_to_fstring(tmp
, &domains
[i
].sid
),
4397 domains
[i
].trust_flags
,
4398 domains
[i
].trust_attribs
,
4399 domains
[i
].trust_type
);
4402 if ( buflen
< len
) {
4404 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
4405 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4419 /*********************************************************************
4420 ********************************************************************/
4422 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
4423 struct winbindd_tdc_domain
**domains
)
4425 fstring domain_name
, dns_name
, sid_string
;
4426 uint32 type
, attribs
, flags
;
4430 struct winbindd_tdc_domain
*list
= NULL
;
4432 /* get the number of domains */
4433 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
4435 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4439 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, num_domains
);
4441 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4445 for ( i
=0; i
<num_domains
; i
++ ) {
4446 len
+= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
4455 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4456 TALLOC_FREE( list
);
4460 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4461 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4462 domain_name
, dns_name
, sid_string
,
4463 flags
, attribs
, type
));
4465 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
4466 list
[i
].dns_name
= talloc_strdup( list
, dns_name
);
4467 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
4468 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4471 list
[i
].trust_flags
= flags
;
4472 list
[i
].trust_attribs
= attribs
;
4473 list
[i
].trust_type
= type
;
4481 /*********************************************************************
4482 ********************************************************************/
4484 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
4486 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4487 TDB_DATA data
= { NULL
, 0 };
4493 /* See if we were asked to delete the cache entry */
4496 ret
= tdb_delete( wcache
->tdb
, key
);
4500 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4507 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4510 SAFE_FREE( data
.dptr
);
4511 SAFE_FREE( key
.dptr
);
4513 return ( ret
== 0 );
4516 /*********************************************************************
4517 ********************************************************************/
4519 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4521 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4522 TDB_DATA data
= { NULL
, 0 };
4530 data
= tdb_fetch_compat( wcache
->tdb
, key
);
4532 SAFE_FREE( key
.dptr
);
4537 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4539 SAFE_FREE( data
.dptr
);
4547 /*********************************************************************
4548 ********************************************************************/
4550 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4552 struct winbindd_tdc_domain
*dom_list
= NULL
;
4553 size_t num_domains
= 0;
4556 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4557 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4558 domain
->name
, domain
->alt_name
,
4559 sid_string_dbg(&domain
->sid
),
4560 domain
->domain_flags
,
4561 domain
->domain_trust_attribs
,
4562 domain
->domain_type
));
4564 if ( !init_wcache() ) {
4568 /* fetch the list */
4570 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4572 /* add the new domain */
4574 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4578 /* pack the domain */
4580 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4588 TALLOC_FREE( dom_list
);
4593 /*********************************************************************
4594 ********************************************************************/
4596 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4598 struct winbindd_tdc_domain
*dom_list
= NULL
;
4599 size_t num_domains
= 0;
4601 struct winbindd_tdc_domain
*d
= NULL
;
4603 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4605 if ( !init_wcache() ) {
4609 /* fetch the list */
4611 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4613 for ( i
=0; i
<num_domains
; i
++ ) {
4614 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4615 strequal(name
, dom_list
[i
].dns_name
) )
4617 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4620 d
= talloc( ctx
, struct winbindd_tdc_domain
);
4624 d
->domain_name
= talloc_strdup( d
, dom_list
[i
].domain_name
);
4625 d
->dns_name
= talloc_strdup( d
, dom_list
[i
].dns_name
);
4626 sid_copy( &d
->sid
, &dom_list
[i
].sid
);
4627 d
->trust_flags
= dom_list
[i
].trust_flags
;
4628 d
->trust_type
= dom_list
[i
].trust_type
;
4629 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
4635 TALLOC_FREE( dom_list
);
4640 /*********************************************************************
4641 ********************************************************************/
4643 struct winbindd_tdc_domain
*
4644 wcache_tdc_fetch_domainbysid(TALLOC_CTX
*ctx
,
4645 const struct dom_sid
*sid
)
4647 struct winbindd_tdc_domain
*dom_list
= NULL
;
4648 size_t num_domains
= 0;
4650 struct winbindd_tdc_domain
*d
= NULL
;
4652 DEBUG(10,("wcache_tdc_fetch_domainbysid: Searching for domain %s\n",
4653 sid_string_dbg(sid
)));
4655 if (!init_wcache()) {
4659 /* fetch the list */
4661 wcache_tdc_fetch_list(&dom_list
, &num_domains
);
4663 for (i
= 0; i
<num_domains
; i
++) {
4664 if (dom_sid_equal(sid
, &(dom_list
[i
].sid
))) {
4665 DEBUG(10, ("wcache_tdc_fetch_domainbysid: "
4666 "Found domain %s for SID %s\n",
4667 dom_list
[i
].domain_name
,
4668 sid_string_dbg(sid
)));
4670 d
= talloc(ctx
, struct winbindd_tdc_domain
);
4674 d
->domain_name
= talloc_strdup(d
,
4675 dom_list
[i
].domain_name
);
4677 d
->dns_name
= talloc_strdup(d
, dom_list
[i
].dns_name
);
4678 sid_copy(&d
->sid
, &dom_list
[i
].sid
);
4679 d
->trust_flags
= dom_list
[i
].trust_flags
;
4680 d
->trust_type
= dom_list
[i
].trust_type
;
4681 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
4687 TALLOC_FREE(dom_list
);
4693 /*********************************************************************
4694 ********************************************************************/
4696 void wcache_tdc_clear( void )
4698 if ( !init_wcache() )
4701 wcache_tdc_store_list( NULL
, 0 );
4707 /*********************************************************************
4708 ********************************************************************/
4710 static void wcache_save_user_pwinfo(struct winbindd_domain
*domain
,
4712 const struct dom_sid
*user_sid
,
4713 const char *homedir
,
4718 struct cache_entry
*centry
;
4721 if ( (centry
= centry_start(domain
, status
)) == NULL
)
4724 centry_put_string( centry
, homedir
);
4725 centry_put_string( centry
, shell
);
4726 centry_put_string( centry
, gecos
);
4727 centry_put_uint32( centry
, gid
);
4729 centry_end(centry
, "NSS/PWINFO/%s", sid_to_fstring(tmp
, user_sid
) );
4731 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid
) ));
4733 centry_free(centry
);
4738 NTSTATUS
nss_get_info_cached( struct winbindd_domain
*domain
,
4739 const struct dom_sid
*user_sid
,
4741 const char **homedir
, const char **shell
,
4742 const char **gecos
, gid_t
*p_gid
)
4744 struct winbind_cache
*cache
= get_cache(domain
);
4745 struct cache_entry
*centry
= NULL
;
4752 centry
= wcache_fetch(cache
, domain
, "NSS/PWINFO/%s",
4753 sid_to_fstring(tmp
, user_sid
));
4758 *homedir
= centry_string( centry
, ctx
);
4759 *shell
= centry_string( centry
, ctx
);
4760 *gecos
= centry_string( centry
, ctx
);
4761 *p_gid
= centry_uint32( centry
);
4763 centry_free(centry
);
4765 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4766 sid_string_dbg(user_sid
)));
4768 return NT_STATUS_OK
;
4772 nt_status
= nss_get_info( domain
->name
, user_sid
, ctx
,
4773 homedir
, shell
, gecos
, p_gid
);
4775 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status
)));
4777 if ( NT_STATUS_IS_OK(nt_status
) ) {
4778 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir
));
4779 DEBUGADD(10, ("\tshell = '%s'\n", *shell
));
4780 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos
));
4781 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid
));
4783 wcache_save_user_pwinfo( domain
, nt_status
, user_sid
,
4784 *homedir
, *shell
, *gecos
, *p_gid
);
4787 if ( NT_STATUS_EQUAL( nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
4788 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4790 set_domain_offline( domain
);
4798 /* the cache backend methods are exposed via this structure */
4799 struct winbindd_methods cache_methods
= {
4817 static bool wcache_ndr_key(TALLOC_CTX
*mem_ctx
, char *domain_name
,
4818 uint32_t opnum
, const DATA_BLOB
*req
,
4824 key
= talloc_asprintf(mem_ctx
, "NDR/%s/%d/", domain_name
, (int)opnum
);
4828 keylen
= talloc_get_size(key
) - 1;
4830 key
= talloc_realloc(mem_ctx
, key
, char, keylen
+ req
->length
);
4834 memcpy(key
+ keylen
, req
->data
, req
->length
);
4836 pkey
->dptr
= (uint8_t *)key
;
4837 pkey
->dsize
= talloc_get_size(key
);
4841 static bool wcache_opnum_cacheable(uint32_t opnum
)
4844 case NDR_WBINT_PING
:
4845 case NDR_WBINT_QUERYSEQUENCENUMBER
:
4846 case NDR_WBINT_ALLOCATEUID
:
4847 case NDR_WBINT_ALLOCATEGID
:
4848 case NDR_WBINT_CHECKMACHINEACCOUNT
:
4849 case NDR_WBINT_CHANGEMACHINEACCOUNT
:
4850 case NDR_WBINT_PINGDC
:
4856 bool wcache_fetch_ndr(TALLOC_CTX
*mem_ctx
, struct winbindd_domain
*domain
,
4857 uint32_t opnum
, const DATA_BLOB
*req
, DATA_BLOB
*resp
)
4862 if (!wcache_opnum_cacheable(opnum
) ||
4863 is_my_own_sam_domain(domain
) ||
4864 is_builtin_domain(domain
)) {
4868 if (wcache
->tdb
== NULL
) {
4872 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4875 data
= tdb_fetch_compat(wcache
->tdb
, key
);
4876 TALLOC_FREE(key
.dptr
);
4878 if (data
.dptr
== NULL
) {
4881 if (data
.dsize
< 12) {
4885 if (!is_domain_offline(domain
)) {
4886 uint32_t entry_seqnum
, dom_seqnum
, last_check
;
4887 uint64_t entry_timeout
;
4889 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
,
4893 entry_seqnum
= IVAL(data
.dptr
, 0);
4894 if (entry_seqnum
!= dom_seqnum
) {
4895 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4896 (int)entry_seqnum
));
4899 entry_timeout
= BVAL(data
.dptr
, 4);
4900 if (time(NULL
) > entry_timeout
) {
4901 DEBUG(10, ("Entry has timed out\n"));
4906 resp
->data
= (uint8_t *)talloc_memdup(mem_ctx
, data
.dptr
+ 12,
4908 if (resp
->data
== NULL
) {
4909 DEBUG(10, ("talloc failed\n"));
4912 resp
->length
= data
.dsize
- 12;
4916 SAFE_FREE(data
.dptr
);
4920 void wcache_store_ndr(struct winbindd_domain
*domain
, uint32_t opnum
,
4921 const DATA_BLOB
*req
, const DATA_BLOB
*resp
)
4924 uint32_t dom_seqnum
, last_check
;
4927 if (!wcache_opnum_cacheable(opnum
) ||
4928 is_my_own_sam_domain(domain
) ||
4929 is_builtin_domain(domain
)) {
4933 if (wcache
->tdb
== NULL
) {
4937 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
, &last_check
)) {
4938 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4943 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4947 timeout
= time(NULL
) + lp_winbind_cache_time();
4949 data
.dsize
= resp
->length
+ 12;
4950 data
.dptr
= talloc_array(key
.dptr
, uint8_t, data
.dsize
);
4951 if (data
.dptr
== NULL
) {
4955 SIVAL(data
.dptr
, 0, dom_seqnum
);
4956 SBVAL(data
.dptr
, 4, timeout
);
4957 memcpy(data
.dptr
+ 12, resp
->data
, resp
->length
);
4959 tdb_store(wcache
->tdb
, key
, data
, 0);
4962 TALLOC_FREE(key
.dptr
);