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
;
1299 if (!winbindd_use_cache()) {
1300 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1304 return NT_STATUS_INTERNAL_DB_ERROR
;
1307 if (is_null_sid(sid
)) {
1308 return NT_STATUS_INVALID_SID
;
1311 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1312 return NT_STATUS_INVALID_SID
;
1315 /* Try and get a salted cred first. If we can't
1316 fall back to an unsalted cred. */
1318 centry
= wcache_fetch(cache
, domain
, "CRED/%s",
1319 sid_to_fstring(tmp
, sid
));
1321 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1322 sid_string_dbg(sid
)));
1323 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1326 /* In the salted case this isn't actually the nt_hash itself,
1327 but the MD5 of the salt + nt_hash. Let the caller
1328 sort this out. It can tell as we only return the cached_salt
1329 if we are returning a salted cred. */
1331 *cached_nt_pass
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1332 if (*cached_nt_pass
== NULL
) {
1335 sid_to_fstring(sidstr
, sid
);
1337 /* Bad (old) cred cache. Delete and pretend we
1339 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1341 wcache_delete("CRED/%s", sidstr
);
1342 centry_free(centry
);
1343 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1346 /* We only have 17 bytes more data in the salted cred case. */
1347 if (centry
->len
- centry
->ofs
== 17) {
1348 *cached_salt
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1350 *cached_salt
= NULL
;
1353 dump_data_pw("cached_nt_pass", *cached_nt_pass
, NT_HASH_LEN
);
1355 dump_data_pw("cached_salt", *cached_salt
, NT_HASH_LEN
);
1358 status
= centry
->status
;
1360 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1361 sid_string_dbg(sid
), nt_errstr(status
) ));
1363 centry_free(centry
);
1367 /* Store creds for a SID - only writes out new salted ones. */
1369 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1370 const struct dom_sid
*sid
,
1371 const uint8 nt_pass
[NT_HASH_LEN
])
1373 struct cache_entry
*centry
;
1376 uint8 cred_salt
[NT_HASH_LEN
];
1377 uint8 salted_hash
[NT_HASH_LEN
];
1379 if (is_null_sid(sid
)) {
1380 return NT_STATUS_INVALID_SID
;
1383 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1384 return NT_STATUS_INVALID_SID
;
1387 centry
= centry_start(domain
, NT_STATUS_OK
);
1389 return NT_STATUS_INTERNAL_DB_ERROR
;
1392 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1394 centry_put_time(centry
, time(NULL
));
1396 /* Create a salt and then salt the hash. */
1397 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1398 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1400 centry_put_hash16(centry
, salted_hash
);
1401 centry_put_hash16(centry
, cred_salt
);
1402 centry_end(centry
, "CRED/%s", sid_to_fstring(sid_string
, sid
));
1404 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1406 centry_free(centry
);
1408 return NT_STATUS_OK
;
1412 /* Query display info. This is the basic user list fn */
1413 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
1414 TALLOC_CTX
*mem_ctx
,
1415 uint32
*num_entries
,
1416 struct wbint_userinfo
**info
)
1418 struct winbind_cache
*cache
= get_cache(domain
);
1419 struct cache_entry
*centry
= NULL
;
1421 unsigned int i
, retry
;
1422 bool old_status
= domain
->online
;
1427 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1432 *num_entries
= centry_uint32(centry
);
1434 if (*num_entries
== 0)
1437 (*info
) = talloc_array(mem_ctx
, struct wbint_userinfo
, *num_entries
);
1439 smb_panic_fn("query_user_list out of memory");
1441 for (i
=0; i
<(*num_entries
); i
++) {
1442 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
1443 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
1444 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
1445 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
1446 centry_sid(centry
, &(*info
)[i
].user_sid
);
1447 centry_sid(centry
, &(*info
)[i
].group_sid
);
1451 status
= centry
->status
;
1453 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1454 domain
->name
, nt_errstr(status
) ));
1456 centry_free(centry
);
1463 /* Return status value returned by seq number check */
1465 if (!NT_STATUS_IS_OK(domain
->last_status
))
1466 return domain
->last_status
;
1468 /* Put the query_user_list() in a retry loop. There appears to be
1469 * some bug either with Windows 2000 or Samba's handling of large
1470 * rpc replies. This manifests itself as sudden disconnection
1471 * at a random point in the enumeration of a large (60k) user list.
1472 * The retry loop simply tries the operation again. )-: It's not
1473 * pretty but an acceptable workaround until we work out what the
1474 * real problem is. */
1479 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1482 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
1483 if (!NT_STATUS_IS_OK(status
)) {
1484 DEBUG(3, ("query_user_list: returned 0x%08x, "
1485 "retrying\n", NT_STATUS_V(status
)));
1487 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1488 DEBUG(3, ("query_user_list: flushing "
1489 "connection cache\n"));
1490 invalidate_cm_connection(&domain
->conn
);
1492 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1493 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1494 if (!domain
->internal
&& old_status
) {
1495 set_domain_offline(domain
);
1497 /* store partial response. */
1498 if (*num_entries
> 0) {
1500 * humm, what about the status used for cache?
1501 * Should it be NT_STATUS_OK?
1506 * domain is offline now, and there is no user entries,
1507 * try to fetch from cache again.
1509 if (cache
->tdb
&& !domain
->online
&& !domain
->internal
&& old_status
) {
1510 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1511 /* partial response... */
1515 goto do_fetch_cache
;
1522 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1526 refresh_sequence_number(domain
, false);
1527 if (!NT_STATUS_IS_OK(status
)) {
1530 centry
= centry_start(domain
, status
);
1533 centry_put_uint32(centry
, *num_entries
);
1534 for (i
=0; i
<(*num_entries
); i
++) {
1535 centry_put_string(centry
, (*info
)[i
].acct_name
);
1536 centry_put_string(centry
, (*info
)[i
].full_name
);
1537 centry_put_string(centry
, (*info
)[i
].homedir
);
1538 centry_put_string(centry
, (*info
)[i
].shell
);
1539 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1540 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1541 if (domain
->backend
&& domain
->backend
->consistent
) {
1542 /* when the backend is consistent we can pre-prime some mappings */
1543 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1545 (*info
)[i
].acct_name
,
1546 &(*info
)[i
].user_sid
,
1548 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1549 &(*info
)[i
].user_sid
,
1551 (*info
)[i
].acct_name
,
1553 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1556 centry_end(centry
, "UL/%s", domain
->name
);
1557 centry_free(centry
);
1563 /* list all domain groups */
1564 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
1565 TALLOC_CTX
*mem_ctx
,
1566 uint32
*num_entries
,
1567 struct wb_acct_info
**info
)
1569 struct winbind_cache
*cache
= get_cache(domain
);
1570 struct cache_entry
*centry
= NULL
;
1575 old_status
= domain
->online
;
1579 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1584 *num_entries
= centry_uint32(centry
);
1586 if (*num_entries
== 0)
1589 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1591 smb_panic_fn("enum_dom_groups out of memory");
1593 for (i
=0; i
<(*num_entries
); i
++) {
1594 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1595 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1596 (*info
)[i
].rid
= centry_uint32(centry
);
1600 status
= centry
->status
;
1602 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1603 domain
->name
, nt_errstr(status
) ));
1605 centry_free(centry
);
1612 /* Return status value returned by seq number check */
1614 if (!NT_STATUS_IS_OK(domain
->last_status
))
1615 return domain
->last_status
;
1617 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1620 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1622 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1623 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1624 if (!domain
->internal
&& old_status
) {
1625 set_domain_offline(domain
);
1629 !domain
->internal
&&
1631 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1633 goto do_fetch_cache
;
1638 refresh_sequence_number(domain
, false);
1639 if (!NT_STATUS_IS_OK(status
)) {
1642 centry
= centry_start(domain
, status
);
1645 centry_put_uint32(centry
, *num_entries
);
1646 for (i
=0; i
<(*num_entries
); i
++) {
1647 centry_put_string(centry
, (*info
)[i
].acct_name
);
1648 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1649 centry_put_uint32(centry
, (*info
)[i
].rid
);
1651 centry_end(centry
, "GL/%s/domain", domain
->name
);
1652 centry_free(centry
);
1658 /* list all domain groups */
1659 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
1660 TALLOC_CTX
*mem_ctx
,
1661 uint32
*num_entries
,
1662 struct wb_acct_info
**info
)
1664 struct winbind_cache
*cache
= get_cache(domain
);
1665 struct cache_entry
*centry
= NULL
;
1670 old_status
= domain
->online
;
1674 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1679 *num_entries
= centry_uint32(centry
);
1681 if (*num_entries
== 0)
1684 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1686 smb_panic_fn("enum_dom_groups out of memory");
1688 for (i
=0; i
<(*num_entries
); i
++) {
1689 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1690 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1691 (*info
)[i
].rid
= centry_uint32(centry
);
1696 /* If we are returning cached data and the domain controller
1697 is down then we don't know whether the data is up to date
1698 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1701 if (wcache_server_down(domain
)) {
1702 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1703 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1705 status
= centry
->status
;
1707 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1708 domain
->name
, nt_errstr(status
) ));
1710 centry_free(centry
);
1717 /* Return status value returned by seq number check */
1719 if (!NT_STATUS_IS_OK(domain
->last_status
))
1720 return domain
->last_status
;
1722 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1725 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1727 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1728 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1729 if (!domain
->internal
&& old_status
) {
1730 set_domain_offline(domain
);
1733 !domain
->internal
&&
1736 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1738 goto do_fetch_cache
;
1743 refresh_sequence_number(domain
, false);
1744 if (!NT_STATUS_IS_OK(status
)) {
1747 centry
= centry_start(domain
, status
);
1750 centry_put_uint32(centry
, *num_entries
);
1751 for (i
=0; i
<(*num_entries
); i
++) {
1752 centry_put_string(centry
, (*info
)[i
].acct_name
);
1753 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1754 centry_put_uint32(centry
, (*info
)[i
].rid
);
1756 centry_end(centry
, "GL/%s/local", domain
->name
);
1757 centry_free(centry
);
1763 NTSTATUS
wcache_name_to_sid(struct winbindd_domain
*domain
,
1764 const char *domain_name
,
1766 struct dom_sid
*sid
,
1767 enum lsa_SidType
*type
)
1769 struct winbind_cache
*cache
= get_cache(domain
);
1770 struct cache_entry
*centry
;
1774 if (cache
->tdb
== NULL
) {
1775 return NT_STATUS_NOT_FOUND
;
1778 uname
= talloc_strdup_upper(talloc_tos(), name
);
1779 if (uname
== NULL
) {
1780 return NT_STATUS_NO_MEMORY
;
1783 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1785 if (centry
== NULL
) {
1786 return NT_STATUS_NOT_FOUND
;
1789 status
= centry
->status
;
1790 if (NT_STATUS_IS_OK(status
)) {
1791 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1792 centry_sid(centry
, sid
);
1795 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1796 "%s\n", domain
->name
, nt_errstr(status
) ));
1798 centry_free(centry
);
1802 /* convert a single name to a sid in a domain */
1803 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
1804 TALLOC_CTX
*mem_ctx
,
1805 const char *domain_name
,
1808 struct dom_sid
*sid
,
1809 enum lsa_SidType
*type
)
1814 old_status
= domain
->online
;
1816 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1817 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1823 /* If the seq number check indicated that there is a problem
1824 * with this DC, then return that status... except for
1825 * access_denied. This is special because the dc may be in
1826 * "restrict anonymous = 1" mode, in which case it will deny
1827 * most unauthenticated operations, but *will* allow the LSA
1828 * name-to-sid that we try as a fallback. */
1830 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1831 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1832 return domain
->last_status
;
1834 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1837 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
,
1838 name
, flags
, sid
, type
);
1840 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1841 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1842 if (!domain
->internal
&& old_status
) {
1843 set_domain_offline(domain
);
1845 if (!domain
->internal
&&
1848 NTSTATUS cache_status
;
1849 cache_status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1850 return cache_status
;
1854 refresh_sequence_number(domain
, false);
1856 if (domain
->online
&&
1857 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1858 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1860 /* Only save the reverse mapping if this was not a UPN */
1861 if (!strchr(name
, '@')) {
1862 strupper_m(discard_const_p(char, domain_name
));
1863 strlower_m(discard_const_p(char, name
));
1864 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1871 NTSTATUS
wcache_sid_to_name(struct winbindd_domain
*domain
,
1872 const struct dom_sid
*sid
,
1873 TALLOC_CTX
*mem_ctx
,
1876 enum lsa_SidType
*type
)
1878 struct winbind_cache
*cache
= get_cache(domain
);
1879 struct cache_entry
*centry
;
1883 if (cache
->tdb
== NULL
) {
1884 return NT_STATUS_NOT_FOUND
;
1887 sid_string
= sid_string_tos(sid
);
1888 if (sid_string
== NULL
) {
1889 return NT_STATUS_NO_MEMORY
;
1892 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_string
);
1893 TALLOC_FREE(sid_string
);
1894 if (centry
== NULL
) {
1895 return NT_STATUS_NOT_FOUND
;
1898 if (NT_STATUS_IS_OK(centry
->status
)) {
1899 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1900 *domain_name
= centry_string(centry
, mem_ctx
);
1901 *name
= centry_string(centry
, mem_ctx
);
1904 status
= centry
->status
;
1905 centry_free(centry
);
1907 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1908 "%s\n", domain
->name
, nt_errstr(status
) ));
1913 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1915 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1916 TALLOC_CTX
*mem_ctx
,
1917 const struct dom_sid
*sid
,
1920 enum lsa_SidType
*type
)
1925 old_status
= domain
->online
;
1926 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
1928 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1933 *domain_name
= NULL
;
1935 /* If the seq number check indicated that there is a problem
1936 * with this DC, then return that status... except for
1937 * access_denied. This is special because the dc may be in
1938 * "restrict anonymous = 1" mode, in which case it will deny
1939 * most unauthenticated operations, but *will* allow the LSA
1940 * sid-to-name that we try as a fallback. */
1942 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1943 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1944 return domain
->last_status
;
1946 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1949 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1951 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1952 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1953 if (!domain
->internal
&& old_status
) {
1954 set_domain_offline(domain
);
1956 if (!domain
->internal
&&
1959 NTSTATUS cache_status
;
1960 cache_status
= wcache_sid_to_name(domain
, sid
, mem_ctx
,
1961 domain_name
, name
, type
);
1962 return cache_status
;
1966 refresh_sequence_number(domain
, false);
1967 if (!NT_STATUS_IS_OK(status
)) {
1970 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
1972 /* We can't save the name to sid mapping here, as with sid history a
1973 * later name2sid would give the wrong sid. */
1978 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
1979 TALLOC_CTX
*mem_ctx
,
1980 const struct dom_sid
*domain_sid
,
1985 enum lsa_SidType
**types
)
1987 struct winbind_cache
*cache
= get_cache(domain
);
1989 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1994 old_status
= domain
->online
;
1995 *domain_name
= NULL
;
2003 if (num_rids
== 0) {
2004 return NT_STATUS_OK
;
2007 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2008 *types
= talloc_array(mem_ctx
, enum lsa_SidType
, num_rids
);
2010 if ((*names
== NULL
) || (*types
== NULL
)) {
2011 result
= NT_STATUS_NO_MEMORY
;
2015 have_mapped
= have_unmapped
= false;
2017 for (i
=0; i
<num_rids
; i
++) {
2019 struct cache_entry
*centry
;
2022 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2023 result
= NT_STATUS_INTERNAL_ERROR
;
2027 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2028 sid_to_fstring(tmp
, &sid
));
2033 (*types
)[i
] = SID_NAME_UNKNOWN
;
2034 (*names
)[i
] = talloc_strdup(*names
, "");
2036 if (NT_STATUS_IS_OK(centry
->status
)) {
2039 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2041 dom
= centry_string(centry
, mem_ctx
);
2042 if (*domain_name
== NULL
) {
2048 (*names
)[i
] = centry_string(centry
, *names
);
2050 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)
2051 || NT_STATUS_EQUAL(centry
->status
, STATUS_SOME_UNMAPPED
)) {
2052 have_unmapped
= true;
2055 /* something's definitely wrong */
2056 result
= centry
->status
;
2060 centry_free(centry
);
2064 return NT_STATUS_NONE_MAPPED
;
2066 if (!have_unmapped
) {
2067 return NT_STATUS_OK
;
2069 return STATUS_SOME_UNMAPPED
;
2073 TALLOC_FREE(*names
);
2074 TALLOC_FREE(*types
);
2076 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
2077 rids
, num_rids
, domain_name
,
2080 if (NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
2081 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2082 if (!domain
->internal
&& old_status
) {
2083 set_domain_offline(domain
);
2086 !domain
->internal
&&
2089 have_mapped
= have_unmapped
= false;
2091 for (i
=0; i
<num_rids
; i
++) {
2093 struct cache_entry
*centry
;
2096 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2097 result
= NT_STATUS_INTERNAL_ERROR
;
2101 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2102 sid_to_fstring(tmp
, &sid
));
2104 (*types
)[i
] = SID_NAME_UNKNOWN
;
2105 (*names
)[i
] = talloc_strdup(*names
, "");
2109 (*types
)[i
] = SID_NAME_UNKNOWN
;
2110 (*names
)[i
] = talloc_strdup(*names
, "");
2112 if (NT_STATUS_IS_OK(centry
->status
)) {
2115 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2117 dom
= centry_string(centry
, mem_ctx
);
2118 if (*domain_name
== NULL
) {
2124 (*names
)[i
] = centry_string(centry
, *names
);
2126 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)) {
2127 have_unmapped
= true;
2130 /* something's definitely wrong */
2131 result
= centry
->status
;
2135 centry_free(centry
);
2139 return NT_STATUS_NONE_MAPPED
;
2141 if (!have_unmapped
) {
2142 return NT_STATUS_OK
;
2144 return STATUS_SOME_UNMAPPED
;
2148 None of the queried rids has been found so save all negative entries
2150 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
2151 for (i
= 0; i
< num_rids
; i
++) {
2153 const char *name
= "";
2154 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
2155 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
2157 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2158 return NT_STATUS_INTERNAL_ERROR
;
2161 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2169 Some or all of the queried rids have been found.
2171 if (!NT_STATUS_IS_OK(result
) &&
2172 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
2176 refresh_sequence_number(domain
, false);
2178 for (i
=0; i
<num_rids
; i
++) {
2182 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2183 result
= NT_STATUS_INTERNAL_ERROR
;
2187 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
2188 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
2190 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2191 (*names
)[i
], (*types
)[i
]);
2197 TALLOC_FREE(*names
);
2198 TALLOC_FREE(*types
);
2202 NTSTATUS
wcache_query_user(struct winbindd_domain
*domain
,
2203 TALLOC_CTX
*mem_ctx
,
2204 const struct dom_sid
*user_sid
,
2205 struct wbint_userinfo
*info
)
2207 struct winbind_cache
*cache
= get_cache(domain
);
2208 struct cache_entry
*centry
= NULL
;
2212 if (cache
->tdb
== NULL
) {
2213 return NT_STATUS_NOT_FOUND
;
2216 sid_string
= sid_string_tos(user_sid
);
2217 if (sid_string
== NULL
) {
2218 return NT_STATUS_NO_MEMORY
;
2221 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string
);
2222 TALLOC_FREE(sid_string
);
2223 if (centry
== NULL
) {
2224 return NT_STATUS_NOT_FOUND
;
2228 * If we have an access denied cache entry and a cached info3
2229 * in the samlogon cache then do a query. This will force the
2230 * rpc back end to return the info3 data.
2233 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
) &&
2234 netsamlogon_cache_have(user_sid
)) {
2235 DEBUG(10, ("query_user: cached access denied and have cached "
2237 domain
->last_status
= NT_STATUS_OK
;
2238 centry_free(centry
);
2239 return NT_STATUS_NOT_FOUND
;
2242 /* if status is not ok then this is a negative hit
2243 and the rest of the data doesn't matter */
2244 status
= centry
->status
;
2245 if (NT_STATUS_IS_OK(status
)) {
2246 info
->acct_name
= centry_string(centry
, mem_ctx
);
2247 info
->full_name
= centry_string(centry
, mem_ctx
);
2248 info
->homedir
= centry_string(centry
, mem_ctx
);
2249 info
->shell
= centry_string(centry
, mem_ctx
);
2250 info
->primary_gid
= centry_uint32(centry
);
2251 centry_sid(centry
, &info
->user_sid
);
2252 centry_sid(centry
, &info
->group_sid
);
2255 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2256 "%s\n", domain
->name
, nt_errstr(status
) ));
2258 centry_free(centry
);
2262 /* Lookup user information from a rid */
2263 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
2264 TALLOC_CTX
*mem_ctx
,
2265 const struct dom_sid
*user_sid
,
2266 struct wbint_userinfo
*info
)
2271 old_status
= domain
->online
;
2272 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2273 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2279 /* Return status value returned by seq number check */
2281 if (!NT_STATUS_IS_OK(domain
->last_status
))
2282 return domain
->last_status
;
2284 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2287 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
2289 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2290 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2291 if (!domain
->internal
&& old_status
) {
2292 set_domain_offline(domain
);
2294 if (!domain
->internal
&&
2297 NTSTATUS cache_status
;
2298 cache_status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2299 return cache_status
;
2303 refresh_sequence_number(domain
, false);
2304 if (!NT_STATUS_IS_OK(status
)) {
2307 wcache_save_user(domain
, status
, info
);
2312 NTSTATUS
wcache_lookup_usergroups(struct winbindd_domain
*domain
,
2313 TALLOC_CTX
*mem_ctx
,
2314 const struct dom_sid
*user_sid
,
2315 uint32_t *pnum_sids
,
2316 struct dom_sid
**psids
)
2318 struct winbind_cache
*cache
= get_cache(domain
);
2319 struct cache_entry
*centry
= NULL
;
2321 uint32_t i
, num_sids
;
2322 struct dom_sid
*sids
;
2325 if (cache
->tdb
== NULL
) {
2326 return NT_STATUS_NOT_FOUND
;
2329 centry
= wcache_fetch(cache
, domain
, "UG/%s",
2330 sid_to_fstring(sid_string
, user_sid
));
2331 if (centry
== NULL
) {
2332 return NT_STATUS_NOT_FOUND
;
2335 /* If we have an access denied cache entry and a cached info3 in the
2336 samlogon cache then do a query. This will force the rpc back end
2337 to return the info3 data. */
2339 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)
2340 && netsamlogon_cache_have(user_sid
)) {
2341 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2343 domain
->last_status
= NT_STATUS_OK
;
2344 centry_free(centry
);
2345 return NT_STATUS_NOT_FOUND
;
2348 num_sids
= centry_uint32(centry
);
2349 sids
= talloc_array(mem_ctx
, struct dom_sid
, num_sids
);
2351 centry_free(centry
);
2352 return NT_STATUS_NO_MEMORY
;
2355 for (i
=0; i
<num_sids
; i
++) {
2356 centry_sid(centry
, &sids
[i
]);
2359 status
= centry
->status
;
2361 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2362 "status: %s\n", domain
->name
, nt_errstr(status
)));
2364 centry_free(centry
);
2366 *pnum_sids
= num_sids
;
2371 /* Lookup groups a user is a member of. */
2372 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
2373 TALLOC_CTX
*mem_ctx
,
2374 const struct dom_sid
*user_sid
,
2375 uint32
*num_groups
, struct dom_sid
**user_gids
)
2377 struct cache_entry
*centry
= NULL
;
2383 old_status
= domain
->online
;
2384 status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2385 num_groups
, user_gids
);
2386 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2391 (*user_gids
) = NULL
;
2393 /* Return status value returned by seq number check */
2395 if (!NT_STATUS_IS_OK(domain
->last_status
))
2396 return domain
->last_status
;
2398 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2401 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
2403 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2404 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2405 if (!domain
->internal
&& old_status
) {
2406 set_domain_offline(domain
);
2408 if (!domain
->internal
&&
2411 NTSTATUS cache_status
;
2412 cache_status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2413 num_groups
, user_gids
);
2414 return cache_status
;
2417 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
2421 refresh_sequence_number(domain
, false);
2422 if (!NT_STATUS_IS_OK(status
)) {
2425 centry
= centry_start(domain
, status
);
2429 centry_put_uint32(centry
, *num_groups
);
2430 for (i
=0; i
<(*num_groups
); i
++) {
2431 centry_put_sid(centry
, &(*user_gids
)[i
]);
2434 centry_end(centry
, "UG/%s", sid_to_fstring(sid_string
, user_sid
));
2435 centry_free(centry
);
2441 static char *wcache_make_sidlist(TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2442 const struct dom_sid
*sids
)
2447 sidlist
= talloc_strdup(mem_ctx
, "");
2448 if (sidlist
== NULL
) {
2451 for (i
=0; i
<num_sids
; i
++) {
2453 sidlist
= talloc_asprintf_append_buffer(
2454 sidlist
, "/%s", sid_to_fstring(tmp
, &sids
[i
]));
2455 if (sidlist
== NULL
) {
2462 NTSTATUS
wcache_lookup_useraliases(struct winbindd_domain
*domain
,
2463 TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2464 const struct dom_sid
*sids
,
2465 uint32_t *pnum_aliases
, uint32_t **paliases
)
2467 struct winbind_cache
*cache
= get_cache(domain
);
2468 struct cache_entry
*centry
= NULL
;
2469 uint32_t num_aliases
;
2475 if (cache
->tdb
== NULL
) {
2476 return NT_STATUS_NOT_FOUND
;
2479 if (num_sids
== 0) {
2482 return NT_STATUS_OK
;
2485 /* We need to cache indexed by the whole list of SIDs, the aliases
2486 * resulting might come from any of the SIDs. */
2488 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2489 if (sidlist
== NULL
) {
2490 return NT_STATUS_NO_MEMORY
;
2493 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2494 TALLOC_FREE(sidlist
);
2495 if (centry
== NULL
) {
2496 return NT_STATUS_NOT_FOUND
;
2499 num_aliases
= centry_uint32(centry
);
2500 aliases
= talloc_array(mem_ctx
, uint32_t, num_aliases
);
2501 if (aliases
== NULL
) {
2502 centry_free(centry
);
2503 return NT_STATUS_NO_MEMORY
;
2506 for (i
=0; i
<num_aliases
; i
++) {
2507 aliases
[i
] = centry_uint32(centry
);
2510 status
= centry
->status
;
2512 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2513 "status %s\n", domain
->name
, nt_errstr(status
)));
2515 centry_free(centry
);
2517 *pnum_aliases
= num_aliases
;
2518 *paliases
= aliases
;
2523 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
2524 TALLOC_CTX
*mem_ctx
,
2525 uint32 num_sids
, const struct dom_sid
*sids
,
2526 uint32
*num_aliases
, uint32
**alias_rids
)
2528 struct cache_entry
*centry
= NULL
;
2534 old_status
= domain
->online
;
2535 status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
2536 num_aliases
, alias_rids
);
2537 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2542 (*alias_rids
) = NULL
;
2544 if (!NT_STATUS_IS_OK(domain
->last_status
))
2545 return domain
->last_status
;
2547 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2548 "for domain %s\n", domain
->name
));
2550 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2551 if (sidlist
== NULL
) {
2552 return NT_STATUS_NO_MEMORY
;
2555 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2557 num_aliases
, alias_rids
);
2559 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2560 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2561 if (!domain
->internal
&& old_status
) {
2562 set_domain_offline(domain
);
2564 if (!domain
->internal
&&
2567 NTSTATUS cache_status
;
2568 cache_status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
,
2569 sids
, num_aliases
, alias_rids
);
2570 return cache_status
;
2574 refresh_sequence_number(domain
, false);
2575 if (!NT_STATUS_IS_OK(status
)) {
2578 centry
= centry_start(domain
, status
);
2581 centry_put_uint32(centry
, *num_aliases
);
2582 for (i
=0; i
<(*num_aliases
); i
++)
2583 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2584 centry_end(centry
, "UA%s", sidlist
);
2585 centry_free(centry
);
2591 NTSTATUS
wcache_lookup_groupmem(struct winbindd_domain
*domain
,
2592 TALLOC_CTX
*mem_ctx
,
2593 const struct dom_sid
*group_sid
,
2594 uint32_t *num_names
,
2595 struct dom_sid
**sid_mem
, char ***names
,
2596 uint32_t **name_types
)
2598 struct winbind_cache
*cache
= get_cache(domain
);
2599 struct cache_entry
*centry
= NULL
;
2604 if (cache
->tdb
== NULL
) {
2605 return NT_STATUS_NOT_FOUND
;
2608 sid_string
= sid_string_tos(group_sid
);
2609 if (sid_string
== NULL
) {
2610 return NT_STATUS_NO_MEMORY
;
2613 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_string
);
2614 TALLOC_FREE(sid_string
);
2615 if (centry
== NULL
) {
2616 return NT_STATUS_NOT_FOUND
;
2623 *num_names
= centry_uint32(centry
);
2624 if (*num_names
== 0) {
2625 centry_free(centry
);
2626 return NT_STATUS_OK
;
2629 *sid_mem
= talloc_array(mem_ctx
, struct dom_sid
, *num_names
);
2630 *names
= talloc_array(mem_ctx
, char *, *num_names
);
2631 *name_types
= talloc_array(mem_ctx
, uint32
, *num_names
);
2633 if ((*sid_mem
== NULL
) || (*names
== NULL
) || (*name_types
== NULL
)) {
2634 TALLOC_FREE(*sid_mem
);
2635 TALLOC_FREE(*names
);
2636 TALLOC_FREE(*name_types
);
2637 centry_free(centry
);
2638 return NT_STATUS_NO_MEMORY
;
2641 for (i
=0; i
<(*num_names
); i
++) {
2642 centry_sid(centry
, &(*sid_mem
)[i
]);
2643 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2644 (*name_types
)[i
] = centry_uint32(centry
);
2647 status
= centry
->status
;
2649 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2650 "status: %s\n", domain
->name
, nt_errstr(status
)));
2652 centry_free(centry
);
2656 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
2657 TALLOC_CTX
*mem_ctx
,
2658 const struct dom_sid
*group_sid
,
2659 enum lsa_SidType type
,
2661 struct dom_sid
**sid_mem
, char ***names
,
2662 uint32
**name_types
)
2664 struct cache_entry
*centry
= NULL
;
2670 old_status
= domain
->online
;
2671 status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2672 sid_mem
, names
, name_types
);
2673 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2680 (*name_types
) = NULL
;
2682 /* Return status value returned by seq number check */
2684 if (!NT_STATUS_IS_OK(domain
->last_status
))
2685 return domain
->last_status
;
2687 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2690 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
,
2692 sid_mem
, names
, name_types
);
2694 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2695 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2696 if (!domain
->internal
&& old_status
) {
2697 set_domain_offline(domain
);
2699 if (!domain
->internal
&&
2702 NTSTATUS cache_status
;
2703 cache_status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
,
2704 num_names
, sid_mem
, names
,
2706 return cache_status
;
2710 refresh_sequence_number(domain
, false);
2711 if (!NT_STATUS_IS_OK(status
)) {
2714 centry
= centry_start(domain
, status
);
2717 centry_put_uint32(centry
, *num_names
);
2718 for (i
=0; i
<(*num_names
); i
++) {
2719 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2720 centry_put_string(centry
, (*names
)[i
]);
2721 centry_put_uint32(centry
, (*name_types
)[i
]);
2723 centry_end(centry
, "GM/%s", sid_to_fstring(sid_string
, group_sid
));
2724 centry_free(centry
);
2730 /* find the sequence number for a domain */
2731 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
2733 refresh_sequence_number(domain
, false);
2735 *seq
= domain
->sequence_number
;
2737 return NT_STATUS_OK
;
2740 /* enumerate trusted domains
2741 * (we need to have the list of trustdoms in the cache when we go offline) -
2743 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
2744 TALLOC_CTX
*mem_ctx
,
2745 struct netr_DomainTrustList
*trusts
)
2748 struct winbind_cache
*cache
;
2749 struct winbindd_tdc_domain
*dom_list
= NULL
;
2750 size_t num_domains
= 0;
2751 bool retval
= false;
2755 old_status
= domain
->online
;
2757 trusts
->array
= NULL
;
2759 cache
= get_cache(domain
);
2760 if (!cache
|| !cache
->tdb
) {
2764 if (domain
->online
) {
2768 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2769 if (!retval
|| !num_domains
|| !dom_list
) {
2770 TALLOC_FREE(dom_list
);
2775 trusts
->array
= talloc_zero_array(mem_ctx
, struct netr_DomainTrust
, num_domains
);
2776 if (!trusts
->array
) {
2777 TALLOC_FREE(dom_list
);
2778 return NT_STATUS_NO_MEMORY
;
2781 for (i
= 0; i
< num_domains
; i
++) {
2782 struct netr_DomainTrust
*trust
;
2783 struct dom_sid
*sid
;
2784 struct winbindd_domain
*dom
;
2786 dom
= find_domain_from_name_noinit(dom_list
[i
].domain_name
);
2787 if (dom
&& dom
->internal
) {
2791 trust
= &trusts
->array
[trusts
->count
];
2792 trust
->netbios_name
= talloc_strdup(trusts
->array
, dom_list
[i
].domain_name
);
2793 trust
->dns_name
= talloc_strdup(trusts
->array
, dom_list
[i
].dns_name
);
2794 sid
= talloc(trusts
->array
, struct dom_sid
);
2795 if (!trust
->netbios_name
|| !trust
->dns_name
||
2797 TALLOC_FREE(dom_list
);
2798 TALLOC_FREE(trusts
->array
);
2799 return NT_STATUS_NO_MEMORY
;
2802 trust
->trust_flags
= dom_list
[i
].trust_flags
;
2803 trust
->trust_attributes
= dom_list
[i
].trust_attribs
;
2804 trust
->trust_type
= dom_list
[i
].trust_type
;
2805 sid_copy(sid
, &dom_list
[i
].sid
);
2810 TALLOC_FREE(dom_list
);
2811 return NT_STATUS_OK
;
2814 /* Return status value returned by seq number check */
2816 if (!NT_STATUS_IS_OK(domain
->last_status
))
2817 return domain
->last_status
;
2819 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2822 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, trusts
);
2824 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2825 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2826 if (!domain
->internal
&& old_status
) {
2827 set_domain_offline(domain
);
2829 if (!domain
->internal
&&
2832 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2833 if (retval
&& num_domains
&& dom_list
) {
2834 TALLOC_FREE(trusts
->array
);
2836 goto do_fetch_cache
;
2840 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2841 * so that the generic centry handling still applies correctly -
2844 if (!NT_STATUS_IS_ERR(status
)) {
2845 status
= NT_STATUS_OK
;
2850 /* get lockout policy */
2851 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
2852 TALLOC_CTX
*mem_ctx
,
2853 struct samr_DomInfo12
*policy
)
2855 struct winbind_cache
*cache
= get_cache(domain
);
2856 struct cache_entry
*centry
= NULL
;
2860 old_status
= domain
->online
;
2864 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2870 policy
->lockout_duration
= centry_nttime(centry
);
2871 policy
->lockout_window
= centry_nttime(centry
);
2872 policy
->lockout_threshold
= centry_uint16(centry
);
2874 status
= centry
->status
;
2876 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2877 domain
->name
, nt_errstr(status
) ));
2879 centry_free(centry
);
2883 ZERO_STRUCTP(policy
);
2885 /* Return status value returned by seq number check */
2887 if (!NT_STATUS_IS_OK(domain
->last_status
))
2888 return domain
->last_status
;
2890 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2893 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2895 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2896 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2897 if (!domain
->internal
&& old_status
) {
2898 set_domain_offline(domain
);
2901 !domain
->internal
&&
2904 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2906 goto do_fetch_cache
;
2911 refresh_sequence_number(domain
, false);
2912 if (!NT_STATUS_IS_OK(status
)) {
2915 wcache_save_lockout_policy(domain
, status
, policy
);
2920 /* get password policy */
2921 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
2922 TALLOC_CTX
*mem_ctx
,
2923 struct samr_DomInfo1
*policy
)
2925 struct winbind_cache
*cache
= get_cache(domain
);
2926 struct cache_entry
*centry
= NULL
;
2930 old_status
= domain
->online
;
2934 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2940 policy
->min_password_length
= centry_uint16(centry
);
2941 policy
->password_history_length
= centry_uint16(centry
);
2942 policy
->password_properties
= centry_uint32(centry
);
2943 policy
->max_password_age
= centry_nttime(centry
);
2944 policy
->min_password_age
= centry_nttime(centry
);
2946 status
= centry
->status
;
2948 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2949 domain
->name
, nt_errstr(status
) ));
2951 centry_free(centry
);
2955 ZERO_STRUCTP(policy
);
2957 /* Return status value returned by seq number check */
2959 if (!NT_STATUS_IS_OK(domain
->last_status
))
2960 return domain
->last_status
;
2962 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2965 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
2967 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2968 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2969 if (!domain
->internal
&& old_status
) {
2970 set_domain_offline(domain
);
2973 !domain
->internal
&&
2976 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2978 goto do_fetch_cache
;
2983 refresh_sequence_number(domain
, false);
2984 if (!NT_STATUS_IS_OK(status
)) {
2987 wcache_save_password_policy(domain
, status
, policy
);
2993 /* Invalidate cached user and group lists coherently */
2995 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2998 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
2999 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
3000 tdb_delete(the_tdb
, kbuf
);
3005 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3007 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
3008 const struct dom_sid
*sid
)
3010 fstring key_str
, sid_string
;
3011 struct winbind_cache
*cache
;
3013 /* dont clear cached U/SID and UG/SID entries when we want to logon
3016 if (lp_winbind_offline_logon()) {
3023 cache
= get_cache(domain
);
3029 /* Clear U/SID cache entry */
3030 fstr_sprintf(key_str
, "U/%s", sid_to_fstring(sid_string
, sid
));
3031 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3032 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3034 /* Clear UG/SID cache entry */
3035 fstr_sprintf(key_str
, "UG/%s", sid_to_fstring(sid_string
, sid
));
3036 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3037 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3039 /* Samba/winbindd never needs this. */
3040 netsamlogon_clear_cached_user(sid
);
3043 bool wcache_invalidate_cache(void)
3045 struct winbindd_domain
*domain
;
3047 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3048 struct winbind_cache
*cache
= get_cache(domain
);
3050 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3051 "entries for %s\n", domain
->name
));
3054 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3063 bool wcache_invalidate_cache_noinit(void)
3065 struct winbindd_domain
*domain
;
3067 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3068 struct winbind_cache
*cache
;
3070 /* Skip uninitialized domains. */
3071 if (!domain
->initialized
&& !domain
->internal
) {
3075 cache
= get_cache(domain
);
3077 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3078 "entries for %s\n", domain
->name
));
3081 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3083 * Flushing cache has nothing to with domains.
3084 * return here if we successfully flushed once.
3085 * To avoid unnecessary traversing the cache.
3096 bool init_wcache(void)
3098 if (wcache
== NULL
) {
3099 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
3100 ZERO_STRUCTP(wcache
);
3103 if (wcache
->tdb
!= NULL
)
3106 /* when working offline we must not clear the cache on restart */
3107 wcache
->tdb
= tdb_open_log(state_path("winbindd_cache.tdb"),
3108 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3109 TDB_INCOMPATIBLE_HASH
|
3110 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3111 O_RDWR
|O_CREAT
, 0600);
3113 if (wcache
->tdb
== NULL
) {
3114 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3121 /************************************************************************
3122 This is called by the parent to initialize the cache file.
3123 We don't need sophisticated locking here as we know we're the
3125 ************************************************************************/
3127 bool initialize_winbindd_cache(void)
3129 bool cache_bad
= true;
3132 if (!init_wcache()) {
3133 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3137 /* Check version number. */
3138 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
3139 vers
== WINBINDD_CACHE_VERSION
) {
3144 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3145 "and re-creating with version number %d\n",
3146 WINBINDD_CACHE_VERSION
));
3148 tdb_close(wcache
->tdb
);
3151 if (unlink(state_path("winbindd_cache.tdb")) == -1) {
3152 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3153 state_path("winbindd_cache.tdb"),
3157 if (!init_wcache()) {
3158 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3159 "init_wcache failed.\n"));
3163 /* Write the version. */
3164 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
3165 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3166 tdb_errorstr_compat(wcache
->tdb
) ));
3171 tdb_close(wcache
->tdb
);
3176 void close_winbindd_cache(void)
3182 tdb_close(wcache
->tdb
);
3187 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*sid
,
3188 char **domain_name
, char **name
,
3189 enum lsa_SidType
*type
)
3191 struct winbindd_domain
*domain
;
3194 domain
= find_lookup_domain_from_sid(sid
);
3195 if (domain
== NULL
) {
3198 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
3200 return NT_STATUS_IS_OK(status
);
3203 bool lookup_cached_name(const char *domain_name
,
3205 struct dom_sid
*sid
,
3206 enum lsa_SidType
*type
)
3208 struct winbindd_domain
*domain
;
3210 bool original_online_state
;
3212 domain
= find_lookup_domain_from_name(domain_name
);
3213 if (domain
== NULL
) {
3217 /* If we are doing a cached logon, temporarily set the domain
3218 offline so the cache won't expire the entry */
3220 original_online_state
= domain
->online
;
3221 domain
->online
= false;
3222 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
3223 domain
->online
= original_online_state
;
3225 return NT_STATUS_IS_OK(status
);
3228 void cache_name2sid(struct winbindd_domain
*domain
,
3229 const char *domain_name
, const char *name
,
3230 enum lsa_SidType type
, const struct dom_sid
*sid
)
3232 refresh_sequence_number(domain
, false);
3233 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
3238 * The original idea that this cache only contains centries has
3239 * been blurred - now other stuff gets put in here. Ensure we
3240 * ignore these things on cleanup.
3243 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
3244 TDB_DATA dbuf
, void *state
)
3246 struct cache_entry
*centry
;
3248 if (is_non_centry_key(kbuf
)) {
3252 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
3257 if (!NT_STATUS_IS_OK(centry
->status
)) {
3258 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
3259 tdb_delete(the_tdb
, kbuf
);
3262 centry_free(centry
);
3266 /* flush the cache */
3267 void wcache_flush_cache(void)
3272 tdb_close(wcache
->tdb
);
3275 if (!winbindd_use_cache()) {
3279 /* when working offline we must not clear the cache on restart */
3280 wcache
->tdb
= tdb_open_log(state_path("winbindd_cache.tdb"),
3281 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3282 TDB_INCOMPATIBLE_HASH
|
3283 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3284 O_RDWR
|O_CREAT
, 0600);
3287 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3291 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
3293 DEBUG(10,("wcache_flush_cache success\n"));
3296 /* Count cached creds */
3298 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3301 int *cred_count
= (int*)state
;
3303 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3309 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
3311 struct winbind_cache
*cache
= get_cache(domain
);
3316 return NT_STATUS_INTERNAL_DB_ERROR
;
3319 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
3321 return NT_STATUS_OK
;
3325 struct cred_list
*prev
, *next
;
3330 static struct cred_list
*wcache_cred_list
;
3332 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3335 struct cred_list
*cred
;
3337 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3339 cred
= SMB_MALLOC_P(struct cred_list
);
3341 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3347 /* save a copy of the key */
3349 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
3350 DLIST_ADD(wcache_cred_list
, cred
);
3356 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
3358 struct winbind_cache
*cache
= get_cache(domain
);
3361 struct cred_list
*cred
, *oldest
= NULL
;
3364 return NT_STATUS_INTERNAL_DB_ERROR
;
3367 /* we possibly already have an entry */
3368 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
3370 fstring key_str
, tmp
;
3372 DEBUG(11,("we already have an entry, deleting that\n"));
3374 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
3376 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3378 return NT_STATUS_OK
;
3381 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
3383 return NT_STATUS_OK
;
3384 } else if ((ret
< 0) || (wcache_cred_list
== NULL
)) {
3385 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3388 ZERO_STRUCTP(oldest
);
3390 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
3395 data
= tdb_fetch_compat(cache
->tdb
, string_tdb_data(cred
->name
));
3397 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3399 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3403 t
= IVAL(data
.dptr
, 0);
3404 SAFE_FREE(data
.dptr
);
3407 oldest
= SMB_MALLOC_P(struct cred_list
);
3408 if (oldest
== NULL
) {
3409 status
= NT_STATUS_NO_MEMORY
;
3413 fstrcpy(oldest
->name
, cred
->name
);
3414 oldest
->created
= t
;
3418 if (t
< oldest
->created
) {
3419 fstrcpy(oldest
->name
, cred
->name
);
3420 oldest
->created
= t
;
3424 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3425 status
= NT_STATUS_OK
;
3427 status
= NT_STATUS_UNSUCCESSFUL
;
3430 SAFE_FREE(wcache_cred_list
);
3436 /* Change the global online/offline state. */
3437 bool set_global_winbindd_state_offline(void)
3441 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3443 /* Only go offline if someone has created
3444 the key "WINBINDD_OFFLINE" in the cache tdb. */
3446 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3447 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3451 if (!lp_winbind_offline_logon()) {
3452 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3456 if (global_winbindd_offline_state
) {
3457 /* Already offline. */
3461 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
3463 if (!data
.dptr
|| data
.dsize
!= 4) {
3464 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3465 SAFE_FREE(data
.dptr
);
3468 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3469 global_winbindd_offline_state
= true;
3470 SAFE_FREE(data
.dptr
);
3475 void set_global_winbindd_state_online(void)
3477 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3479 if (!lp_winbind_offline_logon()) {
3480 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3484 if (!global_winbindd_offline_state
) {
3485 /* Already online. */
3488 global_winbindd_offline_state
= false;
3494 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3495 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3498 bool get_global_winbindd_state_offline(void)
3500 return global_winbindd_offline_state
;
3503 /***********************************************************************
3504 Validate functions for all possible cache tdb keys.
3505 ***********************************************************************/
3507 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3508 struct tdb_validation_status
*state
)
3510 struct cache_entry
*centry
;
3512 centry
= SMB_XMALLOC_P(struct cache_entry
);
3513 centry
->data
= (unsigned char *)memdup(data
.dptr
, data
.dsize
);
3514 if (!centry
->data
) {
3518 centry
->len
= data
.dsize
;
3521 if (centry
->len
< 16) {
3522 /* huh? corrupt cache? */
3523 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3524 "(len < 16) ?\n", kstr
));
3525 centry_free(centry
);
3526 state
->bad_entry
= true;
3527 state
->success
= false;
3531 centry
->status
= NT_STATUS(centry_uint32(centry
));
3532 centry
->sequence_number
= centry_uint32(centry
);
3533 centry
->timeout
= centry_uint64_t(centry
);
3537 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3538 struct tdb_validation_status
*state
)
3540 if (dbuf
.dsize
!= 8) {
3541 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3542 keystr
, (unsigned int)dbuf
.dsize
));
3543 state
->bad_entry
= true;
3549 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3550 struct tdb_validation_status
*state
)
3552 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3557 (void)centry_uint32(centry
);
3558 if (NT_STATUS_IS_OK(centry
->status
)) {
3560 (void)centry_sid(centry
, &sid
);
3563 centry_free(centry
);
3565 if (!(state
->success
)) {
3568 DEBUG(10,("validate_ns: %s ok\n", keystr
));
3572 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3573 struct tdb_validation_status
*state
)
3575 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3580 if (NT_STATUS_IS_OK(centry
->status
)) {
3581 (void)centry_uint32(centry
);
3582 (void)centry_string(centry
, mem_ctx
);
3583 (void)centry_string(centry
, mem_ctx
);
3586 centry_free(centry
);
3588 if (!(state
->success
)) {
3591 DEBUG(10,("validate_sn: %s ok\n", keystr
));
3595 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3596 struct tdb_validation_status
*state
)
3598 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3605 (void)centry_string(centry
, mem_ctx
);
3606 (void)centry_string(centry
, mem_ctx
);
3607 (void)centry_string(centry
, mem_ctx
);
3608 (void)centry_string(centry
, mem_ctx
);
3609 (void)centry_uint32(centry
);
3610 (void)centry_sid(centry
, &sid
);
3611 (void)centry_sid(centry
, &sid
);
3613 centry_free(centry
);
3615 if (!(state
->success
)) {
3618 DEBUG(10,("validate_u: %s ok\n", keystr
));
3622 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3623 struct tdb_validation_status
*state
)
3625 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3631 (void)centry_nttime(centry
);
3632 (void)centry_nttime(centry
);
3633 (void)centry_uint16(centry
);
3635 centry_free(centry
);
3637 if (!(state
->success
)) {
3640 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3644 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3645 struct tdb_validation_status
*state
)
3647 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3653 (void)centry_uint16(centry
);
3654 (void)centry_uint16(centry
);
3655 (void)centry_uint32(centry
);
3656 (void)centry_nttime(centry
);
3657 (void)centry_nttime(centry
);
3659 centry_free(centry
);
3661 if (!(state
->success
)) {
3664 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3668 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3669 struct tdb_validation_status
*state
)
3671 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3677 (void)centry_time(centry
);
3678 (void)centry_hash16(centry
, mem_ctx
);
3680 /* We only have 17 bytes more data in the salted cred case. */
3681 if (centry
->len
- centry
->ofs
== 17) {
3682 (void)centry_hash16(centry
, mem_ctx
);
3685 centry_free(centry
);
3687 if (!(state
->success
)) {
3690 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3694 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3695 struct tdb_validation_status
*state
)
3697 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3698 int32 num_entries
, i
;
3704 num_entries
= (int32
)centry_uint32(centry
);
3706 for (i
=0; i
< num_entries
; i
++) {
3708 (void)centry_string(centry
, mem_ctx
);
3709 (void)centry_string(centry
, mem_ctx
);
3710 (void)centry_string(centry
, mem_ctx
);
3711 (void)centry_string(centry
, mem_ctx
);
3712 (void)centry_sid(centry
, &sid
);
3713 (void)centry_sid(centry
, &sid
);
3716 centry_free(centry
);
3718 if (!(state
->success
)) {
3721 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3725 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3726 struct tdb_validation_status
*state
)
3728 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3729 int32 num_entries
, i
;
3735 num_entries
= centry_uint32(centry
);
3737 for (i
=0; i
< num_entries
; i
++) {
3738 (void)centry_string(centry
, mem_ctx
);
3739 (void)centry_string(centry
, mem_ctx
);
3740 (void)centry_uint32(centry
);
3743 centry_free(centry
);
3745 if (!(state
->success
)) {
3748 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3752 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3753 struct tdb_validation_status
*state
)
3755 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3756 int32 num_groups
, i
;
3762 num_groups
= centry_uint32(centry
);
3764 for (i
=0; i
< num_groups
; i
++) {
3766 centry_sid(centry
, &sid
);
3769 centry_free(centry
);
3771 if (!(state
->success
)) {
3774 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3778 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3779 struct tdb_validation_status
*state
)
3781 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3782 int32 num_aliases
, i
;
3788 num_aliases
= centry_uint32(centry
);
3790 for (i
=0; i
< num_aliases
; i
++) {
3791 (void)centry_uint32(centry
);
3794 centry_free(centry
);
3796 if (!(state
->success
)) {
3799 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3803 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3804 struct tdb_validation_status
*state
)
3806 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3813 num_names
= centry_uint32(centry
);
3815 for (i
=0; i
< num_names
; i
++) {
3817 centry_sid(centry
, &sid
);
3818 (void)centry_string(centry
, mem_ctx
);
3819 (void)centry_uint32(centry
);
3822 centry_free(centry
);
3824 if (!(state
->success
)) {
3827 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3831 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3832 struct tdb_validation_status
*state
)
3834 /* Can't say anything about this other than must be nonzero. */
3835 if (dbuf
.dsize
== 0) {
3836 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3838 state
->bad_entry
= true;
3839 state
->success
= false;
3843 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3847 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3848 struct tdb_validation_status
*state
)
3850 /* Can't say anything about this other than must be nonzero. */
3851 if (dbuf
.dsize
== 0) {
3852 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3854 state
->bad_entry
= true;
3855 state
->success
= false;
3859 DEBUG(10,("validate_de: %s ok\n", keystr
));
3863 static int validate_pwinfo(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3864 TDB_DATA dbuf
, struct tdb_validation_status
*state
)
3866 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3872 (void)centry_string(centry
, mem_ctx
);
3873 (void)centry_string(centry
, mem_ctx
);
3874 (void)centry_string(centry
, mem_ctx
);
3875 (void)centry_uint32(centry
);
3877 centry_free(centry
);
3879 if (!(state
->success
)) {
3882 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3886 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3888 struct tdb_validation_status
*state
)
3890 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3896 (void)centry_string( centry
, mem_ctx
);
3898 centry_free(centry
);
3900 if (!(state
->success
)) {
3903 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3907 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3909 struct tdb_validation_status
*state
)
3911 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3917 (void)centry_string( centry
, mem_ctx
);
3919 centry_free(centry
);
3921 if (!(state
->success
)) {
3924 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3928 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3930 struct tdb_validation_status
*state
)
3932 if (dbuf
.dsize
== 0) {
3933 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3934 "key %s (len ==0) ?\n", keystr
));
3935 state
->bad_entry
= true;
3936 state
->success
= false;
3940 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3941 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3945 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3946 struct tdb_validation_status
*state
)
3948 if (dbuf
.dsize
!= 4) {
3949 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3950 keystr
, (unsigned int)dbuf
.dsize
));
3951 state
->bad_entry
= true;
3952 state
->success
= false;
3955 DEBUG(10,("validate_offline: %s ok\n", keystr
));
3959 static int validate_ndr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3960 struct tdb_validation_status
*state
)
3963 * Ignore validation for now. The proper way to do this is with a
3964 * checksum. Just pure parsing does not really catch much.
3969 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3970 struct tdb_validation_status
*state
)
3972 if (dbuf
.dsize
!= 4) {
3973 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3974 "key %s (len %u != 4) ?\n",
3975 keystr
, (unsigned int)dbuf
.dsize
));
3976 state
->bad_entry
= true;
3977 state
->success
= false;
3981 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
3985 /***********************************************************************
3986 A list of all possible cache tdb keys with associated validation
3988 ***********************************************************************/
3990 struct key_val_struct
{
3991 const char *keyname
;
3992 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
3994 {"SEQNUM/", validate_seqnum
},
3995 {"NS/", validate_ns
},
3996 {"SN/", validate_sn
},
3998 {"LOC_POL/", validate_loc_pol
},
3999 {"PWD_POL/", validate_pwd_pol
},
4000 {"CRED/", validate_cred
},
4001 {"UL/", validate_ul
},
4002 {"GL/", validate_gl
},
4003 {"UG/", validate_ug
},
4004 {"UA", validate_ua
},
4005 {"GM/", validate_gm
},
4006 {"DR/", validate_dr
},
4007 {"DE/", validate_de
},
4008 {"NSS/PWINFO/", validate_pwinfo
},
4009 {"TRUSTDOMCACHE/", validate_trustdomcache
},
4010 {"NSS/NA/", validate_nss_na
},
4011 {"NSS/AN/", validate_nss_an
},
4012 {"WINBINDD_OFFLINE", validate_offline
},
4013 {"NDR/", validate_ndr
},
4014 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
4018 /***********************************************************************
4019 Function to look at every entry in the tdb and validate it as far as
4021 ***********************************************************************/
4023 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
4026 unsigned int max_key_len
= 1024;
4027 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
4029 /* Paranoia check. */
4030 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0) {
4031 max_key_len
= 1024 * 1024;
4033 if (kbuf
.dsize
> max_key_len
) {
4034 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4036 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
4040 for (i
= 0; key_val
[i
].keyname
; i
++) {
4041 size_t namelen
= strlen(key_val
[i
].keyname
);
4042 if (kbuf
.dsize
>= namelen
&& (
4043 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
4044 TALLOC_CTX
*mem_ctx
;
4048 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
4052 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
4053 keystr
[kbuf
.dsize
] = '\0';
4055 mem_ctx
= talloc_init("validate_ctx");
4061 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
4065 talloc_destroy(mem_ctx
);
4070 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4071 dump_data(0, (uint8
*)kbuf
.dptr
, kbuf
.dsize
);
4072 DEBUG(0,("data :\n"));
4073 dump_data(0, (uint8
*)dbuf
.dptr
, dbuf
.dsize
);
4074 v_state
->unknown_key
= true;
4075 v_state
->success
= false;
4076 return 1; /* terminate. */
4079 static void validate_panic(const char *const why
)
4081 DEBUG(0,("validating cache: would panic %s\n", why
));
4082 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4086 static int wbcache_update_centry_fn(TDB_CONTEXT
*tdb
,
4094 if (is_non_centry_key(key
)) {
4098 if (data
.dptr
== NULL
|| data
.dsize
== 0) {
4099 if (tdb_delete(tdb
, key
) < 0) {
4100 DEBUG(0, ("tdb_delete for [%s] failed!\n",
4106 /* add timeout to blob (uint64_t) */
4107 blob
.dsize
= data
.dsize
+ 8;
4109 blob
.dptr
= SMB_XMALLOC_ARRAY(uint8_t, blob
.dsize
);
4110 if (blob
.dptr
== NULL
) {
4113 memset(blob
.dptr
, 0, blob
.dsize
);
4115 /* copy status and seqnum */
4116 memcpy(blob
.dptr
, data
.dptr
, 8);
4119 ctimeout
= lp_winbind_cache_time() + time(NULL
);
4120 SBVAL(blob
.dptr
, 8, ctimeout
);
4123 memcpy(blob
.dptr
+ 16, data
.dptr
+ 8, data
.dsize
- 8);
4125 if (tdb_store(tdb
, key
, blob
, TDB_REPLACE
) < 0) {
4126 DEBUG(0, ("tdb_store to update [%s] failed!\n",
4128 SAFE_FREE(blob
.dptr
);
4132 SAFE_FREE(blob
.dptr
);
4136 static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT
*tdb
)
4140 DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
4142 rc
= tdb_traverse(tdb
, wbcache_update_centry_fn
, NULL
);
4150 /***********************************************************************
4151 Try and validate every entry in the winbindd cache. If we fail here,
4152 delete the cache tdb and return non-zero.
4153 ***********************************************************************/
4155 int winbindd_validate_cache(void)
4158 const char *tdb_path
= state_path("winbindd_cache.tdb");
4159 TDB_CONTEXT
*tdb
= NULL
;
4163 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4164 smb_panic_fn
= validate_panic
;
4166 tdb
= tdb_open_log(tdb_path
,
4167 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
4168 TDB_INCOMPATIBLE_HASH
|
4169 ( lp_winbind_offline_logon()
4171 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
4175 DEBUG(0, ("winbindd_validate_cache: "
4176 "error opening/initializing tdb\n"));
4180 /* Version check and upgrade code. */
4181 if (!tdb_fetch_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers_id
)) {
4182 DEBUG(10, ("Fresh database\n"));
4183 tdb_store_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
);
4184 vers_id
= WINBINDD_CACHE_VERSION
;
4187 if (vers_id
!= WINBINDD_CACHE_VERSION
) {
4188 if (vers_id
== WINBINDD_CACHE_VER1
) {
4189 ok
= wbcache_upgrade_v1_to_v2(tdb
);
4191 DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
4196 tdb_store_uint32(tdb
,
4197 WINBINDD_CACHE_VERSION_KEYSTR
,
4198 WINBINDD_CACHE_VERSION
);
4199 vers_id
= WINBINDD_CACHE_VER2
;
4205 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
4208 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4209 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
4214 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4215 smb_panic_fn
= smb_panic
;
4219 /***********************************************************************
4220 Try and validate every entry in the winbindd cache.
4221 ***********************************************************************/
4223 int winbindd_validate_cache_nobackup(void)
4226 const char *tdb_path
= state_path("winbindd_cache.tdb");
4228 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4229 smb_panic_fn
= validate_panic
;
4232 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
4233 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
4235 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
4239 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4243 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4245 smb_panic_fn
= smb_panic
;
4249 bool winbindd_cache_validate_and_initialize(void)
4251 close_winbindd_cache();
4253 if (lp_winbind_offline_logon()) {
4254 if (winbindd_validate_cache() < 0) {
4255 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4256 "could be restored.\n"));
4260 return initialize_winbindd_cache();
4263 /*********************************************************************
4264 ********************************************************************/
4266 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
4267 struct winbindd_tdc_domain
**domains
,
4268 size_t *num_domains
)
4270 struct winbindd_tdc_domain
*list
= NULL
;
4273 bool set_only
= false;
4275 /* don't allow duplicates */
4280 for ( i
=0; i
< (*num_domains
); i
++ ) {
4281 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
4282 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4293 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, 1 );
4296 list
= talloc_realloc( *domains
, *domains
,
4297 struct winbindd_tdc_domain
,
4302 ZERO_STRUCT( list
[idx
] );
4308 list
[idx
].domain_name
= talloc_strdup( list
, new_dom
->name
);
4309 list
[idx
].dns_name
= talloc_strdup( list
, new_dom
->alt_name
);
4311 if ( !is_null_sid( &new_dom
->sid
) ) {
4312 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
4314 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
4317 if ( new_dom
->domain_flags
!= 0x0 )
4318 list
[idx
].trust_flags
= new_dom
->domain_flags
;
4320 if ( new_dom
->domain_type
!= 0x0 )
4321 list
[idx
].trust_type
= new_dom
->domain_type
;
4323 if ( new_dom
->domain_trust_attribs
!= 0x0 )
4324 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
4328 *num_domains
= idx
+ 1;
4334 /*********************************************************************
4335 ********************************************************************/
4337 static TDB_DATA
make_tdc_key( const char *domain_name
)
4339 char *keystr
= NULL
;
4340 TDB_DATA key
= { NULL
, 0 };
4342 if ( !domain_name
) {
4343 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4347 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
4350 key
= string_term_tdb_data(keystr
);
4355 /*********************************************************************
4356 ********************************************************************/
4358 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
4360 unsigned char **buf
)
4362 unsigned char *buffer
= NULL
;
4367 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4375 /* Store the number of array items first */
4376 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
4379 /* now pack each domain trust record */
4380 for ( i
=0; i
<num_domains
; i
++ ) {
4385 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4386 domains
[i
].domain_name
,
4387 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
4390 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
4391 domains
[i
].domain_name
,
4392 domains
[i
].dns_name
,
4393 sid_to_fstring(tmp
, &domains
[i
].sid
),
4394 domains
[i
].trust_flags
,
4395 domains
[i
].trust_attribs
,
4396 domains
[i
].trust_type
);
4399 if ( buflen
< len
) {
4401 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
4402 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4416 /*********************************************************************
4417 ********************************************************************/
4419 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
4420 struct winbindd_tdc_domain
**domains
)
4422 fstring domain_name
, dns_name
, sid_string
;
4423 uint32 type
, attribs
, flags
;
4427 struct winbindd_tdc_domain
*list
= NULL
;
4429 /* get the number of domains */
4430 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
4432 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4436 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, num_domains
);
4438 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4442 for ( i
=0; i
<num_domains
; i
++ ) {
4443 len
+= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
4452 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4453 TALLOC_FREE( list
);
4457 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4458 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4459 domain_name
, dns_name
, sid_string
,
4460 flags
, attribs
, type
));
4462 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
4463 list
[i
].dns_name
= talloc_strdup( list
, dns_name
);
4464 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
4465 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4468 list
[i
].trust_flags
= flags
;
4469 list
[i
].trust_attribs
= attribs
;
4470 list
[i
].trust_type
= type
;
4478 /*********************************************************************
4479 ********************************************************************/
4481 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
4483 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4484 TDB_DATA data
= { NULL
, 0 };
4490 /* See if we were asked to delete the cache entry */
4493 ret
= tdb_delete( wcache
->tdb
, key
);
4497 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4504 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4507 SAFE_FREE( data
.dptr
);
4508 SAFE_FREE( key
.dptr
);
4510 return ( ret
== 0 );
4513 /*********************************************************************
4514 ********************************************************************/
4516 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4518 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4519 TDB_DATA data
= { NULL
, 0 };
4527 data
= tdb_fetch_compat( wcache
->tdb
, key
);
4529 SAFE_FREE( key
.dptr
);
4534 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4536 SAFE_FREE( data
.dptr
);
4544 /*********************************************************************
4545 ********************************************************************/
4547 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4549 struct winbindd_tdc_domain
*dom_list
= NULL
;
4550 size_t num_domains
= 0;
4553 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4554 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4555 domain
->name
, domain
->alt_name
,
4556 sid_string_dbg(&domain
->sid
),
4557 domain
->domain_flags
,
4558 domain
->domain_trust_attribs
,
4559 domain
->domain_type
));
4561 if ( !init_wcache() ) {
4565 /* fetch the list */
4567 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4569 /* add the new domain */
4571 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4575 /* pack the domain */
4577 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4585 TALLOC_FREE( dom_list
);
4590 /*********************************************************************
4591 ********************************************************************/
4593 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4595 struct winbindd_tdc_domain
*dom_list
= NULL
;
4596 size_t num_domains
= 0;
4598 struct winbindd_tdc_domain
*d
= NULL
;
4600 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4602 if ( !init_wcache() ) {
4606 /* fetch the list */
4608 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4610 for ( i
=0; i
<num_domains
; i
++ ) {
4611 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4612 strequal(name
, dom_list
[i
].dns_name
) )
4614 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4617 d
= talloc( ctx
, struct winbindd_tdc_domain
);
4621 d
->domain_name
= talloc_strdup( d
, dom_list
[i
].domain_name
);
4622 d
->dns_name
= talloc_strdup( d
, dom_list
[i
].dns_name
);
4623 sid_copy( &d
->sid
, &dom_list
[i
].sid
);
4624 d
->trust_flags
= dom_list
[i
].trust_flags
;
4625 d
->trust_type
= dom_list
[i
].trust_type
;
4626 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
4632 TALLOC_FREE( dom_list
);
4637 /*********************************************************************
4638 ********************************************************************/
4640 struct winbindd_tdc_domain
*
4641 wcache_tdc_fetch_domainbysid(TALLOC_CTX
*ctx
,
4642 const struct dom_sid
*sid
)
4644 struct winbindd_tdc_domain
*dom_list
= NULL
;
4645 size_t num_domains
= 0;
4647 struct winbindd_tdc_domain
*d
= NULL
;
4649 DEBUG(10,("wcache_tdc_fetch_domainbysid: Searching for domain %s\n",
4650 sid_string_dbg(sid
)));
4652 if (!init_wcache()) {
4656 /* fetch the list */
4658 wcache_tdc_fetch_list(&dom_list
, &num_domains
);
4660 for (i
= 0; i
<num_domains
; i
++) {
4661 if (dom_sid_equal(sid
, &(dom_list
[i
].sid
))) {
4662 DEBUG(10, ("wcache_tdc_fetch_domainbysid: "
4663 "Found domain %s for SID %s\n",
4664 dom_list
[i
].domain_name
,
4665 sid_string_dbg(sid
)));
4667 d
= talloc(ctx
, struct winbindd_tdc_domain
);
4671 d
->domain_name
= talloc_strdup(d
,
4672 dom_list
[i
].domain_name
);
4674 d
->dns_name
= talloc_strdup(d
, dom_list
[i
].dns_name
);
4675 sid_copy(&d
->sid
, &dom_list
[i
].sid
);
4676 d
->trust_flags
= dom_list
[i
].trust_flags
;
4677 d
->trust_type
= dom_list
[i
].trust_type
;
4678 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
4684 TALLOC_FREE(dom_list
);
4690 /*********************************************************************
4691 ********************************************************************/
4693 void wcache_tdc_clear( void )
4695 if ( !init_wcache() )
4698 wcache_tdc_store_list( NULL
, 0 );
4704 /*********************************************************************
4705 ********************************************************************/
4707 static void wcache_save_user_pwinfo(struct winbindd_domain
*domain
,
4709 const struct dom_sid
*user_sid
,
4710 const char *homedir
,
4715 struct cache_entry
*centry
;
4718 if ( (centry
= centry_start(domain
, status
)) == NULL
)
4721 centry_put_string( centry
, homedir
);
4722 centry_put_string( centry
, shell
);
4723 centry_put_string( centry
, gecos
);
4724 centry_put_uint32( centry
, gid
);
4726 centry_end(centry
, "NSS/PWINFO/%s", sid_to_fstring(tmp
, user_sid
) );
4728 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid
) ));
4730 centry_free(centry
);
4735 NTSTATUS
nss_get_info_cached( struct winbindd_domain
*domain
,
4736 const struct dom_sid
*user_sid
,
4738 const char **homedir
, const char **shell
,
4739 const char **gecos
, gid_t
*p_gid
)
4741 struct winbind_cache
*cache
= get_cache(domain
);
4742 struct cache_entry
*centry
= NULL
;
4749 centry
= wcache_fetch(cache
, domain
, "NSS/PWINFO/%s",
4750 sid_to_fstring(tmp
, user_sid
));
4755 *homedir
= centry_string( centry
, ctx
);
4756 *shell
= centry_string( centry
, ctx
);
4757 *gecos
= centry_string( centry
, ctx
);
4758 *p_gid
= centry_uint32( centry
);
4760 centry_free(centry
);
4762 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4763 sid_string_dbg(user_sid
)));
4765 return NT_STATUS_OK
;
4769 nt_status
= nss_get_info( domain
->name
, user_sid
, ctx
,
4770 homedir
, shell
, gecos
, p_gid
);
4772 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status
)));
4774 if ( NT_STATUS_IS_OK(nt_status
) ) {
4775 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir
));
4776 DEBUGADD(10, ("\tshell = '%s'\n", *shell
));
4777 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos
));
4778 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid
));
4780 wcache_save_user_pwinfo( domain
, nt_status
, user_sid
,
4781 *homedir
, *shell
, *gecos
, *p_gid
);
4784 if ( NT_STATUS_EQUAL( nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
4785 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4787 set_domain_offline( domain
);
4795 /* the cache backend methods are exposed via this structure */
4796 struct winbindd_methods cache_methods
= {
4814 static bool wcache_ndr_key(TALLOC_CTX
*mem_ctx
, char *domain_name
,
4815 uint32_t opnum
, const DATA_BLOB
*req
,
4821 key
= talloc_asprintf(mem_ctx
, "NDR/%s/%d/", domain_name
, (int)opnum
);
4825 keylen
= talloc_get_size(key
) - 1;
4827 key
= talloc_realloc(mem_ctx
, key
, char, keylen
+ req
->length
);
4831 memcpy(key
+ keylen
, req
->data
, req
->length
);
4833 pkey
->dptr
= (uint8_t *)key
;
4834 pkey
->dsize
= talloc_get_size(key
);
4838 static bool wcache_opnum_cacheable(uint32_t opnum
)
4841 case NDR_WBINT_PING
:
4842 case NDR_WBINT_QUERYSEQUENCENUMBER
:
4843 case NDR_WBINT_ALLOCATEUID
:
4844 case NDR_WBINT_ALLOCATEGID
:
4845 case NDR_WBINT_CHECKMACHINEACCOUNT
:
4846 case NDR_WBINT_CHANGEMACHINEACCOUNT
:
4847 case NDR_WBINT_PINGDC
:
4853 bool wcache_fetch_ndr(TALLOC_CTX
*mem_ctx
, struct winbindd_domain
*domain
,
4854 uint32_t opnum
, const DATA_BLOB
*req
, DATA_BLOB
*resp
)
4859 if (!wcache_opnum_cacheable(opnum
) ||
4860 is_my_own_sam_domain(domain
) ||
4861 is_builtin_domain(domain
)) {
4865 if (wcache
->tdb
== NULL
) {
4869 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4872 data
= tdb_fetch_compat(wcache
->tdb
, key
);
4873 TALLOC_FREE(key
.dptr
);
4875 if (data
.dptr
== NULL
) {
4878 if (data
.dsize
< 12) {
4882 if (!is_domain_offline(domain
)) {
4883 uint32_t entry_seqnum
, dom_seqnum
, last_check
;
4884 uint64_t entry_timeout
;
4886 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
,
4890 entry_seqnum
= IVAL(data
.dptr
, 0);
4891 if (entry_seqnum
!= dom_seqnum
) {
4892 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4893 (int)entry_seqnum
));
4896 entry_timeout
= BVAL(data
.dptr
, 4);
4897 if (time(NULL
) > entry_timeout
) {
4898 DEBUG(10, ("Entry has timed out\n"));
4903 resp
->data
= (uint8_t *)talloc_memdup(mem_ctx
, data
.dptr
+ 12,
4905 if (resp
->data
== NULL
) {
4906 DEBUG(10, ("talloc failed\n"));
4909 resp
->length
= data
.dsize
- 12;
4913 SAFE_FREE(data
.dptr
);
4917 void wcache_store_ndr(struct winbindd_domain
*domain
, uint32_t opnum
,
4918 const DATA_BLOB
*req
, const DATA_BLOB
*resp
)
4921 uint32_t dom_seqnum
, last_check
;
4924 if (!wcache_opnum_cacheable(opnum
) ||
4925 is_my_own_sam_domain(domain
) ||
4926 is_builtin_domain(domain
)) {
4930 if (wcache
->tdb
== NULL
) {
4934 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
, &last_check
)) {
4935 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4940 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4944 timeout
= time(NULL
) + lp_winbind_cache_time();
4946 data
.dsize
= resp
->length
+ 12;
4947 data
.dptr
= talloc_array(key
.dptr
, uint8_t, data
.dsize
);
4948 if (data
.dptr
== NULL
) {
4952 SIVAL(data
.dptr
, 0, dom_seqnum
);
4953 SBVAL(data
.dptr
, 4, timeout
);
4954 memcpy(data
.dptr
+ 12, resp
->data
, resp
->length
);
4956 tdb_store(wcache
->tdb
, key
, data
, 0);
4959 TALLOC_FREE(key
.dptr
);