2 Unix SMB/CIFS implementation.
4 Winbind cache backend functions
6 Copyright (C) Andrew Tridgell 2001
7 Copyright (C) Gerald Carter 2003-2007
8 Copyright (C) Volker Lendecke 2005
9 Copyright (C) Guenther Deschner 2005
10 Copyright (C) Michael Adam 2007
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include "system/filesys.h"
29 #include "tdb_validate.h"
30 #include "../libcli/auth/libcli_auth.h"
31 #include "../librpc/gen_ndr/ndr_wbint.h"
34 #include "../libcli/security/security.h"
35 #include "passdb/machine_sid.h"
39 #define DBGC_CLASS DBGC_WINBIND
41 #define WINBINDD_CACHE_VER1 1 /* initial db version */
42 #define WINBINDD_CACHE_VER2 2 /* second version with timeouts for NDR entries */
44 #define WINBINDD_CACHE_VERSION WINBINDD_CACHE_VER2
45 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
47 extern struct winbindd_methods reconnect_methods
;
49 extern struct winbindd_methods ads_methods
;
51 extern struct winbindd_methods builtin_passdb_methods
;
52 extern struct winbindd_methods sam_passdb_methods
;
55 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
56 * Here are the list of entry types that are *not* stored
57 * as form struct cache_entry in the cache.
60 static const char *non_centry_keys
[] = {
63 WINBINDD_CACHE_VERSION_KEYSTR
,
67 /************************************************************************
68 Is this key a non-centry type ?
69 ************************************************************************/
71 static bool is_non_centry_key(TDB_DATA kbuf
)
75 if (kbuf
.dptr
== NULL
|| kbuf
.dsize
== 0) {
78 for (i
= 0; non_centry_keys
[i
] != NULL
; i
++) {
79 size_t namelen
= strlen(non_centry_keys
[i
]);
80 if (kbuf
.dsize
< namelen
) {
83 if (strncmp(non_centry_keys
[i
], (const char *)kbuf
.dptr
, namelen
) == 0) {
90 /* Global online/offline state - False when online. winbindd starts up online
91 and sets this to true if the first query fails and there's an entry in
92 the cache tdb telling us to stay offline. */
94 static bool global_winbindd_offline_state
;
96 struct winbind_cache
{
102 uint32 sequence_number
;
108 void (*smb_panic_fn
)(const char *const why
) = smb_panic
;
110 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
112 static struct winbind_cache
*wcache
;
114 /* get the winbind_cache structure */
115 static struct winbind_cache
*get_cache(struct winbindd_domain
*domain
)
117 struct winbind_cache
*ret
= wcache
;
119 /* We have to know what type of domain we are dealing with first. */
121 if (domain
->internal
) {
122 domain
->backend
= &builtin_passdb_methods
;
123 domain
->initialized
= True
;
126 if (strequal(domain
->name
, get_global_sam_name()) &&
127 sid_check_is_our_sam(&domain
->sid
)) {
128 domain
->backend
= &sam_passdb_methods
;
129 domain
->initialized
= True
;
132 if ( !domain
->initialized
) {
133 init_dc_connection( domain
);
137 OK. listen up becasue I'm only going to say this once.
138 We have the following scenarios to consider
139 (a) trusted AD domains on a Samba DC,
140 (b) trusted AD domains and we are joined to a non-kerberos domain
141 (c) trusted AD domains and we are joined to a kerberos (AD) domain
143 For (a) we can always contact the trusted domain using krb5
144 since we have the domain trust account password
146 For (b) we can only use RPC since we have no way of
147 getting a krb5 ticket in our own domain
149 For (c) we can always use krb5 since we have a kerberos trust
154 if (!domain
->backend
) {
156 struct winbindd_domain
*our_domain
= domain
;
158 /* find our domain first so we can figure out if we
159 are joined to a kerberized domain */
161 if ( !domain
->primary
)
162 our_domain
= find_our_domain();
164 if ((our_domain
->active_directory
|| IS_DC
)
165 && domain
->active_directory
166 && !lp_winbind_rpc_only()) {
167 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain
->name
));
168 domain
->backend
= &ads_methods
;
170 #endif /* HAVE_ADS */
171 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain
->name
));
172 domain
->backend
= &reconnect_methods
;
175 #endif /* HAVE_ADS */
181 ret
= SMB_XMALLOC_P(struct winbind_cache
);
185 wcache_flush_cache();
191 free a centry structure
193 static void centry_free(struct cache_entry
*centry
)
197 SAFE_FREE(centry
->data
);
201 static bool centry_check_bytes(struct cache_entry
*centry
, size_t nbytes
)
203 if (centry
->len
- centry
->ofs
< nbytes
) {
204 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
205 (unsigned int)nbytes
,
206 centry
->len
- centry
->ofs
));
213 pull a uint64_t from a cache entry
215 static uint64_t centry_uint64_t(struct cache_entry
*centry
)
219 if (!centry_check_bytes(centry
, 8)) {
220 smb_panic_fn("centry_uint64_t");
222 ret
= BVAL(centry
->data
, centry
->ofs
);
228 pull a uint32 from a cache entry
230 static uint32
centry_uint32(struct cache_entry
*centry
)
234 if (!centry_check_bytes(centry
, 4)) {
235 smb_panic_fn("centry_uint32");
237 ret
= IVAL(centry
->data
, centry
->ofs
);
243 pull a uint16 from a cache entry
245 static uint16
centry_uint16(struct cache_entry
*centry
)
248 if (!centry_check_bytes(centry
, 2)) {
249 smb_panic_fn("centry_uint16");
251 ret
= SVAL(centry
->data
, centry
->ofs
);
257 pull a uint8 from a cache entry
259 static uint8
centry_uint8(struct cache_entry
*centry
)
262 if (!centry_check_bytes(centry
, 1)) {
263 smb_panic_fn("centry_uint8");
265 ret
= CVAL(centry
->data
, centry
->ofs
);
271 pull a NTTIME from a cache entry
273 static NTTIME
centry_nttime(struct cache_entry
*centry
)
276 if (!centry_check_bytes(centry
, 8)) {
277 smb_panic_fn("centry_nttime");
279 ret
= IVAL(centry
->data
, centry
->ofs
);
281 ret
+= (uint64
)IVAL(centry
->data
, centry
->ofs
) << 32;
287 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
289 static time_t centry_time(struct cache_entry
*centry
)
291 return (time_t)centry_nttime(centry
);
294 /* pull a string from a cache entry, using the supplied
297 static char *centry_string(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
302 len
= centry_uint8(centry
);
305 /* a deliberate NULL string */
309 if (!centry_check_bytes(centry
, (size_t)len
)) {
310 smb_panic_fn("centry_string");
313 ret
= talloc_array(mem_ctx
, char, len
+1);
315 smb_panic_fn("centry_string out of memory\n");
317 memcpy(ret
,centry
->data
+ centry
->ofs
, len
);
323 /* pull a hash16 from a cache entry, using the supplied
326 static char *centry_hash16(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
331 len
= centry_uint8(centry
);
334 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
339 if (!centry_check_bytes(centry
, 16)) {
343 ret
= talloc_array(mem_ctx
, char, 16);
345 smb_panic_fn("centry_hash out of memory\n");
347 memcpy(ret
,centry
->data
+ centry
->ofs
, 16);
352 /* pull a sid from a cache entry, using the supplied
355 static bool centry_sid(struct cache_entry
*centry
, struct dom_sid
*sid
)
360 sid_string
= centry_string(centry
, talloc_tos());
361 if (sid_string
== NULL
) {
364 ret
= string_to_sid(sid
, sid_string
);
365 TALLOC_FREE(sid_string
);
371 pull a NTSTATUS from a cache entry
373 static NTSTATUS
centry_ntstatus(struct cache_entry
*centry
)
377 status
= NT_STATUS(centry_uint32(centry
));
382 /* the server is considered down if it can't give us a sequence number */
383 static bool wcache_server_down(struct winbindd_domain
*domain
)
390 ret
= (domain
->sequence_number
== DOM_SEQUENCE_NONE
);
393 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
398 static bool wcache_fetch_seqnum(const char *domain_name
, uint32_t *seqnum
,
399 uint32_t *last_seq_check
)
404 if (wcache
->tdb
== NULL
) {
405 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
409 key
= talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name
);
411 DEBUG(10, ("talloc failed\n"));
415 data
= tdb_fetch_bystring(wcache
->tdb
, key
);
418 if (data
.dptr
== NULL
) {
419 DEBUG(10, ("wcache_fetch_seqnum: %s not found\n",
423 if (data
.dsize
!= 8) {
424 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
426 SAFE_FREE(data
.dptr
);
430 *seqnum
= IVAL(data
.dptr
, 0);
431 *last_seq_check
= IVAL(data
.dptr
, 4);
432 SAFE_FREE(data
.dptr
);
437 static NTSTATUS
fetch_cache_seqnum( struct winbindd_domain
*domain
, time_t now
)
439 uint32 last_check
, time_diff
;
441 if (!wcache_fetch_seqnum(domain
->name
, &domain
->sequence_number
,
443 return NT_STATUS_UNSUCCESSFUL
;
445 domain
->last_seq_check
= last_check
;
447 /* have we expired? */
449 time_diff
= now
- domain
->last_seq_check
;
450 if ( time_diff
> lp_winbind_cache_time() ) {
451 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
452 domain
->name
, domain
->sequence_number
,
453 (uint32
)domain
->last_seq_check
));
454 return NT_STATUS_UNSUCCESSFUL
;
457 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
458 domain
->name
, domain
->sequence_number
,
459 (uint32
)domain
->last_seq_check
));
464 bool wcache_store_seqnum(const char *domain_name
, uint32_t seqnum
,
465 time_t last_seq_check
)
471 if (wcache
->tdb
== NULL
) {
472 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
476 key_str
= talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name
);
477 if (key_str
== NULL
) {
478 DEBUG(10, ("talloc_asprintf failed\n"));
482 SIVAL(buf
, 0, seqnum
);
483 SIVAL(buf
, 4, last_seq_check
);
485 ret
= tdb_store_bystring(wcache
->tdb
, key_str
,
486 make_tdb_data(buf
, sizeof(buf
)), TDB_REPLACE
);
487 TALLOC_FREE(key_str
);
489 DEBUG(10, ("tdb_store_bystring failed: %s\n",
490 tdb_errorstr_compat(wcache
->tdb
)));
491 TALLOC_FREE(key_str
);
495 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
496 domain_name
, seqnum
, (unsigned)last_seq_check
));
501 static bool store_cache_seqnum( struct winbindd_domain
*domain
)
503 return wcache_store_seqnum(domain
->name
, domain
->sequence_number
,
504 domain
->last_seq_check
);
508 refresh the domain sequence number. If force is true
509 then always refresh it, no matter how recently we fetched it
512 static void refresh_sequence_number(struct winbindd_domain
*domain
, bool force
)
516 time_t t
= time(NULL
);
517 unsigned cache_time
= lp_winbind_cache_time();
519 if (is_domain_offline(domain
)) {
525 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
526 /* trying to reconnect is expensive, don't do it too often */
527 if (domain
->sequence_number
== DOM_SEQUENCE_NONE
) {
532 time_diff
= t
- domain
->last_seq_check
;
534 /* see if we have to refetch the domain sequence number */
535 if (!force
&& (time_diff
< cache_time
) &&
536 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
537 NT_STATUS_IS_OK(domain
->last_status
)) {
538 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain
->name
));
542 /* try to get the sequence number from the tdb cache first */
543 /* this will update the timestamp as well */
545 status
= fetch_cache_seqnum( domain
, t
);
546 if (NT_STATUS_IS_OK(status
) &&
547 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
548 NT_STATUS_IS_OK(domain
->last_status
)) {
552 /* important! make sure that we know if this is a native
553 mode domain or not. And that we can contact it. */
555 if ( winbindd_can_contact_domain( domain
) ) {
556 status
= domain
->backend
->sequence_number(domain
,
557 &domain
->sequence_number
);
559 /* just use the current time */
560 status
= NT_STATUS_OK
;
561 domain
->sequence_number
= time(NULL
);
565 /* the above call could have set our domain->backend to NULL when
566 * coming from offline to online mode, make sure to reinitialize the
567 * backend - Guenther */
570 if (!NT_STATUS_IS_OK(status
)) {
571 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status
)));
572 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
575 domain
->last_status
= status
;
576 domain
->last_seq_check
= time(NULL
);
578 /* save the new sequence number in the cache */
579 store_cache_seqnum( domain
);
582 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
583 domain
->name
, domain
->sequence_number
));
589 decide if a cache entry has expired
591 static bool centry_expired(struct winbindd_domain
*domain
, const char *keystr
, struct cache_entry
*centry
)
593 /* If we've been told to be offline - stay in that state... */
594 if (lp_winbind_offline_logon() && global_winbindd_offline_state
) {
595 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
596 keystr
, domain
->name
));
600 /* when the domain is offline return the cached entry.
601 * This deals with transient offline states... */
603 if (!domain
->online
) {
604 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
605 keystr
, domain
->name
));
609 /* if the server is OK and our cache entry came from when it was down then
610 the entry is invalid */
611 if ((domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
612 (centry
->sequence_number
== DOM_SEQUENCE_NONE
)) {
613 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
614 keystr
, domain
->name
));
618 /* if the server is down or the cache entry is not older than the
619 current sequence number or it did not timeout then it is OK */
620 if (wcache_server_down(domain
)
621 || ((centry
->sequence_number
== domain
->sequence_number
)
622 && (centry
->timeout
> time(NULL
)))) {
623 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
624 keystr
, domain
->name
));
628 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
629 keystr
, domain
->name
));
635 static struct cache_entry
*wcache_fetch_raw(char *kstr
)
638 struct cache_entry
*centry
;
641 key
= string_tdb_data(kstr
);
642 data
= tdb_fetch_compat(wcache
->tdb
, key
);
648 centry
= SMB_XMALLOC_P(struct cache_entry
);
649 centry
->data
= (unsigned char *)data
.dptr
;
650 centry
->len
= data
.dsize
;
653 if (centry
->len
< 16) {
654 /* huh? corrupt cache? */
655 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s "
656 "(len < 16)?\n", kstr
));
661 centry
->status
= centry_ntstatus(centry
);
662 centry
->sequence_number
= centry_uint32(centry
);
663 centry
->timeout
= centry_uint64_t(centry
);
668 static bool is_my_own_sam_domain(struct winbindd_domain
*domain
)
670 if (strequal(domain
->name
, get_global_sam_name()) &&
671 sid_check_is_our_sam(&domain
->sid
)) {
678 static bool is_builtin_domain(struct winbindd_domain
*domain
)
680 if (strequal(domain
->name
, "BUILTIN") &&
681 sid_check_is_builtin(&domain
->sid
)) {
689 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
690 number and return status
692 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
693 struct winbindd_domain
*domain
,
694 const char *format
, ...) PRINTF_ATTRIBUTE(3,4);
695 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
696 struct winbindd_domain
*domain
,
697 const char *format
, ...)
701 struct cache_entry
*centry
;
703 if (!winbindd_use_cache() ||
704 is_my_own_sam_domain(domain
) ||
705 is_builtin_domain(domain
)) {
709 refresh_sequence_number(domain
, false);
711 va_start(ap
, format
);
712 smb_xvasprintf(&kstr
, format
, ap
);
715 centry
= wcache_fetch_raw(kstr
);
716 if (centry
== NULL
) {
721 if (centry_expired(domain
, kstr
, centry
)) {
723 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
724 kstr
, domain
->name
));
731 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
732 kstr
, domain
->name
));
738 static void wcache_delete(const char *format
, ...) PRINTF_ATTRIBUTE(1,2);
739 static void wcache_delete(const char *format
, ...)
745 va_start(ap
, format
);
746 smb_xvasprintf(&kstr
, format
, ap
);
749 key
= string_tdb_data(kstr
);
751 tdb_delete(wcache
->tdb
, key
);
756 make sure we have at least len bytes available in a centry
758 static void centry_expand(struct cache_entry
*centry
, uint32 len
)
760 if (centry
->len
- centry
->ofs
>= len
)
763 centry
->data
= SMB_REALLOC_ARRAY(centry
->data
, unsigned char,
766 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry
->len
));
767 smb_panic_fn("out of memory in centry_expand");
772 push a uint64_t into a centry
774 static void centry_put_uint64_t(struct cache_entry
*centry
, uint64_t v
)
776 centry_expand(centry
, 8);
777 SBVAL(centry
->data
, centry
->ofs
, v
);
782 push a uint32 into a centry
784 static void centry_put_uint32(struct cache_entry
*centry
, uint32 v
)
786 centry_expand(centry
, 4);
787 SIVAL(centry
->data
, centry
->ofs
, v
);
792 push a uint16 into a centry
794 static void centry_put_uint16(struct cache_entry
*centry
, uint16 v
)
796 centry_expand(centry
, 2);
797 SSVAL(centry
->data
, centry
->ofs
, v
);
802 push a uint8 into a centry
804 static void centry_put_uint8(struct cache_entry
*centry
, uint8 v
)
806 centry_expand(centry
, 1);
807 SCVAL(centry
->data
, centry
->ofs
, v
);
812 push a string into a centry
814 static void centry_put_string(struct cache_entry
*centry
, const char *s
)
819 /* null strings are marked as len 0xFFFF */
820 centry_put_uint8(centry
, 0xFF);
825 /* can't handle more than 254 char strings. Truncating is probably best */
827 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len
));
830 centry_put_uint8(centry
, len
);
831 centry_expand(centry
, len
);
832 memcpy(centry
->data
+ centry
->ofs
, s
, len
);
837 push a 16 byte hash into a centry - treat as 16 byte string.
839 static void centry_put_hash16(struct cache_entry
*centry
, const uint8 val
[16])
841 centry_put_uint8(centry
, 16);
842 centry_expand(centry
, 16);
843 memcpy(centry
->data
+ centry
->ofs
, val
, 16);
847 static void centry_put_sid(struct cache_entry
*centry
, const struct dom_sid
*sid
)
850 centry_put_string(centry
, sid_to_fstring(sid_string
, sid
));
855 put NTSTATUS into a centry
857 static void centry_put_ntstatus(struct cache_entry
*centry
, NTSTATUS status
)
859 uint32 status_value
= NT_STATUS_V(status
);
860 centry_put_uint32(centry
, status_value
);
865 push a NTTIME into a centry
867 static void centry_put_nttime(struct cache_entry
*centry
, NTTIME nt
)
869 centry_expand(centry
, 8);
870 SIVAL(centry
->data
, centry
->ofs
, nt
& 0xFFFFFFFF);
872 SIVAL(centry
->data
, centry
->ofs
, nt
>> 32);
877 push a time_t into a centry - use a 64 bit size.
878 NTTIME here is being used as a convenient 64-bit size.
880 static void centry_put_time(struct cache_entry
*centry
, time_t t
)
882 NTTIME nt
= (NTTIME
)t
;
883 centry_put_nttime(centry
, nt
);
887 start a centry for output. When finished, call centry_end()
889 static struct cache_entry
*centry_start(struct winbindd_domain
*domain
,
892 struct cache_entry
*centry
;
897 centry
= SMB_XMALLOC_P(struct cache_entry
);
899 centry
->len
= 8192; /* reasonable default */
900 centry
->data
= SMB_XMALLOC_ARRAY(uint8
, centry
->len
);
902 centry
->sequence_number
= domain
->sequence_number
;
903 centry
->timeout
= lp_winbind_cache_time() + time(NULL
);
904 centry_put_ntstatus(centry
, status
);
905 centry_put_uint32(centry
, centry
->sequence_number
);
906 centry_put_uint64_t(centry
, centry
->timeout
);
911 finish a centry and write it to the tdb
913 static void centry_end(struct cache_entry
*centry
, const char *format
, ...) PRINTF_ATTRIBUTE(2,3);
914 static void centry_end(struct cache_entry
*centry
, const char *format
, ...)
920 if (!winbindd_use_cache()) {
924 va_start(ap
, format
);
925 smb_xvasprintf(&kstr
, format
, ap
);
928 key
= string_tdb_data(kstr
);
929 data
.dptr
= centry
->data
;
930 data
.dsize
= centry
->ofs
;
932 tdb_store(wcache
->tdb
, key
, data
, TDB_REPLACE
);
936 static void wcache_save_name_to_sid(struct winbindd_domain
*domain
,
937 NTSTATUS status
, const char *domain_name
,
938 const char *name
, const struct dom_sid
*sid
,
939 enum lsa_SidType type
)
941 struct cache_entry
*centry
;
944 centry
= centry_start(domain
, status
);
948 if ((domain_name
== NULL
) || (domain_name
[0] == '\0')) {
949 struct winbindd_domain
*mydomain
=
950 find_domain_from_sid_noinit(sid
);
951 if (mydomain
!= NULL
) {
952 domain_name
= mydomain
->name
;
956 centry_put_uint32(centry
, type
);
957 centry_put_sid(centry
, sid
);
958 fstrcpy(uname
, name
);
959 (void)strupper_m(uname
);
960 centry_end(centry
, "NS/%s/%s", domain_name
, uname
);
961 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name
,
962 uname
, sid_string_dbg(sid
), nt_errstr(status
)));
966 static void wcache_save_sid_to_name(struct winbindd_domain
*domain
, NTSTATUS status
,
967 const struct dom_sid
*sid
, const char *domain_name
, const char *name
, enum lsa_SidType type
)
969 struct cache_entry
*centry
;
972 centry
= centry_start(domain
, status
);
976 if ((domain_name
== NULL
) || (domain_name
[0] == '\0')) {
977 struct winbindd_domain
*mydomain
=
978 find_domain_from_sid_noinit(sid
);
979 if (mydomain
!= NULL
) {
980 domain_name
= mydomain
->name
;
984 if (NT_STATUS_IS_OK(status
)) {
985 centry_put_uint32(centry
, type
);
986 centry_put_string(centry
, domain_name
);
987 centry_put_string(centry
, name
);
990 centry_end(centry
, "SN/%s", sid_to_fstring(sid_string
, sid
));
991 DEBUG(10,("wcache_save_sid_to_name: %s -> %s\\%s (%s)\n", sid_string
,
992 domain_name
, name
, nt_errstr(status
)));
997 static void wcache_save_user(struct winbindd_domain
*domain
, NTSTATUS status
,
998 struct wbint_userinfo
*info
)
1000 struct cache_entry
*centry
;
1003 if (is_null_sid(&info
->user_sid
)) {
1007 centry
= centry_start(domain
, status
);
1010 centry_put_string(centry
, info
->acct_name
);
1011 centry_put_string(centry
, info
->full_name
);
1012 centry_put_string(centry
, info
->homedir
);
1013 centry_put_string(centry
, info
->shell
);
1014 centry_put_uint32(centry
, info
->primary_gid
);
1015 centry_put_sid(centry
, &info
->user_sid
);
1016 centry_put_sid(centry
, &info
->group_sid
);
1017 centry_end(centry
, "U/%s", sid_to_fstring(sid_string
,
1019 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string
, info
->acct_name
));
1020 centry_free(centry
);
1023 static void wcache_save_lockout_policy(struct winbindd_domain
*domain
,
1025 struct samr_DomInfo12
*lockout_policy
)
1027 struct cache_entry
*centry
;
1029 centry
= centry_start(domain
, status
);
1033 centry_put_nttime(centry
, lockout_policy
->lockout_duration
);
1034 centry_put_nttime(centry
, lockout_policy
->lockout_window
);
1035 centry_put_uint16(centry
, lockout_policy
->lockout_threshold
);
1037 centry_end(centry
, "LOC_POL/%s", domain
->name
);
1039 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain
->name
));
1041 centry_free(centry
);
1046 static void wcache_save_password_policy(struct winbindd_domain
*domain
,
1048 struct samr_DomInfo1
*policy
)
1050 struct cache_entry
*centry
;
1052 centry
= centry_start(domain
, status
);
1056 centry_put_uint16(centry
, policy
->min_password_length
);
1057 centry_put_uint16(centry
, policy
->password_history_length
);
1058 centry_put_uint32(centry
, policy
->password_properties
);
1059 centry_put_nttime(centry
, policy
->max_password_age
);
1060 centry_put_nttime(centry
, policy
->min_password_age
);
1062 centry_end(centry
, "PWD_POL/%s", domain
->name
);
1064 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
1066 centry_free(centry
);
1069 /***************************************************************************
1070 ***************************************************************************/
1072 static void wcache_save_username_alias(struct winbindd_domain
*domain
,
1074 const char *name
, const char *alias
)
1076 struct cache_entry
*centry
;
1079 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1082 centry_put_string( centry
, alias
);
1084 fstrcpy(uname
, name
);
1085 (void)strupper_m(uname
);
1086 centry_end(centry
, "NSS/NA/%s", uname
);
1088 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name
, alias
));
1090 centry_free(centry
);
1093 static void wcache_save_alias_username(struct winbindd_domain
*domain
,
1095 const char *alias
, const char *name
)
1097 struct cache_entry
*centry
;
1100 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1103 centry_put_string( centry
, name
);
1105 fstrcpy(uname
, alias
);
1106 (void)strupper_m(uname
);
1107 centry_end(centry
, "NSS/AN/%s", uname
);
1109 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias
, name
));
1111 centry_free(centry
);
1114 /***************************************************************************
1115 ***************************************************************************/
1117 NTSTATUS
resolve_username_to_alias( TALLOC_CTX
*mem_ctx
,
1118 struct winbindd_domain
*domain
,
1119 const char *name
, char **alias
)
1121 struct winbind_cache
*cache
= get_cache(domain
);
1122 struct cache_entry
*centry
= NULL
;
1126 if ( domain
->internal
)
1127 return NT_STATUS_NOT_SUPPORTED
;
1132 upper_name
= talloc_strdup(mem_ctx
, name
);
1133 if (upper_name
== NULL
) {
1134 return NT_STATUS_NO_MEMORY
;
1136 if (!strupper_m(upper_name
)) {
1137 talloc_free(upper_name
);
1138 return NT_STATUS_INVALID_PARAMETER
;
1141 centry
= wcache_fetch(cache
, domain
, "NSS/NA/%s", upper_name
);
1143 talloc_free(upper_name
);
1148 status
= centry
->status
;
1150 if (!NT_STATUS_IS_OK(status
)) {
1151 centry_free(centry
);
1155 *alias
= centry_string( centry
, mem_ctx
);
1157 centry_free(centry
);
1159 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1160 name
, *alias
? *alias
: "(none)"));
1162 return (*alias
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1166 /* If its not in cache and we are offline, then fail */
1168 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1169 DEBUG(8,("resolve_username_to_alias: rejecting query "
1170 "in offline mode\n"));
1171 return NT_STATUS_NOT_FOUND
;
1174 status
= nss_map_to_alias( mem_ctx
, domain
->name
, name
, alias
);
1176 if ( NT_STATUS_IS_OK( status
) ) {
1177 wcache_save_username_alias(domain
, status
, name
, *alias
);
1180 if ( NT_STATUS_EQUAL( status
, NT_STATUS_NONE_MAPPED
) ) {
1181 wcache_save_username_alias(domain
, status
, name
, "(NULL)");
1184 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1185 nt_errstr(status
)));
1187 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1188 set_domain_offline( domain
);
1194 /***************************************************************************
1195 ***************************************************************************/
1197 NTSTATUS
resolve_alias_to_username( TALLOC_CTX
*mem_ctx
,
1198 struct winbindd_domain
*domain
,
1199 const char *alias
, char **name
)
1201 struct winbind_cache
*cache
= get_cache(domain
);
1202 struct cache_entry
*centry
= NULL
;
1206 if ( domain
->internal
)
1207 return NT_STATUS_NOT_SUPPORTED
;
1212 upper_name
= talloc_strdup(mem_ctx
, alias
);
1213 if (upper_name
== NULL
) {
1214 return NT_STATUS_NO_MEMORY
;
1216 if (!strupper_m(upper_name
)) {
1217 talloc_free(upper_name
);
1218 return NT_STATUS_INVALID_PARAMETER
;
1221 centry
= wcache_fetch(cache
, domain
, "NSS/AN/%s", upper_name
);
1223 talloc_free(upper_name
);
1228 status
= centry
->status
;
1230 if (!NT_STATUS_IS_OK(status
)) {
1231 centry_free(centry
);
1235 *name
= centry_string( centry
, mem_ctx
);
1237 centry_free(centry
);
1239 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1240 alias
, *name
? *name
: "(none)"));
1242 return (*name
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1246 /* If its not in cache and we are offline, then fail */
1248 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1249 DEBUG(8,("resolve_alias_to_username: rejecting query "
1250 "in offline mode\n"));
1251 return NT_STATUS_NOT_FOUND
;
1254 /* an alias cannot contain a domain prefix or '@' */
1256 if (strchr(alias
, '\\') || strchr(alias
, '@')) {
1257 DEBUG(10,("resolve_alias_to_username: skipping fully "
1258 "qualified name %s\n", alias
));
1259 return NT_STATUS_OBJECT_NAME_INVALID
;
1262 status
= nss_map_from_alias( mem_ctx
, domain
->name
, alias
, name
);
1264 if ( NT_STATUS_IS_OK( status
) ) {
1265 wcache_save_alias_username( domain
, status
, alias
, *name
);
1268 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1269 wcache_save_alias_username(domain
, status
, alias
, "(NULL)");
1272 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1273 nt_errstr(status
)));
1275 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1276 set_domain_offline( domain
);
1282 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
1284 struct winbind_cache
*cache
= get_cache(domain
);
1286 fstring key_str
, tmp
;
1290 return NT_STATUS_INTERNAL_DB_ERROR
;
1293 if (is_null_sid(sid
)) {
1294 return NT_STATUS_INVALID_SID
;
1297 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1298 return NT_STATUS_INVALID_SID
;
1301 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
1303 data
= tdb_fetch_compat(cache
->tdb
, string_tdb_data(key_str
));
1305 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1308 SAFE_FREE(data
.dptr
);
1309 return NT_STATUS_OK
;
1312 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1313 as new salted ones. */
1315 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
1316 TALLOC_CTX
*mem_ctx
,
1317 const struct dom_sid
*sid
,
1318 const uint8
**cached_nt_pass
,
1319 const uint8
**cached_salt
)
1321 struct winbind_cache
*cache
= get_cache(domain
);
1322 struct cache_entry
*centry
= NULL
;
1328 return NT_STATUS_INTERNAL_DB_ERROR
;
1331 if (is_null_sid(sid
)) {
1332 return NT_STATUS_INVALID_SID
;
1335 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1336 return NT_STATUS_INVALID_SID
;
1339 /* Try and get a salted cred first. If we can't
1340 fall back to an unsalted cred. */
1342 centry
= wcache_fetch(cache
, domain
, "CRED/%s",
1343 sid_to_fstring(tmp
, sid
));
1345 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1346 sid_string_dbg(sid
)));
1347 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1351 * We don't use the time element at this moment,
1352 * but we have to consume it, so that we don't
1353 * neet to change the disk format of the cache.
1355 (void)centry_time(centry
);
1357 /* In the salted case this isn't actually the nt_hash itself,
1358 but the MD5 of the salt + nt_hash. Let the caller
1359 sort this out. It can tell as we only return the cached_salt
1360 if we are returning a salted cred. */
1362 *cached_nt_pass
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1363 if (*cached_nt_pass
== NULL
) {
1366 sid_to_fstring(sidstr
, sid
);
1368 /* Bad (old) cred cache. Delete and pretend we
1370 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1372 wcache_delete("CRED/%s", sidstr
);
1373 centry_free(centry
);
1374 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1377 /* We only have 17 bytes more data in the salted cred case. */
1378 if (centry
->len
- centry
->ofs
== 17) {
1379 *cached_salt
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1381 *cached_salt
= NULL
;
1384 dump_data_pw("cached_nt_pass", *cached_nt_pass
, NT_HASH_LEN
);
1386 dump_data_pw("cached_salt", *cached_salt
, NT_HASH_LEN
);
1389 status
= centry
->status
;
1391 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1392 sid_string_dbg(sid
), nt_errstr(status
) ));
1394 centry_free(centry
);
1398 /* Store creds for a SID - only writes out new salted ones. */
1400 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1401 const struct dom_sid
*sid
,
1402 const uint8 nt_pass
[NT_HASH_LEN
])
1404 struct cache_entry
*centry
;
1407 uint8 cred_salt
[NT_HASH_LEN
];
1408 uint8 salted_hash
[NT_HASH_LEN
];
1410 if (is_null_sid(sid
)) {
1411 return NT_STATUS_INVALID_SID
;
1414 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1415 return NT_STATUS_INVALID_SID
;
1418 centry
= centry_start(domain
, NT_STATUS_OK
);
1420 return NT_STATUS_INTERNAL_DB_ERROR
;
1423 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1425 centry_put_time(centry
, time(NULL
));
1427 /* Create a salt and then salt the hash. */
1428 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1429 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1431 centry_put_hash16(centry
, salted_hash
);
1432 centry_put_hash16(centry
, cred_salt
);
1433 centry_end(centry
, "CRED/%s", sid_to_fstring(sid_string
, sid
));
1435 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1437 centry_free(centry
);
1439 return NT_STATUS_OK
;
1443 /* Query display info. This is the basic user list fn */
1444 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
1445 TALLOC_CTX
*mem_ctx
,
1446 uint32
*num_entries
,
1447 struct wbint_userinfo
**info
)
1449 struct winbind_cache
*cache
= get_cache(domain
);
1450 struct cache_entry
*centry
= NULL
;
1452 unsigned int i
, retry
;
1453 bool old_status
= domain
->online
;
1458 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1463 *num_entries
= centry_uint32(centry
);
1465 if (*num_entries
== 0)
1468 (*info
) = talloc_array(mem_ctx
, struct wbint_userinfo
, *num_entries
);
1470 smb_panic_fn("query_user_list out of memory");
1472 for (i
=0; i
<(*num_entries
); i
++) {
1473 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
1474 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
1475 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
1476 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
1477 centry_sid(centry
, &(*info
)[i
].user_sid
);
1478 centry_sid(centry
, &(*info
)[i
].group_sid
);
1482 status
= centry
->status
;
1484 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1485 domain
->name
, nt_errstr(status
) ));
1487 centry_free(centry
);
1494 /* Return status value returned by seq number check */
1496 if (!NT_STATUS_IS_OK(domain
->last_status
))
1497 return domain
->last_status
;
1499 /* Put the query_user_list() in a retry loop. There appears to be
1500 * some bug either with Windows 2000 or Samba's handling of large
1501 * rpc replies. This manifests itself as sudden disconnection
1502 * at a random point in the enumeration of a large (60k) user list.
1503 * The retry loop simply tries the operation again. )-: It's not
1504 * pretty but an acceptable workaround until we work out what the
1505 * real problem is. */
1510 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1513 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
1514 if (!NT_STATUS_IS_OK(status
)) {
1515 DEBUG(3, ("query_user_list: returned 0x%08x, "
1516 "retrying\n", NT_STATUS_V(status
)));
1518 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1519 DEBUG(3, ("query_user_list: flushing "
1520 "connection cache\n"));
1521 invalidate_cm_connection(&domain
->conn
);
1523 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1524 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1525 if (!domain
->internal
&& old_status
) {
1526 set_domain_offline(domain
);
1528 /* store partial response. */
1529 if (*num_entries
> 0) {
1531 * humm, what about the status used for cache?
1532 * Should it be NT_STATUS_OK?
1537 * domain is offline now, and there is no user entries,
1538 * try to fetch from cache again.
1540 if (cache
->tdb
&& !domain
->online
&& !domain
->internal
&& old_status
) {
1541 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1542 /* partial response... */
1546 goto do_fetch_cache
;
1553 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1557 refresh_sequence_number(domain
, false);
1558 if (!NT_STATUS_IS_OK(status
)) {
1561 centry
= centry_start(domain
, status
);
1564 centry_put_uint32(centry
, *num_entries
);
1565 for (i
=0; i
<(*num_entries
); i
++) {
1566 centry_put_string(centry
, (*info
)[i
].acct_name
);
1567 centry_put_string(centry
, (*info
)[i
].full_name
);
1568 centry_put_string(centry
, (*info
)[i
].homedir
);
1569 centry_put_string(centry
, (*info
)[i
].shell
);
1570 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1571 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1572 if (domain
->backend
&& domain
->backend
->consistent
) {
1573 /* when the backend is consistent we can pre-prime some mappings */
1574 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1576 (*info
)[i
].acct_name
,
1577 &(*info
)[i
].user_sid
,
1579 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1580 &(*info
)[i
].user_sid
,
1582 (*info
)[i
].acct_name
,
1584 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1587 centry_end(centry
, "UL/%s", domain
->name
);
1588 centry_free(centry
);
1594 /* list all domain groups */
1595 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
1596 TALLOC_CTX
*mem_ctx
,
1597 uint32
*num_entries
,
1598 struct wb_acct_info
**info
)
1600 struct winbind_cache
*cache
= get_cache(domain
);
1601 struct cache_entry
*centry
= NULL
;
1606 old_status
= domain
->online
;
1610 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1615 *num_entries
= centry_uint32(centry
);
1617 if (*num_entries
== 0)
1620 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1622 smb_panic_fn("enum_dom_groups out of memory");
1624 for (i
=0; i
<(*num_entries
); i
++) {
1625 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1626 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1627 (*info
)[i
].rid
= centry_uint32(centry
);
1631 status
= centry
->status
;
1633 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1634 domain
->name
, nt_errstr(status
) ));
1636 centry_free(centry
);
1643 /* Return status value returned by seq number check */
1645 if (!NT_STATUS_IS_OK(domain
->last_status
))
1646 return domain
->last_status
;
1648 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1651 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1653 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1654 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1655 if (!domain
->internal
&& old_status
) {
1656 set_domain_offline(domain
);
1660 !domain
->internal
&&
1662 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1664 goto do_fetch_cache
;
1669 refresh_sequence_number(domain
, false);
1670 if (!NT_STATUS_IS_OK(status
)) {
1673 centry
= centry_start(domain
, status
);
1676 centry_put_uint32(centry
, *num_entries
);
1677 for (i
=0; i
<(*num_entries
); i
++) {
1678 centry_put_string(centry
, (*info
)[i
].acct_name
);
1679 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1680 centry_put_uint32(centry
, (*info
)[i
].rid
);
1682 centry_end(centry
, "GL/%s/domain", domain
->name
);
1683 centry_free(centry
);
1689 /* list all domain groups */
1690 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
1691 TALLOC_CTX
*mem_ctx
,
1692 uint32
*num_entries
,
1693 struct wb_acct_info
**info
)
1695 struct winbind_cache
*cache
= get_cache(domain
);
1696 struct cache_entry
*centry
= NULL
;
1701 old_status
= domain
->online
;
1705 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1710 *num_entries
= centry_uint32(centry
);
1712 if (*num_entries
== 0)
1715 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1717 smb_panic_fn("enum_dom_groups out of memory");
1719 for (i
=0; i
<(*num_entries
); i
++) {
1720 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1721 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1722 (*info
)[i
].rid
= centry_uint32(centry
);
1727 /* If we are returning cached data and the domain controller
1728 is down then we don't know whether the data is up to date
1729 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1732 if (wcache_server_down(domain
)) {
1733 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1734 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1736 status
= centry
->status
;
1738 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1739 domain
->name
, nt_errstr(status
) ));
1741 centry_free(centry
);
1748 /* Return status value returned by seq number check */
1750 if (!NT_STATUS_IS_OK(domain
->last_status
))
1751 return domain
->last_status
;
1753 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1756 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1758 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1759 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1760 if (!domain
->internal
&& old_status
) {
1761 set_domain_offline(domain
);
1764 !domain
->internal
&&
1767 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1769 goto do_fetch_cache
;
1774 refresh_sequence_number(domain
, false);
1775 if (!NT_STATUS_IS_OK(status
)) {
1778 centry
= centry_start(domain
, status
);
1781 centry_put_uint32(centry
, *num_entries
);
1782 for (i
=0; i
<(*num_entries
); i
++) {
1783 centry_put_string(centry
, (*info
)[i
].acct_name
);
1784 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1785 centry_put_uint32(centry
, (*info
)[i
].rid
);
1787 centry_end(centry
, "GL/%s/local", domain
->name
);
1788 centry_free(centry
);
1794 NTSTATUS
wcache_name_to_sid(struct winbindd_domain
*domain
,
1795 const char *domain_name
,
1797 struct dom_sid
*sid
,
1798 enum lsa_SidType
*type
)
1800 struct winbind_cache
*cache
= get_cache(domain
);
1801 struct cache_entry
*centry
;
1805 if (cache
->tdb
== NULL
) {
1806 return NT_STATUS_NOT_FOUND
;
1809 uname
= talloc_strdup_upper(talloc_tos(), name
);
1810 if (uname
== NULL
) {
1811 return NT_STATUS_NO_MEMORY
;
1814 if ((domain_name
== NULL
) || (domain_name
[0] == '\0')) {
1815 domain_name
= domain
->name
;
1818 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1820 if (centry
== NULL
) {
1821 return NT_STATUS_NOT_FOUND
;
1824 status
= centry
->status
;
1825 if (NT_STATUS_IS_OK(status
)) {
1826 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1827 centry_sid(centry
, sid
);
1830 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1831 "%s\n", domain
->name
, nt_errstr(status
) ));
1833 centry_free(centry
);
1837 /* convert a single name to a sid in a domain */
1838 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
1839 TALLOC_CTX
*mem_ctx
,
1840 const char *domain_name
,
1843 struct dom_sid
*sid
,
1844 enum lsa_SidType
*type
)
1849 old_status
= domain
->online
;
1851 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1852 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1858 /* If the seq number check indicated that there is a problem
1859 * with this DC, then return that status... except for
1860 * access_denied. This is special because the dc may be in
1861 * "restrict anonymous = 1" mode, in which case it will deny
1862 * most unauthenticated operations, but *will* allow the LSA
1863 * name-to-sid that we try as a fallback. */
1865 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1866 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1867 return domain
->last_status
;
1869 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1872 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
,
1873 name
, flags
, sid
, type
);
1875 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1876 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1877 if (!domain
->internal
&& old_status
) {
1878 set_domain_offline(domain
);
1880 if (!domain
->internal
&&
1883 NTSTATUS cache_status
;
1884 cache_status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1885 return cache_status
;
1889 refresh_sequence_number(domain
, false);
1891 if (domain
->online
&&
1892 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1893 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1895 /* Only save the reverse mapping if this was not a UPN */
1896 if (!strchr(name
, '@')) {
1897 if (!strupper_m(discard_const_p(char, domain_name
))) {
1898 return NT_STATUS_INVALID_PARAMETER
;
1900 (void)strlower_m(discard_const_p(char, name
));
1901 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1908 NTSTATUS
wcache_sid_to_name(struct winbindd_domain
*domain
,
1909 const struct dom_sid
*sid
,
1910 TALLOC_CTX
*mem_ctx
,
1913 enum lsa_SidType
*type
)
1915 struct winbind_cache
*cache
= get_cache(domain
);
1916 struct cache_entry
*centry
;
1920 if (cache
->tdb
== NULL
) {
1921 return NT_STATUS_NOT_FOUND
;
1924 sid_string
= sid_string_tos(sid
);
1925 if (sid_string
== NULL
) {
1926 return NT_STATUS_NO_MEMORY
;
1929 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_string
);
1930 TALLOC_FREE(sid_string
);
1931 if (centry
== NULL
) {
1932 return NT_STATUS_NOT_FOUND
;
1935 if (NT_STATUS_IS_OK(centry
->status
)) {
1936 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1937 *domain_name
= centry_string(centry
, mem_ctx
);
1938 *name
= centry_string(centry
, mem_ctx
);
1941 status
= centry
->status
;
1942 centry_free(centry
);
1944 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1945 "%s\n", domain
->name
, nt_errstr(status
) ));
1950 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1952 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1953 TALLOC_CTX
*mem_ctx
,
1954 const struct dom_sid
*sid
,
1957 enum lsa_SidType
*type
)
1962 old_status
= domain
->online
;
1963 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
1965 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1970 *domain_name
= NULL
;
1972 /* If the seq number check indicated that there is a problem
1973 * with this DC, then return that status... except for
1974 * access_denied. This is special because the dc may be in
1975 * "restrict anonymous = 1" mode, in which case it will deny
1976 * most unauthenticated operations, but *will* allow the LSA
1977 * sid-to-name that we try as a fallback. */
1979 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1980 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1981 return domain
->last_status
;
1983 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1986 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1988 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1989 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1990 if (!domain
->internal
&& old_status
) {
1991 set_domain_offline(domain
);
1993 if (!domain
->internal
&&
1996 NTSTATUS cache_status
;
1997 cache_status
= wcache_sid_to_name(domain
, sid
, mem_ctx
,
1998 domain_name
, name
, type
);
1999 return cache_status
;
2003 refresh_sequence_number(domain
, false);
2004 if (!NT_STATUS_IS_OK(status
)) {
2007 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
2009 /* We can't save the name to sid mapping here, as with sid history a
2010 * later name2sid would give the wrong sid. */
2015 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
2016 TALLOC_CTX
*mem_ctx
,
2017 const struct dom_sid
*domain_sid
,
2022 enum lsa_SidType
**types
)
2024 struct winbind_cache
*cache
= get_cache(domain
);
2026 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
2031 old_status
= domain
->online
;
2032 *domain_name
= NULL
;
2040 if (num_rids
== 0) {
2041 return NT_STATUS_OK
;
2044 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2045 *types
= talloc_array(mem_ctx
, enum lsa_SidType
, num_rids
);
2047 if ((*names
== NULL
) || (*types
== NULL
)) {
2048 result
= NT_STATUS_NO_MEMORY
;
2052 have_mapped
= have_unmapped
= false;
2054 for (i
=0; i
<num_rids
; i
++) {
2056 struct cache_entry
*centry
;
2059 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2060 result
= NT_STATUS_INTERNAL_ERROR
;
2064 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2065 sid_to_fstring(tmp
, &sid
));
2070 (*types
)[i
] = SID_NAME_UNKNOWN
;
2071 (*names
)[i
] = talloc_strdup(*names
, "");
2073 if (NT_STATUS_IS_OK(centry
->status
)) {
2076 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2078 dom
= centry_string(centry
, mem_ctx
);
2079 if (*domain_name
== NULL
) {
2085 (*names
)[i
] = centry_string(centry
, *names
);
2087 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)
2088 || NT_STATUS_EQUAL(centry
->status
, STATUS_SOME_UNMAPPED
)) {
2089 have_unmapped
= true;
2092 /* something's definitely wrong */
2093 result
= centry
->status
;
2094 centry_free(centry
);
2098 centry_free(centry
);
2102 return NT_STATUS_NONE_MAPPED
;
2104 if (!have_unmapped
) {
2105 return NT_STATUS_OK
;
2107 return STATUS_SOME_UNMAPPED
;
2111 TALLOC_FREE(*names
);
2112 TALLOC_FREE(*types
);
2114 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
2115 rids
, num_rids
, domain_name
,
2118 if (NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
2119 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2120 if (!domain
->internal
&& old_status
) {
2121 set_domain_offline(domain
);
2124 !domain
->internal
&&
2127 have_mapped
= have_unmapped
= false;
2129 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2130 if (*names
!= NULL
) {
2131 result
= NT_STATUS_NO_MEMORY
;
2135 *types
= talloc_array(mem_ctx
, enum lsa_SidType
,
2137 if (*types
!= NULL
) {
2138 result
= NT_STATUS_NO_MEMORY
;
2142 for (i
=0; i
<num_rids
; i
++) {
2144 struct cache_entry
*centry
;
2147 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2148 result
= NT_STATUS_INTERNAL_ERROR
;
2152 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2153 sid_to_fstring(tmp
, &sid
));
2155 (*types
)[i
] = SID_NAME_UNKNOWN
;
2156 (*names
)[i
] = talloc_strdup(*names
, "");
2160 (*types
)[i
] = SID_NAME_UNKNOWN
;
2161 (*names
)[i
] = talloc_strdup(*names
, "");
2163 if (NT_STATUS_IS_OK(centry
->status
)) {
2166 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2168 dom
= centry_string(centry
, mem_ctx
);
2169 if (*domain_name
== NULL
) {
2175 (*names
)[i
] = centry_string(centry
, *names
);
2177 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)) {
2178 have_unmapped
= true;
2181 /* something's definitely wrong */
2182 result
= centry
->status
;
2183 centry_free(centry
);
2187 centry_free(centry
);
2191 return NT_STATUS_NONE_MAPPED
;
2193 if (!have_unmapped
) {
2194 return NT_STATUS_OK
;
2196 return STATUS_SOME_UNMAPPED
;
2200 None of the queried rids has been found so save all negative entries
2202 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
2203 for (i
= 0; i
< num_rids
; i
++) {
2205 const char *name
= "";
2206 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
2207 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
2209 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2210 return NT_STATUS_INTERNAL_ERROR
;
2213 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2221 Some or all of the queried rids have been found.
2223 if (!NT_STATUS_IS_OK(result
) &&
2224 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
2228 refresh_sequence_number(domain
, false);
2230 for (i
=0; i
<num_rids
; i
++) {
2234 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2235 result
= NT_STATUS_INTERNAL_ERROR
;
2239 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
2240 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
2242 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2243 (*names
)[i
], (*types
)[i
]);
2249 TALLOC_FREE(*names
);
2250 TALLOC_FREE(*types
);
2254 NTSTATUS
wcache_query_user(struct winbindd_domain
*domain
,
2255 TALLOC_CTX
*mem_ctx
,
2256 const struct dom_sid
*user_sid
,
2257 struct wbint_userinfo
*info
)
2259 struct winbind_cache
*cache
= get_cache(domain
);
2260 struct cache_entry
*centry
= NULL
;
2264 if (cache
->tdb
== NULL
) {
2265 return NT_STATUS_NOT_FOUND
;
2268 sid_string
= sid_string_tos(user_sid
);
2269 if (sid_string
== NULL
) {
2270 return NT_STATUS_NO_MEMORY
;
2273 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string
);
2274 TALLOC_FREE(sid_string
);
2275 if (centry
== NULL
) {
2276 return NT_STATUS_NOT_FOUND
;
2280 * If we have an access denied cache entry and a cached info3
2281 * in the samlogon cache then do a query. This will force the
2282 * rpc back end to return the info3 data.
2285 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
) &&
2286 netsamlogon_cache_have(user_sid
)) {
2287 DEBUG(10, ("query_user: cached access denied and have cached "
2289 domain
->last_status
= NT_STATUS_OK
;
2290 centry_free(centry
);
2291 return NT_STATUS_NOT_FOUND
;
2294 /* if status is not ok then this is a negative hit
2295 and the rest of the data doesn't matter */
2296 status
= centry
->status
;
2297 if (NT_STATUS_IS_OK(status
)) {
2298 info
->acct_name
= centry_string(centry
, mem_ctx
);
2299 info
->full_name
= centry_string(centry
, mem_ctx
);
2300 info
->homedir
= centry_string(centry
, mem_ctx
);
2301 info
->shell
= centry_string(centry
, mem_ctx
);
2302 info
->primary_gid
= centry_uint32(centry
);
2303 centry_sid(centry
, &info
->user_sid
);
2304 centry_sid(centry
, &info
->group_sid
);
2307 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2308 "%s\n", domain
->name
, nt_errstr(status
) ));
2310 centry_free(centry
);
2314 /* Lookup user information from a rid */
2315 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
2316 TALLOC_CTX
*mem_ctx
,
2317 const struct dom_sid
*user_sid
,
2318 struct wbint_userinfo
*info
)
2323 old_status
= domain
->online
;
2324 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2325 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2331 /* Return status value returned by seq number check */
2333 if (!NT_STATUS_IS_OK(domain
->last_status
))
2334 return domain
->last_status
;
2336 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2339 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
2341 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2342 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2343 if (!domain
->internal
&& old_status
) {
2344 set_domain_offline(domain
);
2346 if (!domain
->internal
&&
2349 NTSTATUS cache_status
;
2350 cache_status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2351 return cache_status
;
2355 refresh_sequence_number(domain
, false);
2356 if (!NT_STATUS_IS_OK(status
)) {
2359 wcache_save_user(domain
, status
, info
);
2364 NTSTATUS
wcache_lookup_usergroups(struct winbindd_domain
*domain
,
2365 TALLOC_CTX
*mem_ctx
,
2366 const struct dom_sid
*user_sid
,
2367 uint32_t *pnum_sids
,
2368 struct dom_sid
**psids
)
2370 struct winbind_cache
*cache
= get_cache(domain
);
2371 struct cache_entry
*centry
= NULL
;
2373 uint32_t i
, num_sids
;
2374 struct dom_sid
*sids
;
2377 if (cache
->tdb
== NULL
) {
2378 return NT_STATUS_NOT_FOUND
;
2381 centry
= wcache_fetch(cache
, domain
, "UG/%s",
2382 sid_to_fstring(sid_string
, user_sid
));
2383 if (centry
== NULL
) {
2384 return NT_STATUS_NOT_FOUND
;
2387 /* If we have an access denied cache entry and a cached info3 in the
2388 samlogon cache then do a query. This will force the rpc back end
2389 to return the info3 data. */
2391 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)
2392 && netsamlogon_cache_have(user_sid
)) {
2393 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2395 domain
->last_status
= NT_STATUS_OK
;
2396 centry_free(centry
);
2397 return NT_STATUS_NOT_FOUND
;
2400 num_sids
= centry_uint32(centry
);
2401 sids
= talloc_array(mem_ctx
, struct dom_sid
, num_sids
);
2403 centry_free(centry
);
2404 return NT_STATUS_NO_MEMORY
;
2407 for (i
=0; i
<num_sids
; i
++) {
2408 centry_sid(centry
, &sids
[i
]);
2411 status
= centry
->status
;
2413 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2414 "status: %s\n", domain
->name
, nt_errstr(status
)));
2416 centry_free(centry
);
2418 *pnum_sids
= num_sids
;
2423 /* Lookup groups a user is a member of. */
2424 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
2425 TALLOC_CTX
*mem_ctx
,
2426 const struct dom_sid
*user_sid
,
2427 uint32
*num_groups
, struct dom_sid
**user_gids
)
2429 struct cache_entry
*centry
= NULL
;
2435 old_status
= domain
->online
;
2436 status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2437 num_groups
, user_gids
);
2438 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2443 (*user_gids
) = NULL
;
2445 /* Return status value returned by seq number check */
2447 if (!NT_STATUS_IS_OK(domain
->last_status
))
2448 return domain
->last_status
;
2450 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2453 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
2455 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2456 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2457 if (!domain
->internal
&& old_status
) {
2458 set_domain_offline(domain
);
2460 if (!domain
->internal
&&
2463 NTSTATUS cache_status
;
2464 cache_status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2465 num_groups
, user_gids
);
2466 return cache_status
;
2469 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
2473 refresh_sequence_number(domain
, false);
2474 if (!NT_STATUS_IS_OK(status
)) {
2477 centry
= centry_start(domain
, status
);
2481 centry_put_uint32(centry
, *num_groups
);
2482 for (i
=0; i
<(*num_groups
); i
++) {
2483 centry_put_sid(centry
, &(*user_gids
)[i
]);
2486 centry_end(centry
, "UG/%s", sid_to_fstring(sid_string
, user_sid
));
2487 centry_free(centry
);
2493 static char *wcache_make_sidlist(TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2494 const struct dom_sid
*sids
)
2499 sidlist
= talloc_strdup(mem_ctx
, "");
2500 if (sidlist
== NULL
) {
2503 for (i
=0; i
<num_sids
; i
++) {
2505 sidlist
= talloc_asprintf_append_buffer(
2506 sidlist
, "/%s", sid_to_fstring(tmp
, &sids
[i
]));
2507 if (sidlist
== NULL
) {
2514 NTSTATUS
wcache_lookup_useraliases(struct winbindd_domain
*domain
,
2515 TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2516 const struct dom_sid
*sids
,
2517 uint32_t *pnum_aliases
, uint32_t **paliases
)
2519 struct winbind_cache
*cache
= get_cache(domain
);
2520 struct cache_entry
*centry
= NULL
;
2521 uint32_t num_aliases
;
2527 if (cache
->tdb
== NULL
) {
2528 return NT_STATUS_NOT_FOUND
;
2531 if (num_sids
== 0) {
2534 return NT_STATUS_OK
;
2537 /* We need to cache indexed by the whole list of SIDs, the aliases
2538 * resulting might come from any of the SIDs. */
2540 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2541 if (sidlist
== NULL
) {
2542 return NT_STATUS_NO_MEMORY
;
2545 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2546 TALLOC_FREE(sidlist
);
2547 if (centry
== NULL
) {
2548 return NT_STATUS_NOT_FOUND
;
2551 num_aliases
= centry_uint32(centry
);
2552 aliases
= talloc_array(mem_ctx
, uint32_t, num_aliases
);
2553 if (aliases
== NULL
) {
2554 centry_free(centry
);
2555 return NT_STATUS_NO_MEMORY
;
2558 for (i
=0; i
<num_aliases
; i
++) {
2559 aliases
[i
] = centry_uint32(centry
);
2562 status
= centry
->status
;
2564 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2565 "status %s\n", domain
->name
, nt_errstr(status
)));
2567 centry_free(centry
);
2569 *pnum_aliases
= num_aliases
;
2570 *paliases
= aliases
;
2575 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
2576 TALLOC_CTX
*mem_ctx
,
2577 uint32 num_sids
, const struct dom_sid
*sids
,
2578 uint32
*num_aliases
, uint32
**alias_rids
)
2580 struct cache_entry
*centry
= NULL
;
2586 old_status
= domain
->online
;
2587 status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
2588 num_aliases
, alias_rids
);
2589 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2594 (*alias_rids
) = NULL
;
2596 if (!NT_STATUS_IS_OK(domain
->last_status
))
2597 return domain
->last_status
;
2599 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2600 "for domain %s\n", domain
->name
));
2602 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2603 if (sidlist
== NULL
) {
2604 return NT_STATUS_NO_MEMORY
;
2607 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2609 num_aliases
, alias_rids
);
2611 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2612 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2613 if (!domain
->internal
&& old_status
) {
2614 set_domain_offline(domain
);
2616 if (!domain
->internal
&&
2619 NTSTATUS cache_status
;
2620 cache_status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
,
2621 sids
, num_aliases
, alias_rids
);
2622 return cache_status
;
2626 refresh_sequence_number(domain
, false);
2627 if (!NT_STATUS_IS_OK(status
)) {
2630 centry
= centry_start(domain
, status
);
2633 centry_put_uint32(centry
, *num_aliases
);
2634 for (i
=0; i
<(*num_aliases
); i
++)
2635 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2636 centry_end(centry
, "UA%s", sidlist
);
2637 centry_free(centry
);
2643 NTSTATUS
wcache_lookup_groupmem(struct winbindd_domain
*domain
,
2644 TALLOC_CTX
*mem_ctx
,
2645 const struct dom_sid
*group_sid
,
2646 uint32_t *num_names
,
2647 struct dom_sid
**sid_mem
, char ***names
,
2648 uint32_t **name_types
)
2650 struct winbind_cache
*cache
= get_cache(domain
);
2651 struct cache_entry
*centry
= NULL
;
2656 if (cache
->tdb
== NULL
) {
2657 return NT_STATUS_NOT_FOUND
;
2660 sid_string
= sid_string_tos(group_sid
);
2661 if (sid_string
== NULL
) {
2662 return NT_STATUS_NO_MEMORY
;
2665 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_string
);
2666 TALLOC_FREE(sid_string
);
2667 if (centry
== NULL
) {
2668 return NT_STATUS_NOT_FOUND
;
2675 *num_names
= centry_uint32(centry
);
2676 if (*num_names
== 0) {
2677 centry_free(centry
);
2678 return NT_STATUS_OK
;
2681 *sid_mem
= talloc_array(mem_ctx
, struct dom_sid
, *num_names
);
2682 *names
= talloc_array(mem_ctx
, char *, *num_names
);
2683 *name_types
= talloc_array(mem_ctx
, uint32
, *num_names
);
2685 if ((*sid_mem
== NULL
) || (*names
== NULL
) || (*name_types
== NULL
)) {
2686 TALLOC_FREE(*sid_mem
);
2687 TALLOC_FREE(*names
);
2688 TALLOC_FREE(*name_types
);
2689 centry_free(centry
);
2690 return NT_STATUS_NO_MEMORY
;
2693 for (i
=0; i
<(*num_names
); i
++) {
2694 centry_sid(centry
, &(*sid_mem
)[i
]);
2695 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2696 (*name_types
)[i
] = centry_uint32(centry
);
2699 status
= centry
->status
;
2701 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2702 "status: %s\n", domain
->name
, nt_errstr(status
)));
2704 centry_free(centry
);
2708 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
2709 TALLOC_CTX
*mem_ctx
,
2710 const struct dom_sid
*group_sid
,
2711 enum lsa_SidType type
,
2713 struct dom_sid
**sid_mem
, char ***names
,
2714 uint32
**name_types
)
2716 struct cache_entry
*centry
= NULL
;
2722 old_status
= domain
->online
;
2723 status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2724 sid_mem
, names
, name_types
);
2725 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2732 (*name_types
) = NULL
;
2734 /* Return status value returned by seq number check */
2736 if (!NT_STATUS_IS_OK(domain
->last_status
))
2737 return domain
->last_status
;
2739 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2742 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
,
2744 sid_mem
, names
, name_types
);
2746 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2747 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2748 if (!domain
->internal
&& old_status
) {
2749 set_domain_offline(domain
);
2751 if (!domain
->internal
&&
2754 NTSTATUS cache_status
;
2755 cache_status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
,
2756 num_names
, sid_mem
, names
,
2758 return cache_status
;
2762 refresh_sequence_number(domain
, false);
2763 if (!NT_STATUS_IS_OK(status
)) {
2766 centry
= centry_start(domain
, status
);
2769 centry_put_uint32(centry
, *num_names
);
2770 for (i
=0; i
<(*num_names
); i
++) {
2771 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2772 centry_put_string(centry
, (*names
)[i
]);
2773 centry_put_uint32(centry
, (*name_types
)[i
]);
2775 centry_end(centry
, "GM/%s", sid_to_fstring(sid_string
, group_sid
));
2776 centry_free(centry
);
2782 /* find the sequence number for a domain */
2783 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
2785 refresh_sequence_number(domain
, false);
2787 *seq
= domain
->sequence_number
;
2789 return NT_STATUS_OK
;
2792 /* enumerate trusted domains
2793 * (we need to have the list of trustdoms in the cache when we go offline) -
2795 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
2796 TALLOC_CTX
*mem_ctx
,
2797 struct netr_DomainTrustList
*trusts
)
2800 struct winbind_cache
*cache
;
2801 struct winbindd_tdc_domain
*dom_list
= NULL
;
2802 size_t num_domains
= 0;
2803 bool retval
= false;
2807 old_status
= domain
->online
;
2809 trusts
->array
= NULL
;
2811 cache
= get_cache(domain
);
2812 if (!cache
|| !cache
->tdb
) {
2816 if (domain
->online
) {
2820 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2821 if (!retval
|| !num_domains
|| !dom_list
) {
2822 TALLOC_FREE(dom_list
);
2827 trusts
->array
= talloc_zero_array(mem_ctx
, struct netr_DomainTrust
, num_domains
);
2828 if (!trusts
->array
) {
2829 TALLOC_FREE(dom_list
);
2830 return NT_STATUS_NO_MEMORY
;
2833 for (i
= 0; i
< num_domains
; i
++) {
2834 struct netr_DomainTrust
*trust
;
2835 struct dom_sid
*sid
;
2836 struct winbindd_domain
*dom
;
2838 dom
= find_domain_from_name_noinit(dom_list
[i
].domain_name
);
2839 if (dom
&& dom
->internal
) {
2843 trust
= &trusts
->array
[trusts
->count
];
2844 trust
->netbios_name
= talloc_strdup(trusts
->array
, dom_list
[i
].domain_name
);
2845 trust
->dns_name
= talloc_strdup(trusts
->array
, dom_list
[i
].dns_name
);
2846 sid
= talloc(trusts
->array
, struct dom_sid
);
2847 if (!trust
->netbios_name
|| !trust
->dns_name
||
2849 TALLOC_FREE(dom_list
);
2850 TALLOC_FREE(trusts
->array
);
2851 return NT_STATUS_NO_MEMORY
;
2854 trust
->trust_flags
= dom_list
[i
].trust_flags
;
2855 trust
->trust_attributes
= dom_list
[i
].trust_attribs
;
2856 trust
->trust_type
= dom_list
[i
].trust_type
;
2857 sid_copy(sid
, &dom_list
[i
].sid
);
2862 TALLOC_FREE(dom_list
);
2863 return NT_STATUS_OK
;
2866 /* Return status value returned by seq number check */
2868 if (!NT_STATUS_IS_OK(domain
->last_status
))
2869 return domain
->last_status
;
2871 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2874 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, trusts
);
2876 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2877 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2878 if (!domain
->internal
&& old_status
) {
2879 set_domain_offline(domain
);
2881 if (!domain
->internal
&&
2884 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2885 if (retval
&& num_domains
&& dom_list
) {
2886 TALLOC_FREE(trusts
->array
);
2888 goto do_fetch_cache
;
2892 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2893 * so that the generic centry handling still applies correctly -
2896 if (!NT_STATUS_IS_ERR(status
)) {
2897 status
= NT_STATUS_OK
;
2902 /* get lockout policy */
2903 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
2904 TALLOC_CTX
*mem_ctx
,
2905 struct samr_DomInfo12
*policy
)
2907 struct winbind_cache
*cache
= get_cache(domain
);
2908 struct cache_entry
*centry
= NULL
;
2912 old_status
= domain
->online
;
2916 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2922 policy
->lockout_duration
= centry_nttime(centry
);
2923 policy
->lockout_window
= centry_nttime(centry
);
2924 policy
->lockout_threshold
= centry_uint16(centry
);
2926 status
= centry
->status
;
2928 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2929 domain
->name
, nt_errstr(status
) ));
2931 centry_free(centry
);
2935 ZERO_STRUCTP(policy
);
2937 /* Return status value returned by seq number check */
2939 if (!NT_STATUS_IS_OK(domain
->last_status
))
2940 return domain
->last_status
;
2942 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2945 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2947 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2948 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2949 if (!domain
->internal
&& old_status
) {
2950 set_domain_offline(domain
);
2953 !domain
->internal
&&
2956 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2958 goto do_fetch_cache
;
2963 refresh_sequence_number(domain
, false);
2964 if (!NT_STATUS_IS_OK(status
)) {
2967 wcache_save_lockout_policy(domain
, status
, policy
);
2972 /* get password policy */
2973 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
2974 TALLOC_CTX
*mem_ctx
,
2975 struct samr_DomInfo1
*policy
)
2977 struct winbind_cache
*cache
= get_cache(domain
);
2978 struct cache_entry
*centry
= NULL
;
2982 old_status
= domain
->online
;
2986 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2992 policy
->min_password_length
= centry_uint16(centry
);
2993 policy
->password_history_length
= centry_uint16(centry
);
2994 policy
->password_properties
= centry_uint32(centry
);
2995 policy
->max_password_age
= centry_nttime(centry
);
2996 policy
->min_password_age
= centry_nttime(centry
);
2998 status
= centry
->status
;
3000 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
3001 domain
->name
, nt_errstr(status
) ));
3003 centry_free(centry
);
3007 ZERO_STRUCTP(policy
);
3009 /* Return status value returned by seq number check */
3011 if (!NT_STATUS_IS_OK(domain
->last_status
))
3012 return domain
->last_status
;
3014 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
3017 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
3019 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
3020 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
3021 if (!domain
->internal
&& old_status
) {
3022 set_domain_offline(domain
);
3025 !domain
->internal
&&
3028 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
3030 goto do_fetch_cache
;
3035 refresh_sequence_number(domain
, false);
3036 if (!NT_STATUS_IS_OK(status
)) {
3039 wcache_save_password_policy(domain
, status
, policy
);
3045 /* Invalidate cached user and group lists coherently */
3047 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3050 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
3051 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
3052 tdb_delete(the_tdb
, kbuf
);
3057 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3059 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
3060 const struct dom_sid
*sid
)
3062 fstring key_str
, sid_string
;
3063 struct winbind_cache
*cache
;
3065 /* dont clear cached U/SID and UG/SID entries when we want to logon
3068 if (lp_winbind_offline_logon()) {
3075 cache
= get_cache(domain
);
3081 /* Clear U/SID cache entry */
3082 fstr_sprintf(key_str
, "U/%s", sid_to_fstring(sid_string
, sid
));
3083 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3084 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3086 /* Clear UG/SID cache entry */
3087 fstr_sprintf(key_str
, "UG/%s", sid_to_fstring(sid_string
, sid
));
3088 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3089 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3091 /* Samba/winbindd never needs this. */
3092 netsamlogon_clear_cached_user(sid
);
3095 bool wcache_invalidate_cache(void)
3097 struct winbindd_domain
*domain
;
3099 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3100 struct winbind_cache
*cache
= get_cache(domain
);
3102 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3103 "entries for %s\n", domain
->name
));
3106 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3115 bool wcache_invalidate_cache_noinit(void)
3117 struct winbindd_domain
*domain
;
3119 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3120 struct winbind_cache
*cache
;
3122 /* Skip uninitialized domains. */
3123 if (!domain
->initialized
&& !domain
->internal
) {
3127 cache
= get_cache(domain
);
3129 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3130 "entries for %s\n", domain
->name
));
3133 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3135 * Flushing cache has nothing to with domains.
3136 * return here if we successfully flushed once.
3137 * To avoid unnecessary traversing the cache.
3148 bool init_wcache(void)
3150 if (wcache
== NULL
) {
3151 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
3152 ZERO_STRUCTP(wcache
);
3155 if (wcache
->tdb
!= NULL
)
3158 /* when working offline we must not clear the cache on restart */
3159 wcache
->tdb
= tdb_open_log(state_path("winbindd_cache.tdb"),
3160 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3161 TDB_INCOMPATIBLE_HASH
|
3162 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3163 O_RDWR
|O_CREAT
, 0600);
3165 if (wcache
->tdb
== NULL
) {
3166 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3173 /************************************************************************
3174 This is called by the parent to initialize the cache file.
3175 We don't need sophisticated locking here as we know we're the
3177 ************************************************************************/
3179 bool initialize_winbindd_cache(void)
3181 bool cache_bad
= true;
3184 if (!init_wcache()) {
3185 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3189 /* Check version number. */
3190 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
3191 vers
== WINBINDD_CACHE_VERSION
) {
3196 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3197 "and re-creating with version number %d\n",
3198 WINBINDD_CACHE_VERSION
));
3200 tdb_close(wcache
->tdb
);
3203 if (unlink(state_path("winbindd_cache.tdb")) == -1) {
3204 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3205 state_path("winbindd_cache.tdb"),
3209 if (!init_wcache()) {
3210 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3211 "init_wcache failed.\n"));
3215 /* Write the version. */
3216 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
3217 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3218 tdb_errorstr_compat(wcache
->tdb
) ));
3223 tdb_close(wcache
->tdb
);
3228 void close_winbindd_cache(void)
3234 tdb_close(wcache
->tdb
);
3239 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*sid
,
3240 char **domain_name
, char **name
,
3241 enum lsa_SidType
*type
)
3243 struct winbindd_domain
*domain
;
3246 domain
= find_lookup_domain_from_sid(sid
);
3247 if (domain
== NULL
) {
3250 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
3252 return NT_STATUS_IS_OK(status
);
3255 bool lookup_cached_name(const char *domain_name
,
3257 struct dom_sid
*sid
,
3258 enum lsa_SidType
*type
)
3260 struct winbindd_domain
*domain
;
3262 bool original_online_state
;
3264 domain
= find_lookup_domain_from_name(domain_name
);
3265 if (domain
== NULL
) {
3269 /* If we are doing a cached logon, temporarily set the domain
3270 offline so the cache won't expire the entry */
3272 original_online_state
= domain
->online
;
3273 domain
->online
= false;
3274 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
3275 domain
->online
= original_online_state
;
3277 return NT_STATUS_IS_OK(status
);
3280 void cache_name2sid(struct winbindd_domain
*domain
,
3281 const char *domain_name
, const char *name
,
3282 enum lsa_SidType type
, const struct dom_sid
*sid
)
3284 refresh_sequence_number(domain
, false);
3285 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
3290 * The original idea that this cache only contains centries has
3291 * been blurred - now other stuff gets put in here. Ensure we
3292 * ignore these things on cleanup.
3295 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
3296 TDB_DATA dbuf
, void *state
)
3298 struct cache_entry
*centry
;
3300 if (is_non_centry_key(kbuf
)) {
3304 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
3309 if (!NT_STATUS_IS_OK(centry
->status
)) {
3310 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
3311 tdb_delete(the_tdb
, kbuf
);
3314 centry_free(centry
);
3318 /* flush the cache */
3319 void wcache_flush_cache(void)
3324 tdb_close(wcache
->tdb
);
3327 if (!winbindd_use_cache()) {
3331 /* when working offline we must not clear the cache on restart */
3332 wcache
->tdb
= tdb_open_log(state_path("winbindd_cache.tdb"),
3333 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3334 TDB_INCOMPATIBLE_HASH
|
3335 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3336 O_RDWR
|O_CREAT
, 0600);
3339 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3343 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
3345 DEBUG(10,("wcache_flush_cache success\n"));
3348 /* Count cached creds */
3350 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3353 int *cred_count
= (int*)state
;
3355 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3361 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
3363 struct winbind_cache
*cache
= get_cache(domain
);
3368 return NT_STATUS_INTERNAL_DB_ERROR
;
3371 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
3373 return NT_STATUS_OK
;
3377 struct cred_list
*prev
, *next
;
3382 static struct cred_list
*wcache_cred_list
;
3384 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3387 struct cred_list
*cred
;
3389 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3391 cred
= SMB_MALLOC_P(struct cred_list
);
3393 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3399 /* save a copy of the key */
3401 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
3402 DLIST_ADD(wcache_cred_list
, cred
);
3408 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
3410 struct winbind_cache
*cache
= get_cache(domain
);
3413 struct cred_list
*cred
, *oldest
= NULL
;
3416 return NT_STATUS_INTERNAL_DB_ERROR
;
3419 /* we possibly already have an entry */
3420 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
3422 fstring key_str
, tmp
;
3424 DEBUG(11,("we already have an entry, deleting that\n"));
3426 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
3428 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3430 return NT_STATUS_OK
;
3433 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
3435 return NT_STATUS_OK
;
3436 } else if ((ret
< 0) || (wcache_cred_list
== NULL
)) {
3437 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3440 ZERO_STRUCTP(oldest
);
3442 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
3447 data
= tdb_fetch_compat(cache
->tdb
, string_tdb_data(cred
->name
));
3449 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3451 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3455 t
= IVAL(data
.dptr
, 0);
3456 SAFE_FREE(data
.dptr
);
3459 oldest
= SMB_MALLOC_P(struct cred_list
);
3460 if (oldest
== NULL
) {
3461 status
= NT_STATUS_NO_MEMORY
;
3465 fstrcpy(oldest
->name
, cred
->name
);
3466 oldest
->created
= t
;
3470 if (t
< oldest
->created
) {
3471 fstrcpy(oldest
->name
, cred
->name
);
3472 oldest
->created
= t
;
3476 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3477 status
= NT_STATUS_OK
;
3479 status
= NT_STATUS_UNSUCCESSFUL
;
3482 SAFE_FREE(wcache_cred_list
);
3488 /* Change the global online/offline state. */
3489 bool set_global_winbindd_state_offline(void)
3493 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3495 /* Only go offline if someone has created
3496 the key "WINBINDD_OFFLINE" in the cache tdb. */
3498 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3499 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3503 if (!lp_winbind_offline_logon()) {
3504 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3508 if (global_winbindd_offline_state
) {
3509 /* Already offline. */
3513 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
3515 if (!data
.dptr
|| data
.dsize
!= 4) {
3516 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3517 SAFE_FREE(data
.dptr
);
3520 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3521 global_winbindd_offline_state
= true;
3522 SAFE_FREE(data
.dptr
);
3527 void set_global_winbindd_state_online(void)
3529 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3531 if (!lp_winbind_offline_logon()) {
3532 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3536 if (!global_winbindd_offline_state
) {
3537 /* Already online. */
3540 global_winbindd_offline_state
= false;
3546 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3547 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3550 bool get_global_winbindd_state_offline(void)
3552 return global_winbindd_offline_state
;
3555 /***********************************************************************
3556 Validate functions for all possible cache tdb keys.
3557 ***********************************************************************/
3559 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3560 struct tdb_validation_status
*state
)
3562 struct cache_entry
*centry
;
3564 centry
= SMB_XMALLOC_P(struct cache_entry
);
3565 centry
->data
= (unsigned char *)smb_memdup(data
.dptr
, data
.dsize
);
3566 if (!centry
->data
) {
3570 centry
->len
= data
.dsize
;
3573 if (centry
->len
< 16) {
3574 /* huh? corrupt cache? */
3575 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3576 "(len < 16) ?\n", kstr
));
3577 centry_free(centry
);
3578 state
->bad_entry
= true;
3579 state
->success
= false;
3583 centry
->status
= NT_STATUS(centry_uint32(centry
));
3584 centry
->sequence_number
= centry_uint32(centry
);
3585 centry
->timeout
= centry_uint64_t(centry
);
3589 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3590 struct tdb_validation_status
*state
)
3592 if (dbuf
.dsize
!= 8) {
3593 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3594 keystr
, (unsigned int)dbuf
.dsize
));
3595 state
->bad_entry
= true;
3601 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3602 struct tdb_validation_status
*state
)
3604 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3609 (void)centry_uint32(centry
);
3610 if (NT_STATUS_IS_OK(centry
->status
)) {
3612 (void)centry_sid(centry
, &sid
);
3615 centry_free(centry
);
3617 if (!(state
->success
)) {
3620 DEBUG(10,("validate_ns: %s ok\n", keystr
));
3624 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3625 struct tdb_validation_status
*state
)
3627 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3632 if (NT_STATUS_IS_OK(centry
->status
)) {
3633 (void)centry_uint32(centry
);
3634 (void)centry_string(centry
, mem_ctx
);
3635 (void)centry_string(centry
, mem_ctx
);
3638 centry_free(centry
);
3640 if (!(state
->success
)) {
3643 DEBUG(10,("validate_sn: %s ok\n", keystr
));
3647 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3648 struct tdb_validation_status
*state
)
3650 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3657 (void)centry_string(centry
, mem_ctx
);
3658 (void)centry_string(centry
, mem_ctx
);
3659 (void)centry_string(centry
, mem_ctx
);
3660 (void)centry_string(centry
, mem_ctx
);
3661 (void)centry_uint32(centry
);
3662 (void)centry_sid(centry
, &sid
);
3663 (void)centry_sid(centry
, &sid
);
3665 centry_free(centry
);
3667 if (!(state
->success
)) {
3670 DEBUG(10,("validate_u: %s ok\n", keystr
));
3674 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3675 struct tdb_validation_status
*state
)
3677 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3683 (void)centry_nttime(centry
);
3684 (void)centry_nttime(centry
);
3685 (void)centry_uint16(centry
);
3687 centry_free(centry
);
3689 if (!(state
->success
)) {
3692 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3696 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3697 struct tdb_validation_status
*state
)
3699 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3705 (void)centry_uint16(centry
);
3706 (void)centry_uint16(centry
);
3707 (void)centry_uint32(centry
);
3708 (void)centry_nttime(centry
);
3709 (void)centry_nttime(centry
);
3711 centry_free(centry
);
3713 if (!(state
->success
)) {
3716 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3720 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3721 struct tdb_validation_status
*state
)
3723 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3729 (void)centry_time(centry
);
3730 (void)centry_hash16(centry
, mem_ctx
);
3732 /* We only have 17 bytes more data in the salted cred case. */
3733 if (centry
->len
- centry
->ofs
== 17) {
3734 (void)centry_hash16(centry
, mem_ctx
);
3737 centry_free(centry
);
3739 if (!(state
->success
)) {
3742 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3746 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3747 struct tdb_validation_status
*state
)
3749 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3750 int32 num_entries
, i
;
3756 num_entries
= (int32
)centry_uint32(centry
);
3758 for (i
=0; i
< num_entries
; i
++) {
3760 (void)centry_string(centry
, mem_ctx
);
3761 (void)centry_string(centry
, mem_ctx
);
3762 (void)centry_string(centry
, mem_ctx
);
3763 (void)centry_string(centry
, mem_ctx
);
3764 (void)centry_sid(centry
, &sid
);
3765 (void)centry_sid(centry
, &sid
);
3768 centry_free(centry
);
3770 if (!(state
->success
)) {
3773 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3777 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3778 struct tdb_validation_status
*state
)
3780 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3781 int32 num_entries
, i
;
3787 num_entries
= centry_uint32(centry
);
3789 for (i
=0; i
< num_entries
; i
++) {
3790 (void)centry_string(centry
, mem_ctx
);
3791 (void)centry_string(centry
, mem_ctx
);
3792 (void)centry_uint32(centry
);
3795 centry_free(centry
);
3797 if (!(state
->success
)) {
3800 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3804 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3805 struct tdb_validation_status
*state
)
3807 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3808 int32 num_groups
, i
;
3814 num_groups
= centry_uint32(centry
);
3816 for (i
=0; i
< num_groups
; i
++) {
3818 centry_sid(centry
, &sid
);
3821 centry_free(centry
);
3823 if (!(state
->success
)) {
3826 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3830 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3831 struct tdb_validation_status
*state
)
3833 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3834 int32 num_aliases
, i
;
3840 num_aliases
= centry_uint32(centry
);
3842 for (i
=0; i
< num_aliases
; i
++) {
3843 (void)centry_uint32(centry
);
3846 centry_free(centry
);
3848 if (!(state
->success
)) {
3851 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3855 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3856 struct tdb_validation_status
*state
)
3858 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3865 num_names
= centry_uint32(centry
);
3867 for (i
=0; i
< num_names
; i
++) {
3869 centry_sid(centry
, &sid
);
3870 (void)centry_string(centry
, mem_ctx
);
3871 (void)centry_uint32(centry
);
3874 centry_free(centry
);
3876 if (!(state
->success
)) {
3879 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3883 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3884 struct tdb_validation_status
*state
)
3886 /* Can't say anything about this other than must be nonzero. */
3887 if (dbuf
.dsize
== 0) {
3888 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3890 state
->bad_entry
= true;
3891 state
->success
= false;
3895 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3899 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3900 struct tdb_validation_status
*state
)
3902 /* Can't say anything about this other than must be nonzero. */
3903 if (dbuf
.dsize
== 0) {
3904 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3906 state
->bad_entry
= true;
3907 state
->success
= false;
3911 DEBUG(10,("validate_de: %s ok\n", keystr
));
3915 static int validate_pwinfo(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3916 TDB_DATA dbuf
, struct tdb_validation_status
*state
)
3918 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3924 (void)centry_string(centry
, mem_ctx
);
3925 (void)centry_string(centry
, mem_ctx
);
3926 (void)centry_string(centry
, mem_ctx
);
3927 (void)centry_uint32(centry
);
3929 centry_free(centry
);
3931 if (!(state
->success
)) {
3934 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3938 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3940 struct tdb_validation_status
*state
)
3942 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3948 (void)centry_string( centry
, mem_ctx
);
3950 centry_free(centry
);
3952 if (!(state
->success
)) {
3955 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3959 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3961 struct tdb_validation_status
*state
)
3963 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3969 (void)centry_string( centry
, mem_ctx
);
3971 centry_free(centry
);
3973 if (!(state
->success
)) {
3976 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3980 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3982 struct tdb_validation_status
*state
)
3984 if (dbuf
.dsize
== 0) {
3985 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3986 "key %s (len ==0) ?\n", keystr
));
3987 state
->bad_entry
= true;
3988 state
->success
= false;
3992 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3993 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3997 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3998 struct tdb_validation_status
*state
)
4000 if (dbuf
.dsize
!= 4) {
4001 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
4002 keystr
, (unsigned int)dbuf
.dsize
));
4003 state
->bad_entry
= true;
4004 state
->success
= false;
4007 DEBUG(10,("validate_offline: %s ok\n", keystr
));
4011 static int validate_ndr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
4012 struct tdb_validation_status
*state
)
4015 * Ignore validation for now. The proper way to do this is with a
4016 * checksum. Just pure parsing does not really catch much.
4021 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
4022 struct tdb_validation_status
*state
)
4024 if (dbuf
.dsize
!= 4) {
4025 DEBUG(0, ("validate_cache_version: Corrupt cache for "
4026 "key %s (len %u != 4) ?\n",
4027 keystr
, (unsigned int)dbuf
.dsize
));
4028 state
->bad_entry
= true;
4029 state
->success
= false;
4033 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
4037 /***********************************************************************
4038 A list of all possible cache tdb keys with associated validation
4040 ***********************************************************************/
4042 struct key_val_struct
{
4043 const char *keyname
;
4044 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
4046 {"SEQNUM/", validate_seqnum
},
4047 {"NS/", validate_ns
},
4048 {"SN/", validate_sn
},
4050 {"LOC_POL/", validate_loc_pol
},
4051 {"PWD_POL/", validate_pwd_pol
},
4052 {"CRED/", validate_cred
},
4053 {"UL/", validate_ul
},
4054 {"GL/", validate_gl
},
4055 {"UG/", validate_ug
},
4056 {"UA", validate_ua
},
4057 {"GM/", validate_gm
},
4058 {"DR/", validate_dr
},
4059 {"DE/", validate_de
},
4060 {"NSS/PWINFO/", validate_pwinfo
},
4061 {"TRUSTDOMCACHE/", validate_trustdomcache
},
4062 {"NSS/NA/", validate_nss_na
},
4063 {"NSS/AN/", validate_nss_an
},
4064 {"WINBINDD_OFFLINE", validate_offline
},
4065 {"NDR/", validate_ndr
},
4066 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
4070 /***********************************************************************
4071 Function to look at every entry in the tdb and validate it as far as
4073 ***********************************************************************/
4075 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
4078 unsigned int max_key_len
= 1024;
4079 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
4081 /* Paranoia check. */
4082 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0 ||
4083 strncmp("NDR/", (const char *)kbuf
.dptr
, 4) == 0) {
4084 max_key_len
= 1024 * 1024;
4086 if (kbuf
.dsize
> max_key_len
) {
4087 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4089 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
4093 for (i
= 0; key_val
[i
].keyname
; i
++) {
4094 size_t namelen
= strlen(key_val
[i
].keyname
);
4095 if (kbuf
.dsize
>= namelen
&& (
4096 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
4097 TALLOC_CTX
*mem_ctx
;
4101 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
4105 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
4106 keystr
[kbuf
.dsize
] = '\0';
4108 mem_ctx
= talloc_init("validate_ctx");
4114 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
4118 talloc_destroy(mem_ctx
);
4123 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4124 dump_data(0, (uint8
*)kbuf
.dptr
, kbuf
.dsize
);
4125 DEBUG(0,("data :\n"));
4126 dump_data(0, (uint8
*)dbuf
.dptr
, dbuf
.dsize
);
4127 v_state
->unknown_key
= true;
4128 v_state
->success
= false;
4129 return 1; /* terminate. */
4132 static void validate_panic(const char *const why
)
4134 DEBUG(0,("validating cache: would panic %s\n", why
));
4135 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4139 static int wbcache_update_centry_fn(TDB_CONTEXT
*tdb
,
4147 if (is_non_centry_key(key
)) {
4151 if (data
.dptr
== NULL
|| data
.dsize
== 0) {
4152 if (tdb_delete(tdb
, key
) < 0) {
4153 DEBUG(0, ("tdb_delete for [%s] failed!\n",
4159 /* add timeout to blob (uint64_t) */
4160 blob
.dsize
= data
.dsize
+ 8;
4162 blob
.dptr
= SMB_XMALLOC_ARRAY(uint8_t, blob
.dsize
);
4163 if (blob
.dptr
== NULL
) {
4166 memset(blob
.dptr
, 0, blob
.dsize
);
4168 /* copy status and seqnum */
4169 memcpy(blob
.dptr
, data
.dptr
, 8);
4172 ctimeout
= lp_winbind_cache_time() + time(NULL
);
4173 SBVAL(blob
.dptr
, 8, ctimeout
);
4176 memcpy(blob
.dptr
+ 16, data
.dptr
+ 8, data
.dsize
- 8);
4178 if (tdb_store(tdb
, key
, blob
, TDB_REPLACE
) < 0) {
4179 DEBUG(0, ("tdb_store to update [%s] failed!\n",
4181 SAFE_FREE(blob
.dptr
);
4185 SAFE_FREE(blob
.dptr
);
4189 static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT
*tdb
)
4193 DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
4195 rc
= tdb_traverse(tdb
, wbcache_update_centry_fn
, NULL
);
4203 /***********************************************************************
4204 Try and validate every entry in the winbindd cache. If we fail here,
4205 delete the cache tdb and return non-zero.
4206 ***********************************************************************/
4208 int winbindd_validate_cache(void)
4211 const char *tdb_path
= state_path("winbindd_cache.tdb");
4212 TDB_CONTEXT
*tdb
= NULL
;
4216 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4217 smb_panic_fn
= validate_panic
;
4219 tdb
= tdb_open_log(tdb_path
,
4220 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
4221 TDB_INCOMPATIBLE_HASH
|
4222 ( lp_winbind_offline_logon()
4224 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
4228 DEBUG(0, ("winbindd_validate_cache: "
4229 "error opening/initializing tdb\n"));
4233 /* Version check and upgrade code. */
4234 if (!tdb_fetch_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers_id
)) {
4235 DEBUG(10, ("Fresh database\n"));
4236 tdb_store_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
);
4237 vers_id
= WINBINDD_CACHE_VERSION
;
4240 if (vers_id
!= WINBINDD_CACHE_VERSION
) {
4241 if (vers_id
== WINBINDD_CACHE_VER1
) {
4242 ok
= wbcache_upgrade_v1_to_v2(tdb
);
4244 DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
4249 tdb_store_uint32(tdb
,
4250 WINBINDD_CACHE_VERSION_KEYSTR
,
4251 WINBINDD_CACHE_VERSION
);
4252 vers_id
= WINBINDD_CACHE_VER2
;
4258 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
4261 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4262 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
4267 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4268 smb_panic_fn
= smb_panic
;
4272 /***********************************************************************
4273 Try and validate every entry in the winbindd cache.
4274 ***********************************************************************/
4276 int winbindd_validate_cache_nobackup(void)
4279 const char *tdb_path
= state_path("winbindd_cache.tdb");
4281 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4282 smb_panic_fn
= validate_panic
;
4285 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
4286 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
4288 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
4292 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4296 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4298 smb_panic_fn
= smb_panic
;
4302 bool winbindd_cache_validate_and_initialize(void)
4304 close_winbindd_cache();
4306 if (lp_winbind_offline_logon()) {
4307 if (winbindd_validate_cache() < 0) {
4308 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4309 "could be restored.\n"));
4313 return initialize_winbindd_cache();
4316 /*********************************************************************
4317 ********************************************************************/
4319 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
4320 struct winbindd_tdc_domain
**domains
,
4321 size_t *num_domains
)
4323 struct winbindd_tdc_domain
*list
= NULL
;
4326 bool set_only
= false;
4328 /* don't allow duplicates */
4333 for ( i
=0; i
< (*num_domains
); i
++ ) {
4334 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
4335 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4346 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, 1 );
4349 list
= talloc_realloc( *domains
, *domains
,
4350 struct winbindd_tdc_domain
,
4355 ZERO_STRUCT( list
[idx
] );
4361 list
[idx
].domain_name
= talloc_strdup(list
, new_dom
->name
);
4362 if (list
[idx
].domain_name
== NULL
) {
4365 if (new_dom
->alt_name
!= NULL
) {
4366 list
[idx
].dns_name
= talloc_strdup(list
, new_dom
->alt_name
);
4367 if (list
[idx
].dns_name
== NULL
) {
4372 if ( !is_null_sid( &new_dom
->sid
) ) {
4373 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
4375 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
4378 if ( new_dom
->domain_flags
!= 0x0 )
4379 list
[idx
].trust_flags
= new_dom
->domain_flags
;
4381 if ( new_dom
->domain_type
!= 0x0 )
4382 list
[idx
].trust_type
= new_dom
->domain_type
;
4384 if ( new_dom
->domain_trust_attribs
!= 0x0 )
4385 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
4389 *num_domains
= idx
+ 1;
4395 /*********************************************************************
4396 ********************************************************************/
4398 static TDB_DATA
make_tdc_key( const char *domain_name
)
4400 char *keystr
= NULL
;
4401 TDB_DATA key
= { NULL
, 0 };
4403 if ( !domain_name
) {
4404 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4408 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
4411 key
= string_term_tdb_data(keystr
);
4416 /*********************************************************************
4417 ********************************************************************/
4419 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
4421 unsigned char **buf
)
4423 unsigned char *buffer
= NULL
;
4428 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4436 /* Store the number of array items first */
4437 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
4440 /* now pack each domain trust record */
4441 for ( i
=0; i
<num_domains
; i
++ ) {
4446 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4447 domains
[i
].domain_name
,
4448 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
4451 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
4452 domains
[i
].domain_name
,
4453 domains
[i
].dns_name
? domains
[i
].dns_name
: "",
4454 sid_to_fstring(tmp
, &domains
[i
].sid
),
4455 domains
[i
].trust_flags
,
4456 domains
[i
].trust_attribs
,
4457 domains
[i
].trust_type
);
4460 if ( buflen
< len
) {
4462 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
4463 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4477 /*********************************************************************
4478 ********************************************************************/
4480 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
4481 struct winbindd_tdc_domain
**domains
)
4483 fstring domain_name
, dns_name
, sid_string
;
4484 uint32 type
, attribs
, flags
;
4488 struct winbindd_tdc_domain
*list
= NULL
;
4490 /* get the number of domains */
4491 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
4493 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4497 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, num_domains
);
4499 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4503 for ( i
=0; i
<num_domains
; i
++ ) {
4506 this_len
= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
4514 if ( this_len
== -1 ) {
4515 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4516 TALLOC_FREE( list
);
4521 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4522 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4523 domain_name
, dns_name
, sid_string
,
4524 flags
, attribs
, type
));
4526 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
4527 list
[i
].dns_name
= NULL
;
4528 if (dns_name
[0] != '\0') {
4529 list
[i
].dns_name
= talloc_strdup(list
, dns_name
);
4531 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
4532 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4535 list
[i
].trust_flags
= flags
;
4536 list
[i
].trust_attribs
= attribs
;
4537 list
[i
].trust_type
= type
;
4545 /*********************************************************************
4546 ********************************************************************/
4548 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
4550 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4551 TDB_DATA data
= { NULL
, 0 };
4557 /* See if we were asked to delete the cache entry */
4560 ret
= tdb_delete( wcache
->tdb
, key
);
4564 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4571 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4574 SAFE_FREE( data
.dptr
);
4575 SAFE_FREE( key
.dptr
);
4577 return ( ret
== 0 );
4580 /*********************************************************************
4581 ********************************************************************/
4583 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4585 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4586 TDB_DATA data
= { NULL
, 0 };
4594 data
= tdb_fetch_compat( wcache
->tdb
, key
);
4596 SAFE_FREE( key
.dptr
);
4601 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4603 SAFE_FREE( data
.dptr
);
4611 /*********************************************************************
4612 ********************************************************************/
4614 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4616 struct winbindd_tdc_domain
*dom_list
= NULL
;
4617 size_t num_domains
= 0;
4620 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4621 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4622 domain
->name
, domain
->alt_name
,
4623 sid_string_dbg(&domain
->sid
),
4624 domain
->domain_flags
,
4625 domain
->domain_trust_attribs
,
4626 domain
->domain_type
));
4628 if ( !init_wcache() ) {
4632 /* fetch the list */
4634 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4636 /* add the new domain */
4638 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4642 /* pack the domain */
4644 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4652 TALLOC_FREE( dom_list
);
4657 static struct winbindd_tdc_domain
*wcache_tdc_dup_domain(
4658 TALLOC_CTX
*mem_ctx
, const struct winbindd_tdc_domain
*src
)
4660 struct winbindd_tdc_domain
*dst
;
4662 dst
= talloc(mem_ctx
, struct winbindd_tdc_domain
);
4666 dst
->domain_name
= talloc_strdup(dst
, src
->domain_name
);
4667 if (dst
->domain_name
== NULL
) {
4671 dst
->dns_name
= NULL
;
4672 if (src
->dns_name
!= NULL
) {
4673 dst
->dns_name
= talloc_strdup(dst
, src
->dns_name
);
4674 if (dst
->dns_name
== NULL
) {
4679 sid_copy(&dst
->sid
, &src
->sid
);
4680 dst
->trust_flags
= src
->trust_flags
;
4681 dst
->trust_type
= src
->trust_type
;
4682 dst
->trust_attribs
= src
->trust_attribs
;
4689 /*********************************************************************
4690 ********************************************************************/
4692 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4694 struct winbindd_tdc_domain
*dom_list
= NULL
;
4695 size_t num_domains
= 0;
4697 struct winbindd_tdc_domain
*d
= NULL
;
4699 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4701 if ( !init_wcache() ) {
4705 /* fetch the list */
4707 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4709 for ( i
=0; i
<num_domains
; i
++ ) {
4710 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4711 strequal(name
, dom_list
[i
].dns_name
) )
4713 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4716 d
= wcache_tdc_dup_domain(ctx
, &dom_list
[i
]);
4721 TALLOC_FREE( dom_list
);
4726 /*********************************************************************
4727 ********************************************************************/
4729 struct winbindd_tdc_domain
*
4730 wcache_tdc_fetch_domainbysid(TALLOC_CTX
*ctx
,
4731 const struct dom_sid
*sid
)
4733 struct winbindd_tdc_domain
*dom_list
= NULL
;
4734 size_t num_domains
= 0;
4736 struct winbindd_tdc_domain
*d
= NULL
;
4738 DEBUG(10,("wcache_tdc_fetch_domainbysid: Searching for domain %s\n",
4739 sid_string_dbg(sid
)));
4741 if (!init_wcache()) {
4745 /* fetch the list */
4747 wcache_tdc_fetch_list(&dom_list
, &num_domains
);
4749 for (i
= 0; i
<num_domains
; i
++) {
4750 if (dom_sid_equal(sid
, &(dom_list
[i
].sid
))) {
4751 DEBUG(10, ("wcache_tdc_fetch_domainbysid: "
4752 "Found domain %s for SID %s\n",
4753 dom_list
[i
].domain_name
,
4754 sid_string_dbg(sid
)));
4756 d
= wcache_tdc_dup_domain(ctx
, &dom_list
[i
]);
4761 TALLOC_FREE(dom_list
);
4767 /*********************************************************************
4768 ********************************************************************/
4770 void wcache_tdc_clear( void )
4772 if ( !init_wcache() )
4775 wcache_tdc_store_list( NULL
, 0 );
4781 /*********************************************************************
4782 ********************************************************************/
4784 static void wcache_save_user_pwinfo(struct winbindd_domain
*domain
,
4786 const struct dom_sid
*user_sid
,
4787 const char *homedir
,
4792 struct cache_entry
*centry
;
4795 if ( (centry
= centry_start(domain
, status
)) == NULL
)
4798 centry_put_string( centry
, homedir
);
4799 centry_put_string( centry
, shell
);
4800 centry_put_string( centry
, gecos
);
4801 centry_put_uint32( centry
, gid
);
4803 centry_end(centry
, "NSS/PWINFO/%s", sid_to_fstring(tmp
, user_sid
) );
4805 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid
) ));
4807 centry_free(centry
);
4812 NTSTATUS
nss_get_info_cached( struct winbindd_domain
*domain
,
4813 const struct dom_sid
*user_sid
,
4815 const char **homedir
, const char **shell
,
4816 const char **gecos
, gid_t
*p_gid
)
4818 struct winbind_cache
*cache
= get_cache(domain
);
4819 struct cache_entry
*centry
= NULL
;
4826 centry
= wcache_fetch(cache
, domain
, "NSS/PWINFO/%s",
4827 sid_to_fstring(tmp
, user_sid
));
4832 *homedir
= centry_string( centry
, ctx
);
4833 *shell
= centry_string( centry
, ctx
);
4834 *gecos
= centry_string( centry
, ctx
);
4835 *p_gid
= centry_uint32( centry
);
4837 centry_free(centry
);
4839 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4840 sid_string_dbg(user_sid
)));
4842 return NT_STATUS_OK
;
4846 nt_status
= nss_get_info( domain
->name
, user_sid
, ctx
,
4847 homedir
, shell
, gecos
, p_gid
);
4849 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status
)));
4851 if ( NT_STATUS_IS_OK(nt_status
) ) {
4852 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir
));
4853 DEBUGADD(10, ("\tshell = '%s'\n", *shell
));
4854 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos
));
4855 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid
));
4857 wcache_save_user_pwinfo( domain
, nt_status
, user_sid
,
4858 *homedir
, *shell
, *gecos
, *p_gid
);
4861 if ( NT_STATUS_EQUAL( nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
4862 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4864 set_domain_offline( domain
);
4872 /* the cache backend methods are exposed via this structure */
4873 struct winbindd_methods cache_methods
= {
4891 static bool wcache_ndr_key(TALLOC_CTX
*mem_ctx
, const char *domain_name
,
4892 uint32_t opnum
, const DATA_BLOB
*req
,
4898 key
= talloc_asprintf(mem_ctx
, "NDR/%s/%d/", domain_name
, (int)opnum
);
4902 keylen
= talloc_get_size(key
) - 1;
4904 key
= talloc_realloc(mem_ctx
, key
, char, keylen
+ req
->length
);
4908 memcpy(key
+ keylen
, req
->data
, req
->length
);
4910 pkey
->dptr
= (uint8_t *)key
;
4911 pkey
->dsize
= talloc_get_size(key
);
4915 static bool wcache_opnum_cacheable(uint32_t opnum
)
4918 case NDR_WBINT_PING
:
4919 case NDR_WBINT_QUERYSEQUENCENUMBER
:
4920 case NDR_WBINT_ALLOCATEUID
:
4921 case NDR_WBINT_ALLOCATEGID
:
4922 case NDR_WBINT_CHECKMACHINEACCOUNT
:
4923 case NDR_WBINT_CHANGEMACHINEACCOUNT
:
4924 case NDR_WBINT_PINGDC
:
4930 bool wcache_fetch_ndr(TALLOC_CTX
*mem_ctx
, struct winbindd_domain
*domain
,
4931 uint32_t opnum
, const DATA_BLOB
*req
, DATA_BLOB
*resp
)
4936 if (!wcache_opnum_cacheable(opnum
) ||
4937 is_my_own_sam_domain(domain
) ||
4938 is_builtin_domain(domain
)) {
4942 if (wcache
->tdb
== NULL
) {
4946 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4949 data
= tdb_fetch_compat(wcache
->tdb
, key
);
4950 TALLOC_FREE(key
.dptr
);
4952 if (data
.dptr
== NULL
) {
4955 if (data
.dsize
< 12) {
4959 if (!is_domain_offline(domain
)) {
4960 uint32_t entry_seqnum
, dom_seqnum
, last_check
;
4961 uint64_t entry_timeout
;
4963 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
,
4967 entry_seqnum
= IVAL(data
.dptr
, 0);
4968 if (entry_seqnum
!= dom_seqnum
) {
4969 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4970 (int)entry_seqnum
));
4973 entry_timeout
= BVAL(data
.dptr
, 4);
4974 if (time(NULL
) > entry_timeout
) {
4975 DEBUG(10, ("Entry has timed out\n"));
4980 resp
->data
= (uint8_t *)talloc_memdup(mem_ctx
, data
.dptr
+ 12,
4982 if (resp
->data
== NULL
) {
4983 DEBUG(10, ("talloc failed\n"));
4986 resp
->length
= data
.dsize
- 12;
4990 SAFE_FREE(data
.dptr
);
4994 void wcache_store_ndr(struct winbindd_domain
*domain
, uint32_t opnum
,
4995 const DATA_BLOB
*req
, const DATA_BLOB
*resp
)
4998 uint32_t dom_seqnum
, last_check
;
5001 if (!wcache_opnum_cacheable(opnum
) ||
5002 is_my_own_sam_domain(domain
) ||
5003 is_builtin_domain(domain
)) {
5007 if (wcache
->tdb
== NULL
) {
5011 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
, &last_check
)) {
5012 DEBUG(10, ("could not fetch seqnum for domain %s\n",
5017 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
5021 timeout
= time(NULL
) + lp_winbind_cache_time();
5023 data
.dsize
= resp
->length
+ 12;
5024 data
.dptr
= talloc_array(key
.dptr
, uint8_t, data
.dsize
);
5025 if (data
.dptr
== NULL
) {
5029 SIVAL(data
.dptr
, 0, dom_seqnum
);
5030 SBVAL(data
.dptr
, 4, timeout
);
5031 memcpy(data
.dptr
+ 12, resp
->data
, resp
->length
);
5033 tdb_store(wcache
->tdb
, key
, data
, 0);
5036 TALLOC_FREE(key
.dptr
);