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
[] = {
65 WINBINDD_CACHE_VERSION_KEYSTR
,
69 /************************************************************************
70 Is this key a non-centry type ?
71 ************************************************************************/
73 static bool is_non_centry_key(TDB_DATA kbuf
)
77 if (kbuf
.dptr
== NULL
|| kbuf
.dsize
== 0) {
80 for (i
= 0; non_centry_keys
[i
] != NULL
; i
++) {
81 size_t namelen
= strlen(non_centry_keys
[i
]);
82 if (kbuf
.dsize
< namelen
) {
85 if (strncmp(non_centry_keys
[i
], (const char *)kbuf
.dptr
, namelen
) == 0) {
92 /* Global online/offline state - False when online. winbindd starts up online
93 and sets this to true if the first query fails and there's an entry in
94 the cache tdb telling us to stay offline. */
96 static bool global_winbindd_offline_state
;
98 struct winbind_cache
{
104 uint32 sequence_number
;
110 void (*smb_panic_fn
)(const char *const why
) = smb_panic
;
112 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
114 static struct winbind_cache
*wcache
;
116 /* get the winbind_cache structure */
117 static struct winbind_cache
*get_cache(struct winbindd_domain
*domain
)
119 struct winbind_cache
*ret
= wcache
;
121 /* We have to know what type of domain we are dealing with first. */
123 if (domain
->internal
) {
124 domain
->backend
= &builtin_passdb_methods
;
125 domain
->initialized
= True
;
128 if (strequal(domain
->name
, get_global_sam_name()) &&
129 sid_check_is_domain(&domain
->sid
)) {
130 domain
->backend
= &sam_passdb_methods
;
131 domain
->initialized
= True
;
134 if ( !domain
->initialized
) {
135 init_dc_connection( domain
);
139 OK. listen up becasue I'm only going to say this once.
140 We have the following scenarios to consider
141 (a) trusted AD domains on a Samba DC,
142 (b) trusted AD domains and we are joined to a non-kerberos domain
143 (c) trusted AD domains and we are joined to a kerberos (AD) domain
145 For (a) we can always contact the trusted domain using krb5
146 since we have the domain trust account password
148 For (b) we can only use RPC since we have no way of
149 getting a krb5 ticket in our own domain
151 For (c) we can always use krb5 since we have a kerberos trust
156 if (!domain
->backend
) {
158 struct winbindd_domain
*our_domain
= domain
;
160 /* find our domain first so we can figure out if we
161 are joined to a kerberized domain */
163 if ( !domain
->primary
)
164 our_domain
= find_our_domain();
166 if ((our_domain
->active_directory
|| IS_DC
)
167 && domain
->active_directory
168 && !lp_winbind_rpc_only()) {
169 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain
->name
));
170 domain
->backend
= &ads_methods
;
172 #endif /* HAVE_ADS */
173 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain
->name
));
174 domain
->backend
= &reconnect_methods
;
177 #endif /* HAVE_ADS */
183 ret
= SMB_XMALLOC_P(struct winbind_cache
);
187 wcache_flush_cache();
193 free a centry structure
195 static void centry_free(struct cache_entry
*centry
)
199 SAFE_FREE(centry
->data
);
203 static bool centry_check_bytes(struct cache_entry
*centry
, size_t nbytes
)
205 if (centry
->len
- centry
->ofs
< nbytes
) {
206 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
207 (unsigned int)nbytes
,
208 centry
->len
- centry
->ofs
));
215 pull a uint64_t from a cache entry
217 static uint64_t centry_uint64_t(struct cache_entry
*centry
)
221 if (!centry_check_bytes(centry
, 8)) {
222 smb_panic_fn("centry_uint64_t");
224 ret
= BVAL(centry
->data
, centry
->ofs
);
230 pull a uint32 from a cache entry
232 static uint32
centry_uint32(struct cache_entry
*centry
)
236 if (!centry_check_bytes(centry
, 4)) {
237 smb_panic_fn("centry_uint32");
239 ret
= IVAL(centry
->data
, centry
->ofs
);
245 pull a uint16 from a cache entry
247 static uint16
centry_uint16(struct cache_entry
*centry
)
250 if (!centry_check_bytes(centry
, 2)) {
251 smb_panic_fn("centry_uint16");
253 ret
= SVAL(centry
->data
, centry
->ofs
);
259 pull a uint8 from a cache entry
261 static uint8
centry_uint8(struct cache_entry
*centry
)
264 if (!centry_check_bytes(centry
, 1)) {
265 smb_panic_fn("centry_uint8");
267 ret
= CVAL(centry
->data
, centry
->ofs
);
273 pull a NTTIME from a cache entry
275 static NTTIME
centry_nttime(struct cache_entry
*centry
)
278 if (!centry_check_bytes(centry
, 8)) {
279 smb_panic_fn("centry_nttime");
281 ret
= IVAL(centry
->data
, centry
->ofs
);
283 ret
+= (uint64
)IVAL(centry
->data
, centry
->ofs
) << 32;
289 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
291 static time_t centry_time(struct cache_entry
*centry
)
293 return (time_t)centry_nttime(centry
);
296 /* pull a string from a cache entry, using the supplied
299 static char *centry_string(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
304 len
= centry_uint8(centry
);
307 /* a deliberate NULL string */
311 if (!centry_check_bytes(centry
, (size_t)len
)) {
312 smb_panic_fn("centry_string");
315 ret
= TALLOC_ARRAY(mem_ctx
, char, len
+1);
317 smb_panic_fn("centry_string out of memory\n");
319 memcpy(ret
,centry
->data
+ centry
->ofs
, len
);
325 /* pull a hash16 from a cache entry, using the supplied
328 static char *centry_hash16(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
333 len
= centry_uint8(centry
);
336 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
341 if (!centry_check_bytes(centry
, 16)) {
345 ret
= TALLOC_ARRAY(mem_ctx
, char, 16);
347 smb_panic_fn("centry_hash out of memory\n");
349 memcpy(ret
,centry
->data
+ centry
->ofs
, 16);
354 /* pull a sid from a cache entry, using the supplied
357 static bool centry_sid(struct cache_entry
*centry
, struct dom_sid
*sid
)
362 sid_string
= centry_string(centry
, talloc_tos());
363 if (sid_string
== NULL
) {
366 ret
= string_to_sid(sid
, sid_string
);
367 TALLOC_FREE(sid_string
);
373 pull a NTSTATUS from a cache entry
375 static NTSTATUS
centry_ntstatus(struct cache_entry
*centry
)
379 status
= NT_STATUS(centry_uint32(centry
));
384 /* the server is considered down if it can't give us a sequence number */
385 static bool wcache_server_down(struct winbindd_domain
*domain
)
392 ret
= (domain
->sequence_number
== DOM_SEQUENCE_NONE
);
395 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
400 static bool wcache_fetch_seqnum(const char *domain_name
, uint32_t *seqnum
,
401 uint32_t *last_seq_check
)
406 if (wcache
->tdb
== NULL
) {
407 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
411 key
= talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name
);
413 DEBUG(10, ("talloc failed\n"));
417 data
= tdb_fetch_bystring(wcache
->tdb
, key
);
420 if (data
.dptr
== NULL
) {
421 DEBUG(10, ("wcache_fetch_seqnum: %s not found\n",
425 if (data
.dsize
!= 8) {
426 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
428 SAFE_FREE(data
.dptr
);
432 *seqnum
= IVAL(data
.dptr
, 0);
433 *last_seq_check
= IVAL(data
.dptr
, 4);
434 SAFE_FREE(data
.dptr
);
439 static NTSTATUS
fetch_cache_seqnum( struct winbindd_domain
*domain
, time_t now
)
441 uint32 last_check
, time_diff
;
443 if (!wcache_fetch_seqnum(domain
->name
, &domain
->sequence_number
,
445 return NT_STATUS_UNSUCCESSFUL
;
447 domain
->last_seq_check
= last_check
;
449 /* have we expired? */
451 time_diff
= now
- domain
->last_seq_check
;
452 if ( time_diff
> lp_winbind_cache_time() ) {
453 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
454 domain
->name
, domain
->sequence_number
,
455 (uint32
)domain
->last_seq_check
));
456 return NT_STATUS_UNSUCCESSFUL
;
459 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
460 domain
->name
, domain
->sequence_number
,
461 (uint32
)domain
->last_seq_check
));
466 bool wcache_store_seqnum(const char *domain_name
, uint32_t seqnum
,
467 time_t last_seq_check
)
473 if (wcache
->tdb
== NULL
) {
474 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
478 key_str
= talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name
);
479 if (key_str
== NULL
) {
480 DEBUG(10, ("talloc_asprintf failed\n"));
484 SIVAL(buf
, 0, seqnum
);
485 SIVAL(buf
, 4, last_seq_check
);
487 ret
= tdb_store_bystring(wcache
->tdb
, key_str
,
488 make_tdb_data(buf
, sizeof(buf
)), TDB_REPLACE
);
489 TALLOC_FREE(key_str
);
491 DEBUG(10, ("tdb_store_bystring failed: %s\n",
492 tdb_errorstr(wcache
->tdb
)));
493 TALLOC_FREE(key_str
);
497 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
498 domain_name
, seqnum
, (unsigned)last_seq_check
));
503 static bool store_cache_seqnum( struct winbindd_domain
*domain
)
505 return wcache_store_seqnum(domain
->name
, domain
->sequence_number
,
506 domain
->last_seq_check
);
510 refresh the domain sequence number. If force is true
511 then always refresh it, no matter how recently we fetched it
514 static void refresh_sequence_number(struct winbindd_domain
*domain
, bool force
)
518 time_t t
= time(NULL
);
519 unsigned cache_time
= lp_winbind_cache_time();
521 if (is_domain_offline(domain
)) {
527 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
528 /* trying to reconnect is expensive, don't do it too often */
529 if (domain
->sequence_number
== DOM_SEQUENCE_NONE
) {
534 time_diff
= t
- domain
->last_seq_check
;
536 /* see if we have to refetch the domain sequence number */
537 if (!force
&& (time_diff
< cache_time
) &&
538 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
539 NT_STATUS_IS_OK(domain
->last_status
)) {
540 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain
->name
));
544 /* try to get the sequence number from the tdb cache first */
545 /* this will update the timestamp as well */
547 status
= fetch_cache_seqnum( domain
, t
);
548 if (NT_STATUS_IS_OK(status
) &&
549 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
550 NT_STATUS_IS_OK(domain
->last_status
)) {
554 /* important! make sure that we know if this is a native
555 mode domain or not. And that we can contact it. */
557 if ( winbindd_can_contact_domain( domain
) ) {
558 status
= domain
->backend
->sequence_number(domain
,
559 &domain
->sequence_number
);
561 /* just use the current time */
562 status
= NT_STATUS_OK
;
563 domain
->sequence_number
= time(NULL
);
567 /* the above call could have set our domain->backend to NULL when
568 * coming from offline to online mode, make sure to reinitialize the
569 * backend - Guenther */
572 if (!NT_STATUS_IS_OK(status
)) {
573 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status
)));
574 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
577 domain
->last_status
= status
;
578 domain
->last_seq_check
= time(NULL
);
580 /* save the new sequence number in the cache */
581 store_cache_seqnum( domain
);
584 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
585 domain
->name
, domain
->sequence_number
));
591 decide if a cache entry has expired
593 static bool centry_expired(struct winbindd_domain
*domain
, const char *keystr
, struct cache_entry
*centry
)
595 /* If we've been told to be offline - stay in that state... */
596 if (lp_winbind_offline_logon() && global_winbindd_offline_state
) {
597 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
598 keystr
, domain
->name
));
602 /* when the domain is offline return the cached entry.
603 * This deals with transient offline states... */
605 if (!domain
->online
) {
606 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
607 keystr
, domain
->name
));
611 /* if the server is OK and our cache entry came from when it was down then
612 the entry is invalid */
613 if ((domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
614 (centry
->sequence_number
== DOM_SEQUENCE_NONE
)) {
615 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
616 keystr
, domain
->name
));
620 /* if the server is down or the cache entry is not older than the
621 current sequence number or it did not timeout then it is OK */
622 if (wcache_server_down(domain
)
623 || ((centry
->sequence_number
== domain
->sequence_number
)
624 && (centry
->timeout
> time(NULL
)))) {
625 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
626 keystr
, domain
->name
));
630 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
631 keystr
, domain
->name
));
637 static struct cache_entry
*wcache_fetch_raw(char *kstr
)
640 struct cache_entry
*centry
;
643 key
= string_tdb_data(kstr
);
644 data
= tdb_fetch(wcache
->tdb
, key
);
650 centry
= SMB_XMALLOC_P(struct cache_entry
);
651 centry
->data
= (unsigned char *)data
.dptr
;
652 centry
->len
= data
.dsize
;
655 if (centry
->len
< 16) {
656 /* huh? corrupt cache? */
657 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s "
658 "(len < 16)?\n", kstr
));
663 centry
->status
= centry_ntstatus(centry
);
664 centry
->sequence_number
= centry_uint32(centry
);
665 centry
->timeout
= centry_uint64_t(centry
);
670 static bool is_my_own_sam_domain(struct winbindd_domain
*domain
)
672 if (strequal(domain
->name
, get_global_sam_name()) &&
673 sid_check_is_domain(&domain
->sid
)) {
680 static bool is_builtin_domain(struct winbindd_domain
*domain
)
682 if (strequal(domain
->name
, "BUILTIN") &&
683 sid_check_is_builtin(&domain
->sid
)) {
691 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
692 number and return status
694 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
695 struct winbindd_domain
*domain
,
696 const char *format
, ...) PRINTF_ATTRIBUTE(3,4);
697 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
698 struct winbindd_domain
*domain
,
699 const char *format
, ...)
703 struct cache_entry
*centry
;
705 if (!winbindd_use_cache() ||
706 is_my_own_sam_domain(domain
) ||
707 is_builtin_domain(domain
)) {
711 refresh_sequence_number(domain
, false);
713 va_start(ap
, format
);
714 smb_xvasprintf(&kstr
, format
, ap
);
717 centry
= wcache_fetch_raw(kstr
);
718 if (centry
== NULL
) {
723 if (centry_expired(domain
, kstr
, centry
)) {
725 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
726 kstr
, domain
->name
));
733 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
734 kstr
, domain
->name
));
740 static void wcache_delete(const char *format
, ...) PRINTF_ATTRIBUTE(1,2);
741 static void wcache_delete(const char *format
, ...)
747 va_start(ap
, format
);
748 smb_xvasprintf(&kstr
, format
, ap
);
751 key
= string_tdb_data(kstr
);
753 tdb_delete(wcache
->tdb
, key
);
758 make sure we have at least len bytes available in a centry
760 static void centry_expand(struct cache_entry
*centry
, uint32 len
)
762 if (centry
->len
- centry
->ofs
>= len
)
765 centry
->data
= SMB_REALLOC_ARRAY(centry
->data
, unsigned char,
768 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry
->len
));
769 smb_panic_fn("out of memory in centry_expand");
774 push a uint64_t into a centry
776 static void centry_put_uint64_t(struct cache_entry
*centry
, uint64_t v
)
778 centry_expand(centry
, 8);
779 SBVAL(centry
->data
, centry
->ofs
, v
);
784 push a uint32 into a centry
786 static void centry_put_uint32(struct cache_entry
*centry
, uint32 v
)
788 centry_expand(centry
, 4);
789 SIVAL(centry
->data
, centry
->ofs
, v
);
794 push a uint16 into a centry
796 static void centry_put_uint16(struct cache_entry
*centry
, uint16 v
)
798 centry_expand(centry
, 2);
799 SSVAL(centry
->data
, centry
->ofs
, v
);
804 push a uint8 into a centry
806 static void centry_put_uint8(struct cache_entry
*centry
, uint8 v
)
808 centry_expand(centry
, 1);
809 SCVAL(centry
->data
, centry
->ofs
, v
);
814 push a string into a centry
816 static void centry_put_string(struct cache_entry
*centry
, const char *s
)
821 /* null strings are marked as len 0xFFFF */
822 centry_put_uint8(centry
, 0xFF);
827 /* can't handle more than 254 char strings. Truncating is probably best */
829 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len
));
832 centry_put_uint8(centry
, len
);
833 centry_expand(centry
, len
);
834 memcpy(centry
->data
+ centry
->ofs
, s
, len
);
839 push a 16 byte hash into a centry - treat as 16 byte string.
841 static void centry_put_hash16(struct cache_entry
*centry
, const uint8 val
[16])
843 centry_put_uint8(centry
, 16);
844 centry_expand(centry
, 16);
845 memcpy(centry
->data
+ centry
->ofs
, val
, 16);
849 static void centry_put_sid(struct cache_entry
*centry
, const struct dom_sid
*sid
)
852 centry_put_string(centry
, sid_to_fstring(sid_string
, sid
));
857 put NTSTATUS into a centry
859 static void centry_put_ntstatus(struct cache_entry
*centry
, NTSTATUS status
)
861 uint32 status_value
= NT_STATUS_V(status
);
862 centry_put_uint32(centry
, status_value
);
867 push a NTTIME into a centry
869 static void centry_put_nttime(struct cache_entry
*centry
, NTTIME nt
)
871 centry_expand(centry
, 8);
872 SIVAL(centry
->data
, centry
->ofs
, nt
& 0xFFFFFFFF);
874 SIVAL(centry
->data
, centry
->ofs
, nt
>> 32);
879 push a time_t into a centry - use a 64 bit size.
880 NTTIME here is being used as a convenient 64-bit size.
882 static void centry_put_time(struct cache_entry
*centry
, time_t t
)
884 NTTIME nt
= (NTTIME
)t
;
885 centry_put_nttime(centry
, nt
);
889 start a centry for output. When finished, call centry_end()
891 struct cache_entry
*centry_start(struct winbindd_domain
*domain
, NTSTATUS status
)
893 struct cache_entry
*centry
;
898 centry
= SMB_XMALLOC_P(struct cache_entry
);
900 centry
->len
= 8192; /* reasonable default */
901 centry
->data
= SMB_XMALLOC_ARRAY(uint8
, centry
->len
);
903 centry
->sequence_number
= domain
->sequence_number
;
904 centry
->timeout
= lp_winbind_cache_time() + time(NULL
);
905 centry_put_ntstatus(centry
, status
);
906 centry_put_uint32(centry
, centry
->sequence_number
);
907 centry_put_uint64_t(centry
, centry
->timeout
);
912 finish a centry and write it to the tdb
914 static void centry_end(struct cache_entry
*centry
, const char *format
, ...) PRINTF_ATTRIBUTE(2,3);
915 static void centry_end(struct cache_entry
*centry
, const char *format
, ...)
921 if (!winbindd_use_cache()) {
925 va_start(ap
, format
);
926 smb_xvasprintf(&kstr
, format
, ap
);
929 key
= string_tdb_data(kstr
);
930 data
.dptr
= centry
->data
;
931 data
.dsize
= centry
->ofs
;
933 tdb_store(wcache
->tdb
, key
, data
, TDB_REPLACE
);
937 static void wcache_save_name_to_sid(struct winbindd_domain
*domain
,
938 NTSTATUS status
, const char *domain_name
,
939 const char *name
, const struct dom_sid
*sid
,
940 enum lsa_SidType type
)
942 struct cache_entry
*centry
;
945 centry
= centry_start(domain
, status
);
949 if (domain_name
[0] == '\0') {
950 struct winbindd_domain
*mydomain
=
951 find_domain_from_sid_noinit(sid
);
952 if (mydomain
!= NULL
) {
953 domain_name
= mydomain
->name
;
957 centry_put_uint32(centry
, type
);
958 centry_put_sid(centry
, sid
);
959 fstrcpy(uname
, name
);
961 centry_end(centry
, "NS/%s/%s", domain_name
, uname
);
962 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name
,
963 uname
, sid_string_dbg(sid
), nt_errstr(status
)));
967 static void wcache_save_sid_to_name(struct winbindd_domain
*domain
, NTSTATUS status
,
968 const struct dom_sid
*sid
, const char *domain_name
, const char *name
, enum lsa_SidType type
)
970 struct cache_entry
*centry
;
973 centry
= centry_start(domain
, status
);
977 if (domain_name
[0] == '\0') {
978 struct winbindd_domain
*mydomain
=
979 find_domain_from_sid_noinit(sid
);
980 if (mydomain
!= NULL
) {
981 domain_name
= mydomain
->name
;
985 if (NT_STATUS_IS_OK(status
)) {
986 centry_put_uint32(centry
, type
);
987 centry_put_string(centry
, domain_name
);
988 centry_put_string(centry
, name
);
991 centry_end(centry
, "SN/%s", sid_to_fstring(sid_string
, sid
));
992 DEBUG(10,("wcache_save_sid_to_name: %s -> %s (%s)\n", sid_string
,
993 name
, nt_errstr(status
)));
998 static void wcache_save_user(struct winbindd_domain
*domain
, NTSTATUS status
,
999 struct wbint_userinfo
*info
)
1001 struct cache_entry
*centry
;
1004 if (is_null_sid(&info
->user_sid
)) {
1008 centry
= centry_start(domain
, status
);
1011 centry_put_string(centry
, info
->acct_name
);
1012 centry_put_string(centry
, info
->full_name
);
1013 centry_put_string(centry
, info
->homedir
);
1014 centry_put_string(centry
, info
->shell
);
1015 centry_put_uint32(centry
, info
->primary_gid
);
1016 centry_put_sid(centry
, &info
->user_sid
);
1017 centry_put_sid(centry
, &info
->group_sid
);
1018 centry_end(centry
, "U/%s", sid_to_fstring(sid_string
,
1020 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string
, info
->acct_name
));
1021 centry_free(centry
);
1024 static void wcache_save_lockout_policy(struct winbindd_domain
*domain
,
1026 struct samr_DomInfo12
*lockout_policy
)
1028 struct cache_entry
*centry
;
1030 centry
= centry_start(domain
, status
);
1034 centry_put_nttime(centry
, lockout_policy
->lockout_duration
);
1035 centry_put_nttime(centry
, lockout_policy
->lockout_window
);
1036 centry_put_uint16(centry
, lockout_policy
->lockout_threshold
);
1038 centry_end(centry
, "LOC_POL/%s", domain
->name
);
1040 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain
->name
));
1042 centry_free(centry
);
1047 static void wcache_save_password_policy(struct winbindd_domain
*domain
,
1049 struct samr_DomInfo1
*policy
)
1051 struct cache_entry
*centry
;
1053 centry
= centry_start(domain
, status
);
1057 centry_put_uint16(centry
, policy
->min_password_length
);
1058 centry_put_uint16(centry
, policy
->password_history_length
);
1059 centry_put_uint32(centry
, policy
->password_properties
);
1060 centry_put_nttime(centry
, policy
->max_password_age
);
1061 centry_put_nttime(centry
, policy
->min_password_age
);
1063 centry_end(centry
, "PWD_POL/%s", domain
->name
);
1065 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
1067 centry_free(centry
);
1070 /***************************************************************************
1071 ***************************************************************************/
1073 static void wcache_save_username_alias(struct winbindd_domain
*domain
,
1075 const char *name
, const char *alias
)
1077 struct cache_entry
*centry
;
1080 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1083 centry_put_string( centry
, alias
);
1085 fstrcpy(uname
, name
);
1087 centry_end(centry
, "NSS/NA/%s", uname
);
1089 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name
, alias
));
1091 centry_free(centry
);
1094 static void wcache_save_alias_username(struct winbindd_domain
*domain
,
1096 const char *alias
, const char *name
)
1098 struct cache_entry
*centry
;
1101 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1104 centry_put_string( centry
, name
);
1106 fstrcpy(uname
, alias
);
1108 centry_end(centry
, "NSS/AN/%s", uname
);
1110 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias
, name
));
1112 centry_free(centry
);
1115 /***************************************************************************
1116 ***************************************************************************/
1118 NTSTATUS
resolve_username_to_alias( TALLOC_CTX
*mem_ctx
,
1119 struct winbindd_domain
*domain
,
1120 const char *name
, char **alias
)
1122 struct winbind_cache
*cache
= get_cache(domain
);
1123 struct cache_entry
*centry
= NULL
;
1127 if ( domain
->internal
)
1128 return NT_STATUS_NOT_SUPPORTED
;
1133 if ( (upper_name
= SMB_STRDUP(name
)) == NULL
)
1134 return NT_STATUS_NO_MEMORY
;
1135 strupper_m(upper_name
);
1137 centry
= wcache_fetch(cache
, domain
, "NSS/NA/%s", upper_name
);
1139 SAFE_FREE( upper_name
);
1144 status
= centry
->status
;
1146 if (!NT_STATUS_IS_OK(status
)) {
1147 centry_free(centry
);
1151 *alias
= centry_string( centry
, mem_ctx
);
1153 centry_free(centry
);
1155 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1156 name
, *alias
? *alias
: "(none)"));
1158 return (*alias
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1162 /* If its not in cache and we are offline, then fail */
1164 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1165 DEBUG(8,("resolve_username_to_alias: rejecting query "
1166 "in offline mode\n"));
1167 return NT_STATUS_NOT_FOUND
;
1170 status
= nss_map_to_alias( mem_ctx
, domain
->name
, name
, alias
);
1172 if ( NT_STATUS_IS_OK( status
) ) {
1173 wcache_save_username_alias(domain
, status
, name
, *alias
);
1176 if ( NT_STATUS_EQUAL( status
, NT_STATUS_NONE_MAPPED
) ) {
1177 wcache_save_username_alias(domain
, status
, name
, "(NULL)");
1180 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1181 nt_errstr(status
)));
1183 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1184 set_domain_offline( domain
);
1190 /***************************************************************************
1191 ***************************************************************************/
1193 NTSTATUS
resolve_alias_to_username( TALLOC_CTX
*mem_ctx
,
1194 struct winbindd_domain
*domain
,
1195 const char *alias
, char **name
)
1197 struct winbind_cache
*cache
= get_cache(domain
);
1198 struct cache_entry
*centry
= NULL
;
1202 if ( domain
->internal
)
1203 return NT_STATUS_NOT_SUPPORTED
;
1208 if ( (upper_name
= SMB_STRDUP(alias
)) == NULL
)
1209 return NT_STATUS_NO_MEMORY
;
1210 strupper_m(upper_name
);
1212 centry
= wcache_fetch(cache
, domain
, "NSS/AN/%s", upper_name
);
1214 SAFE_FREE( upper_name
);
1219 status
= centry
->status
;
1221 if (!NT_STATUS_IS_OK(status
)) {
1222 centry_free(centry
);
1226 *name
= centry_string( centry
, mem_ctx
);
1228 centry_free(centry
);
1230 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1231 alias
, *name
? *name
: "(none)"));
1233 return (*name
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1237 /* If its not in cache and we are offline, then fail */
1239 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1240 DEBUG(8,("resolve_alias_to_username: rejecting query "
1241 "in offline mode\n"));
1242 return NT_STATUS_NOT_FOUND
;
1245 /* an alias cannot contain a domain prefix or '@' */
1247 if (strchr(alias
, '\\') || strchr(alias
, '@')) {
1248 DEBUG(10,("resolve_alias_to_username: skipping fully "
1249 "qualified name %s\n", alias
));
1250 return NT_STATUS_OBJECT_NAME_INVALID
;
1253 status
= nss_map_from_alias( mem_ctx
, domain
->name
, alias
, name
);
1255 if ( NT_STATUS_IS_OK( status
) ) {
1256 wcache_save_alias_username( domain
, status
, alias
, *name
);
1259 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1260 wcache_save_alias_username(domain
, status
, alias
, "(NULL)");
1263 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1264 nt_errstr(status
)));
1266 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1267 set_domain_offline( domain
);
1273 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
1275 struct winbind_cache
*cache
= get_cache(domain
);
1277 fstring key_str
, tmp
;
1281 return NT_STATUS_INTERNAL_DB_ERROR
;
1284 if (is_null_sid(sid
)) {
1285 return NT_STATUS_INVALID_SID
;
1288 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1289 return NT_STATUS_INVALID_SID
;
1292 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
1294 data
= tdb_fetch(cache
->tdb
, string_tdb_data(key_str
));
1296 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1299 SAFE_FREE(data
.dptr
);
1300 return NT_STATUS_OK
;
1303 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1304 as new salted ones. */
1306 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
1307 TALLOC_CTX
*mem_ctx
,
1308 const struct dom_sid
*sid
,
1309 const uint8
**cached_nt_pass
,
1310 const uint8
**cached_salt
)
1312 struct winbind_cache
*cache
= get_cache(domain
);
1313 struct cache_entry
*centry
= NULL
;
1320 return NT_STATUS_INTERNAL_DB_ERROR
;
1323 if (is_null_sid(sid
)) {
1324 return NT_STATUS_INVALID_SID
;
1327 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1328 return NT_STATUS_INVALID_SID
;
1331 /* Try and get a salted cred first. If we can't
1332 fall back to an unsalted cred. */
1334 centry
= wcache_fetch(cache
, domain
, "CRED/%s",
1335 sid_to_fstring(tmp
, sid
));
1337 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1338 sid_string_dbg(sid
)));
1339 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1342 t
= centry_time(centry
);
1344 /* In the salted case this isn't actually the nt_hash itself,
1345 but the MD5 of the salt + nt_hash. Let the caller
1346 sort this out. It can tell as we only return the cached_salt
1347 if we are returning a salted cred. */
1349 *cached_nt_pass
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1350 if (*cached_nt_pass
== NULL
) {
1353 sid_to_fstring(sidstr
, sid
);
1355 /* Bad (old) cred cache. Delete and pretend we
1357 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1359 wcache_delete("CRED/%s", sidstr
);
1360 centry_free(centry
);
1361 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1364 /* We only have 17 bytes more data in the salted cred case. */
1365 if (centry
->len
- centry
->ofs
== 17) {
1366 *cached_salt
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1368 *cached_salt
= NULL
;
1371 dump_data_pw("cached_nt_pass", *cached_nt_pass
, NT_HASH_LEN
);
1373 dump_data_pw("cached_salt", *cached_salt
, NT_HASH_LEN
);
1376 status
= centry
->status
;
1378 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1379 sid_string_dbg(sid
), nt_errstr(status
) ));
1381 centry_free(centry
);
1385 /* Store creds for a SID - only writes out new salted ones. */
1387 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1388 const struct dom_sid
*sid
,
1389 const uint8 nt_pass
[NT_HASH_LEN
])
1391 struct cache_entry
*centry
;
1394 uint8 cred_salt
[NT_HASH_LEN
];
1395 uint8 salted_hash
[NT_HASH_LEN
];
1397 if (is_null_sid(sid
)) {
1398 return NT_STATUS_INVALID_SID
;
1401 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1402 return NT_STATUS_INVALID_SID
;
1405 centry
= centry_start(domain
, NT_STATUS_OK
);
1407 return NT_STATUS_INTERNAL_DB_ERROR
;
1410 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1412 centry_put_time(centry
, time(NULL
));
1414 /* Create a salt and then salt the hash. */
1415 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1416 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1418 centry_put_hash16(centry
, salted_hash
);
1419 centry_put_hash16(centry
, cred_salt
);
1420 centry_end(centry
, "CRED/%s", sid_to_fstring(sid_string
, sid
));
1422 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1424 centry_free(centry
);
1426 return NT_STATUS_OK
;
1430 /* Query display info. This is the basic user list fn */
1431 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
1432 TALLOC_CTX
*mem_ctx
,
1433 uint32
*num_entries
,
1434 struct wbint_userinfo
**info
)
1436 struct winbind_cache
*cache
= get_cache(domain
);
1437 struct cache_entry
*centry
= NULL
;
1439 unsigned int i
, retry
;
1440 bool old_status
= domain
->online
;
1445 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1450 *num_entries
= centry_uint32(centry
);
1452 if (*num_entries
== 0)
1455 (*info
) = TALLOC_ARRAY(mem_ctx
, struct wbint_userinfo
, *num_entries
);
1457 smb_panic_fn("query_user_list out of memory");
1459 for (i
=0; i
<(*num_entries
); i
++) {
1460 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
1461 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
1462 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
1463 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
1464 centry_sid(centry
, &(*info
)[i
].user_sid
);
1465 centry_sid(centry
, &(*info
)[i
].group_sid
);
1469 status
= centry
->status
;
1471 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1472 domain
->name
, nt_errstr(status
) ));
1474 centry_free(centry
);
1481 /* Return status value returned by seq number check */
1483 if (!NT_STATUS_IS_OK(domain
->last_status
))
1484 return domain
->last_status
;
1486 /* Put the query_user_list() in a retry loop. There appears to be
1487 * some bug either with Windows 2000 or Samba's handling of large
1488 * rpc replies. This manifests itself as sudden disconnection
1489 * at a random point in the enumeration of a large (60k) user list.
1490 * The retry loop simply tries the operation again. )-: It's not
1491 * pretty but an acceptable workaround until we work out what the
1492 * real problem is. */
1497 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1500 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
1501 if (!NT_STATUS_IS_OK(status
)) {
1502 DEBUG(3, ("query_user_list: returned 0x%08x, "
1503 "retrying\n", NT_STATUS_V(status
)));
1505 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1506 DEBUG(3, ("query_user_list: flushing "
1507 "connection cache\n"));
1508 invalidate_cm_connection(&domain
->conn
);
1510 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1511 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1512 if (!domain
->internal
&& old_status
) {
1513 set_domain_offline(domain
);
1515 /* store partial response. */
1516 if (*num_entries
> 0) {
1518 * humm, what about the status used for cache?
1519 * Should it be NT_STATUS_OK?
1524 * domain is offline now, and there is no user entries,
1525 * try to fetch from cache again.
1527 if (cache
->tdb
&& !domain
->online
&& !domain
->internal
&& old_status
) {
1528 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1529 /* partial response... */
1533 goto do_fetch_cache
;
1540 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1544 refresh_sequence_number(domain
, false);
1545 if (!NT_STATUS_IS_OK(status
)) {
1548 centry
= centry_start(domain
, status
);
1551 centry_put_uint32(centry
, *num_entries
);
1552 for (i
=0; i
<(*num_entries
); i
++) {
1553 centry_put_string(centry
, (*info
)[i
].acct_name
);
1554 centry_put_string(centry
, (*info
)[i
].full_name
);
1555 centry_put_string(centry
, (*info
)[i
].homedir
);
1556 centry_put_string(centry
, (*info
)[i
].shell
);
1557 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1558 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1559 if (domain
->backend
&& domain
->backend
->consistent
) {
1560 /* when the backend is consistent we can pre-prime some mappings */
1561 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1563 (*info
)[i
].acct_name
,
1564 &(*info
)[i
].user_sid
,
1566 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1567 &(*info
)[i
].user_sid
,
1569 (*info
)[i
].acct_name
,
1571 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1574 centry_end(centry
, "UL/%s", domain
->name
);
1575 centry_free(centry
);
1581 /* list all domain groups */
1582 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
1583 TALLOC_CTX
*mem_ctx
,
1584 uint32
*num_entries
,
1585 struct wb_acct_info
**info
)
1587 struct winbind_cache
*cache
= get_cache(domain
);
1588 struct cache_entry
*centry
= NULL
;
1593 old_status
= domain
->online
;
1597 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1602 *num_entries
= centry_uint32(centry
);
1604 if (*num_entries
== 0)
1607 (*info
) = TALLOC_ARRAY(mem_ctx
, struct wb_acct_info
, *num_entries
);
1609 smb_panic_fn("enum_dom_groups out of memory");
1611 for (i
=0; i
<(*num_entries
); i
++) {
1612 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1613 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1614 (*info
)[i
].rid
= centry_uint32(centry
);
1618 status
= centry
->status
;
1620 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1621 domain
->name
, nt_errstr(status
) ));
1623 centry_free(centry
);
1630 /* Return status value returned by seq number check */
1632 if (!NT_STATUS_IS_OK(domain
->last_status
))
1633 return domain
->last_status
;
1635 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1638 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1640 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1641 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1642 if (!domain
->internal
&& old_status
) {
1643 set_domain_offline(domain
);
1647 !domain
->internal
&&
1649 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1651 goto do_fetch_cache
;
1656 refresh_sequence_number(domain
, false);
1657 if (!NT_STATUS_IS_OK(status
)) {
1660 centry
= centry_start(domain
, status
);
1663 centry_put_uint32(centry
, *num_entries
);
1664 for (i
=0; i
<(*num_entries
); i
++) {
1665 centry_put_string(centry
, (*info
)[i
].acct_name
);
1666 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1667 centry_put_uint32(centry
, (*info
)[i
].rid
);
1669 centry_end(centry
, "GL/%s/domain", domain
->name
);
1670 centry_free(centry
);
1676 /* list all domain groups */
1677 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
1678 TALLOC_CTX
*mem_ctx
,
1679 uint32
*num_entries
,
1680 struct wb_acct_info
**info
)
1682 struct winbind_cache
*cache
= get_cache(domain
);
1683 struct cache_entry
*centry
= NULL
;
1688 old_status
= domain
->online
;
1692 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1697 *num_entries
= centry_uint32(centry
);
1699 if (*num_entries
== 0)
1702 (*info
) = TALLOC_ARRAY(mem_ctx
, struct wb_acct_info
, *num_entries
);
1704 smb_panic_fn("enum_dom_groups out of memory");
1706 for (i
=0; i
<(*num_entries
); i
++) {
1707 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1708 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1709 (*info
)[i
].rid
= centry_uint32(centry
);
1714 /* If we are returning cached data and the domain controller
1715 is down then we don't know whether the data is up to date
1716 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1719 if (wcache_server_down(domain
)) {
1720 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1721 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1723 status
= centry
->status
;
1725 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1726 domain
->name
, nt_errstr(status
) ));
1728 centry_free(centry
);
1735 /* Return status value returned by seq number check */
1737 if (!NT_STATUS_IS_OK(domain
->last_status
))
1738 return domain
->last_status
;
1740 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1743 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1745 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1746 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1747 if (!domain
->internal
&& old_status
) {
1748 set_domain_offline(domain
);
1751 !domain
->internal
&&
1754 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1756 goto do_fetch_cache
;
1761 refresh_sequence_number(domain
, false);
1762 if (!NT_STATUS_IS_OK(status
)) {
1765 centry
= centry_start(domain
, status
);
1768 centry_put_uint32(centry
, *num_entries
);
1769 for (i
=0; i
<(*num_entries
); i
++) {
1770 centry_put_string(centry
, (*info
)[i
].acct_name
);
1771 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1772 centry_put_uint32(centry
, (*info
)[i
].rid
);
1774 centry_end(centry
, "GL/%s/local", domain
->name
);
1775 centry_free(centry
);
1781 NTSTATUS
wcache_name_to_sid(struct winbindd_domain
*domain
,
1782 const char *domain_name
,
1784 struct dom_sid
*sid
,
1785 enum lsa_SidType
*type
)
1787 struct winbind_cache
*cache
= get_cache(domain
);
1788 struct cache_entry
*centry
;
1792 if (cache
->tdb
== NULL
) {
1793 return NT_STATUS_NOT_FOUND
;
1796 uname
= talloc_strdup_upper(talloc_tos(), name
);
1797 if (uname
== NULL
) {
1798 return NT_STATUS_NO_MEMORY
;
1801 if (domain_name
[0] == '\0') {
1802 domain_name
= domain
->name
;
1805 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1807 if (centry
== NULL
) {
1808 return NT_STATUS_NOT_FOUND
;
1811 status
= centry
->status
;
1812 if (NT_STATUS_IS_OK(status
)) {
1813 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1814 centry_sid(centry
, sid
);
1817 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1818 "%s\n", domain
->name
, nt_errstr(status
) ));
1820 centry_free(centry
);
1824 /* convert a single name to a sid in a domain */
1825 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
1826 TALLOC_CTX
*mem_ctx
,
1827 const char *domain_name
,
1830 struct dom_sid
*sid
,
1831 enum lsa_SidType
*type
)
1836 old_status
= domain
->online
;
1838 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1839 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1845 /* If the seq number check indicated that there is a problem
1846 * with this DC, then return that status... except for
1847 * access_denied. This is special because the dc may be in
1848 * "restrict anonymous = 1" mode, in which case it will deny
1849 * most unauthenticated operations, but *will* allow the LSA
1850 * name-to-sid that we try as a fallback. */
1852 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1853 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1854 return domain
->last_status
;
1856 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1859 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
,
1860 name
, flags
, sid
, type
);
1862 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1863 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1864 if (!domain
->internal
&& old_status
) {
1865 set_domain_offline(domain
);
1867 if (!domain
->internal
&&
1870 NTSTATUS cache_status
;
1871 cache_status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1872 return cache_status
;
1876 refresh_sequence_number(domain
, false);
1878 if (domain
->online
&&
1879 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1880 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1882 /* Only save the reverse mapping if this was not a UPN */
1883 if (!strchr(name
, '@')) {
1884 strupper_m(CONST_DISCARD(char *,domain_name
));
1885 strlower_m(CONST_DISCARD(char *,name
));
1886 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1893 NTSTATUS
wcache_sid_to_name(struct winbindd_domain
*domain
,
1894 const struct dom_sid
*sid
,
1895 TALLOC_CTX
*mem_ctx
,
1898 enum lsa_SidType
*type
)
1900 struct winbind_cache
*cache
= get_cache(domain
);
1901 struct cache_entry
*centry
;
1905 if (cache
->tdb
== NULL
) {
1906 return NT_STATUS_NOT_FOUND
;
1909 sid_string
= sid_string_tos(sid
);
1910 if (sid_string
== NULL
) {
1911 return NT_STATUS_NO_MEMORY
;
1914 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_string
);
1915 TALLOC_FREE(sid_string
);
1916 if (centry
== NULL
) {
1917 return NT_STATUS_NOT_FOUND
;
1920 if (NT_STATUS_IS_OK(centry
->status
)) {
1921 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1922 *domain_name
= centry_string(centry
, mem_ctx
);
1923 *name
= centry_string(centry
, mem_ctx
);
1926 status
= centry
->status
;
1927 centry_free(centry
);
1929 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1930 "%s\n", domain
->name
, nt_errstr(status
) ));
1935 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1937 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1938 TALLOC_CTX
*mem_ctx
,
1939 const struct dom_sid
*sid
,
1942 enum lsa_SidType
*type
)
1947 old_status
= domain
->online
;
1948 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
1950 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1955 *domain_name
= NULL
;
1957 /* If the seq number check indicated that there is a problem
1958 * with this DC, then return that status... except for
1959 * access_denied. This is special because the dc may be in
1960 * "restrict anonymous = 1" mode, in which case it will deny
1961 * most unauthenticated operations, but *will* allow the LSA
1962 * sid-to-name that we try as a fallback. */
1964 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1965 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1966 return domain
->last_status
;
1968 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1971 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1973 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1974 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1975 if (!domain
->internal
&& old_status
) {
1976 set_domain_offline(domain
);
1978 if (!domain
->internal
&&
1981 NTSTATUS cache_status
;
1982 cache_status
= wcache_sid_to_name(domain
, sid
, mem_ctx
,
1983 domain_name
, name
, type
);
1984 return cache_status
;
1988 refresh_sequence_number(domain
, false);
1989 if (!NT_STATUS_IS_OK(status
)) {
1992 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
1994 /* We can't save the name to sid mapping here, as with sid history a
1995 * later name2sid would give the wrong sid. */
2000 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
2001 TALLOC_CTX
*mem_ctx
,
2002 const struct dom_sid
*domain_sid
,
2007 enum lsa_SidType
**types
)
2009 struct winbind_cache
*cache
= get_cache(domain
);
2011 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
2016 old_status
= domain
->online
;
2017 *domain_name
= NULL
;
2025 if (num_rids
== 0) {
2026 return NT_STATUS_OK
;
2029 *names
= TALLOC_ARRAY(mem_ctx
, char *, num_rids
);
2030 *types
= TALLOC_ARRAY(mem_ctx
, enum lsa_SidType
, num_rids
);
2032 if ((*names
== NULL
) || (*types
== NULL
)) {
2033 result
= NT_STATUS_NO_MEMORY
;
2037 have_mapped
= have_unmapped
= false;
2039 for (i
=0; i
<num_rids
; i
++) {
2041 struct cache_entry
*centry
;
2044 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2045 result
= NT_STATUS_INTERNAL_ERROR
;
2049 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2050 sid_to_fstring(tmp
, &sid
));
2055 (*types
)[i
] = SID_NAME_UNKNOWN
;
2056 (*names
)[i
] = talloc_strdup(*names
, "");
2058 if (NT_STATUS_IS_OK(centry
->status
)) {
2061 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2063 dom
= centry_string(centry
, mem_ctx
);
2064 if (*domain_name
== NULL
) {
2070 (*names
)[i
] = centry_string(centry
, *names
);
2072 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)
2073 || NT_STATUS_EQUAL(centry
->status
, STATUS_SOME_UNMAPPED
)) {
2074 have_unmapped
= true;
2077 /* something's definitely wrong */
2078 result
= centry
->status
;
2082 centry_free(centry
);
2086 return NT_STATUS_NONE_MAPPED
;
2088 if (!have_unmapped
) {
2089 return NT_STATUS_OK
;
2091 return STATUS_SOME_UNMAPPED
;
2095 TALLOC_FREE(*names
);
2096 TALLOC_FREE(*types
);
2098 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
2099 rids
, num_rids
, domain_name
,
2102 if (NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
2103 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2104 if (!domain
->internal
&& old_status
) {
2105 set_domain_offline(domain
);
2108 !domain
->internal
&&
2111 have_mapped
= have_unmapped
= false;
2113 for (i
=0; i
<num_rids
; i
++) {
2115 struct cache_entry
*centry
;
2118 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2119 result
= NT_STATUS_INTERNAL_ERROR
;
2123 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2124 sid_to_fstring(tmp
, &sid
));
2126 (*types
)[i
] = SID_NAME_UNKNOWN
;
2127 (*names
)[i
] = talloc_strdup(*names
, "");
2131 (*types
)[i
] = SID_NAME_UNKNOWN
;
2132 (*names
)[i
] = talloc_strdup(*names
, "");
2134 if (NT_STATUS_IS_OK(centry
->status
)) {
2137 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2139 dom
= centry_string(centry
, mem_ctx
);
2140 if (*domain_name
== NULL
) {
2146 (*names
)[i
] = centry_string(centry
, *names
);
2148 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)) {
2149 have_unmapped
= true;
2152 /* something's definitely wrong */
2153 result
= centry
->status
;
2154 centry_free(centry
);
2158 centry_free(centry
);
2162 return NT_STATUS_NONE_MAPPED
;
2164 if (!have_unmapped
) {
2165 return NT_STATUS_OK
;
2167 return STATUS_SOME_UNMAPPED
;
2171 None of the queried rids has been found so save all negative entries
2173 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
2174 for (i
= 0; i
< num_rids
; i
++) {
2176 const char *name
= "";
2177 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
2178 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
2180 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2181 return NT_STATUS_INTERNAL_ERROR
;
2184 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2192 Some or all of the queried rids have been found.
2194 if (!NT_STATUS_IS_OK(result
) &&
2195 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
2199 refresh_sequence_number(domain
, false);
2201 for (i
=0; i
<num_rids
; i
++) {
2205 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2206 result
= NT_STATUS_INTERNAL_ERROR
;
2210 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
2211 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
2213 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2214 (*names
)[i
], (*types
)[i
]);
2220 TALLOC_FREE(*names
);
2221 TALLOC_FREE(*types
);
2225 NTSTATUS
wcache_query_user(struct winbindd_domain
*domain
,
2226 TALLOC_CTX
*mem_ctx
,
2227 const struct dom_sid
*user_sid
,
2228 struct wbint_userinfo
*info
)
2230 struct winbind_cache
*cache
= get_cache(domain
);
2231 struct cache_entry
*centry
= NULL
;
2235 if (cache
->tdb
== NULL
) {
2236 return NT_STATUS_NOT_FOUND
;
2239 sid_string
= sid_string_tos(user_sid
);
2240 if (sid_string
== NULL
) {
2241 return NT_STATUS_NO_MEMORY
;
2244 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string
);
2245 TALLOC_FREE(sid_string
);
2246 if (centry
== NULL
) {
2247 return NT_STATUS_NOT_FOUND
;
2251 * If we have an access denied cache entry and a cached info3
2252 * in the samlogon cache then do a query. This will force the
2253 * rpc back end to return the info3 data.
2256 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
) &&
2257 netsamlogon_cache_have(user_sid
)) {
2258 DEBUG(10, ("query_user: cached access denied and have cached "
2260 domain
->last_status
= NT_STATUS_OK
;
2261 centry_free(centry
);
2262 return NT_STATUS_NOT_FOUND
;
2265 /* if status is not ok then this is a negative hit
2266 and the rest of the data doesn't matter */
2267 status
= centry
->status
;
2268 if (NT_STATUS_IS_OK(status
)) {
2269 info
->acct_name
= centry_string(centry
, mem_ctx
);
2270 info
->full_name
= centry_string(centry
, mem_ctx
);
2271 info
->homedir
= centry_string(centry
, mem_ctx
);
2272 info
->shell
= centry_string(centry
, mem_ctx
);
2273 info
->primary_gid
= centry_uint32(centry
);
2274 centry_sid(centry
, &info
->user_sid
);
2275 centry_sid(centry
, &info
->group_sid
);
2278 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2279 "%s\n", domain
->name
, nt_errstr(status
) ));
2281 centry_free(centry
);
2285 /* Lookup user information from a rid */
2286 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
2287 TALLOC_CTX
*mem_ctx
,
2288 const struct dom_sid
*user_sid
,
2289 struct wbint_userinfo
*info
)
2294 old_status
= domain
->online
;
2295 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2296 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2302 /* Return status value returned by seq number check */
2304 if (!NT_STATUS_IS_OK(domain
->last_status
))
2305 return domain
->last_status
;
2307 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2310 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
2312 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2313 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2314 if (!domain
->internal
&& old_status
) {
2315 set_domain_offline(domain
);
2317 if (!domain
->internal
&&
2320 NTSTATUS cache_status
;
2321 cache_status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2322 return cache_status
;
2326 refresh_sequence_number(domain
, false);
2327 if (!NT_STATUS_IS_OK(status
)) {
2330 wcache_save_user(domain
, status
, info
);
2335 NTSTATUS
wcache_lookup_usergroups(struct winbindd_domain
*domain
,
2336 TALLOC_CTX
*mem_ctx
,
2337 const struct dom_sid
*user_sid
,
2338 uint32_t *pnum_sids
,
2339 struct dom_sid
**psids
)
2341 struct winbind_cache
*cache
= get_cache(domain
);
2342 struct cache_entry
*centry
= NULL
;
2344 uint32_t i
, num_sids
;
2345 struct dom_sid
*sids
;
2348 if (cache
->tdb
== NULL
) {
2349 return NT_STATUS_NOT_FOUND
;
2352 centry
= wcache_fetch(cache
, domain
, "UG/%s",
2353 sid_to_fstring(sid_string
, user_sid
));
2354 if (centry
== NULL
) {
2355 return NT_STATUS_NOT_FOUND
;
2358 /* If we have an access denied cache entry and a cached info3 in the
2359 samlogon cache then do a query. This will force the rpc back end
2360 to return the info3 data. */
2362 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)
2363 && netsamlogon_cache_have(user_sid
)) {
2364 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2366 domain
->last_status
= NT_STATUS_OK
;
2367 centry_free(centry
);
2368 return NT_STATUS_NOT_FOUND
;
2371 num_sids
= centry_uint32(centry
);
2372 sids
= talloc_array(mem_ctx
, struct dom_sid
, num_sids
);
2374 centry_free(centry
);
2375 return NT_STATUS_NO_MEMORY
;
2378 for (i
=0; i
<num_sids
; i
++) {
2379 centry_sid(centry
, &sids
[i
]);
2382 status
= centry
->status
;
2384 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2385 "status: %s\n", domain
->name
, nt_errstr(status
)));
2387 centry_free(centry
);
2389 *pnum_sids
= num_sids
;
2394 /* Lookup groups a user is a member of. */
2395 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
2396 TALLOC_CTX
*mem_ctx
,
2397 const struct dom_sid
*user_sid
,
2398 uint32
*num_groups
, struct dom_sid
**user_gids
)
2400 struct cache_entry
*centry
= NULL
;
2406 old_status
= domain
->online
;
2407 status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2408 num_groups
, user_gids
);
2409 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2414 (*user_gids
) = NULL
;
2416 /* Return status value returned by seq number check */
2418 if (!NT_STATUS_IS_OK(domain
->last_status
))
2419 return domain
->last_status
;
2421 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2424 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
2426 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2427 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2428 if (!domain
->internal
&& old_status
) {
2429 set_domain_offline(domain
);
2431 if (!domain
->internal
&&
2434 NTSTATUS cache_status
;
2435 cache_status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2436 num_groups
, user_gids
);
2437 return cache_status
;
2440 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
2444 refresh_sequence_number(domain
, false);
2445 if (!NT_STATUS_IS_OK(status
)) {
2448 centry
= centry_start(domain
, status
);
2452 centry_put_uint32(centry
, *num_groups
);
2453 for (i
=0; i
<(*num_groups
); i
++) {
2454 centry_put_sid(centry
, &(*user_gids
)[i
]);
2457 centry_end(centry
, "UG/%s", sid_to_fstring(sid_string
, user_sid
));
2458 centry_free(centry
);
2464 static char *wcache_make_sidlist(TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2465 const struct dom_sid
*sids
)
2470 sidlist
= talloc_strdup(mem_ctx
, "");
2471 if (sidlist
== NULL
) {
2474 for (i
=0; i
<num_sids
; i
++) {
2476 sidlist
= talloc_asprintf_append_buffer(
2477 sidlist
, "/%s", sid_to_fstring(tmp
, &sids
[i
]));
2478 if (sidlist
== NULL
) {
2485 NTSTATUS
wcache_lookup_useraliases(struct winbindd_domain
*domain
,
2486 TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2487 const struct dom_sid
*sids
,
2488 uint32_t *pnum_aliases
, uint32_t **paliases
)
2490 struct winbind_cache
*cache
= get_cache(domain
);
2491 struct cache_entry
*centry
= NULL
;
2492 uint32_t num_aliases
;
2498 if (cache
->tdb
== NULL
) {
2499 return NT_STATUS_NOT_FOUND
;
2502 if (num_sids
== 0) {
2505 return NT_STATUS_OK
;
2508 /* We need to cache indexed by the whole list of SIDs, the aliases
2509 * resulting might come from any of the SIDs. */
2511 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2512 if (sidlist
== NULL
) {
2513 return NT_STATUS_NO_MEMORY
;
2516 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2517 TALLOC_FREE(sidlist
);
2518 if (centry
== NULL
) {
2519 return NT_STATUS_NOT_FOUND
;
2522 num_aliases
= centry_uint32(centry
);
2523 aliases
= talloc_array(mem_ctx
, uint32_t, num_aliases
);
2524 if (aliases
== NULL
) {
2525 centry_free(centry
);
2526 return NT_STATUS_NO_MEMORY
;
2529 for (i
=0; i
<num_aliases
; i
++) {
2530 aliases
[i
] = centry_uint32(centry
);
2533 status
= centry
->status
;
2535 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2536 "status %s\n", domain
->name
, nt_errstr(status
)));
2538 centry_free(centry
);
2540 *pnum_aliases
= num_aliases
;
2541 *paliases
= aliases
;
2546 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
2547 TALLOC_CTX
*mem_ctx
,
2548 uint32 num_sids
, const struct dom_sid
*sids
,
2549 uint32
*num_aliases
, uint32
**alias_rids
)
2551 struct cache_entry
*centry
= NULL
;
2557 old_status
= domain
->online
;
2558 status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
2559 num_aliases
, alias_rids
);
2560 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2565 (*alias_rids
) = NULL
;
2567 if (!NT_STATUS_IS_OK(domain
->last_status
))
2568 return domain
->last_status
;
2570 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2571 "for domain %s\n", domain
->name
));
2573 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2574 if (sidlist
== NULL
) {
2575 return NT_STATUS_NO_MEMORY
;
2578 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2580 num_aliases
, alias_rids
);
2582 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2583 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2584 if (!domain
->internal
&& old_status
) {
2585 set_domain_offline(domain
);
2587 if (!domain
->internal
&&
2590 NTSTATUS cache_status
;
2591 cache_status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
,
2592 sids
, num_aliases
, alias_rids
);
2593 return cache_status
;
2597 refresh_sequence_number(domain
, false);
2598 if (!NT_STATUS_IS_OK(status
)) {
2601 centry
= centry_start(domain
, status
);
2604 centry_put_uint32(centry
, *num_aliases
);
2605 for (i
=0; i
<(*num_aliases
); i
++)
2606 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2607 centry_end(centry
, "UA%s", sidlist
);
2608 centry_free(centry
);
2614 NTSTATUS
wcache_lookup_groupmem(struct winbindd_domain
*domain
,
2615 TALLOC_CTX
*mem_ctx
,
2616 const struct dom_sid
*group_sid
,
2617 uint32_t *num_names
,
2618 struct dom_sid
**sid_mem
, char ***names
,
2619 uint32_t **name_types
)
2621 struct winbind_cache
*cache
= get_cache(domain
);
2622 struct cache_entry
*centry
= NULL
;
2627 if (cache
->tdb
== NULL
) {
2628 return NT_STATUS_NOT_FOUND
;
2631 sid_string
= sid_string_tos(group_sid
);
2632 if (sid_string
== NULL
) {
2633 return NT_STATUS_NO_MEMORY
;
2636 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_string
);
2637 TALLOC_FREE(sid_string
);
2638 if (centry
== NULL
) {
2639 return NT_STATUS_NOT_FOUND
;
2646 *num_names
= centry_uint32(centry
);
2647 if (*num_names
== 0) {
2648 centry_free(centry
);
2649 return NT_STATUS_OK
;
2652 *sid_mem
= talloc_array(mem_ctx
, struct dom_sid
, *num_names
);
2653 *names
= talloc_array(mem_ctx
, char *, *num_names
);
2654 *name_types
= talloc_array(mem_ctx
, uint32
, *num_names
);
2656 if ((*sid_mem
== NULL
) || (*names
== NULL
) || (*name_types
== NULL
)) {
2657 TALLOC_FREE(*sid_mem
);
2658 TALLOC_FREE(*names
);
2659 TALLOC_FREE(*name_types
);
2660 centry_free(centry
);
2661 return NT_STATUS_NO_MEMORY
;
2664 for (i
=0; i
<(*num_names
); i
++) {
2665 centry_sid(centry
, &(*sid_mem
)[i
]);
2666 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2667 (*name_types
)[i
] = centry_uint32(centry
);
2670 status
= centry
->status
;
2672 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2673 "status: %s\n", domain
->name
, nt_errstr(status
)));
2675 centry_free(centry
);
2679 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
2680 TALLOC_CTX
*mem_ctx
,
2681 const struct dom_sid
*group_sid
,
2682 enum lsa_SidType type
,
2684 struct dom_sid
**sid_mem
, char ***names
,
2685 uint32
**name_types
)
2687 struct cache_entry
*centry
= NULL
;
2693 old_status
= domain
->online
;
2694 status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2695 sid_mem
, names
, name_types
);
2696 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2703 (*name_types
) = NULL
;
2705 /* Return status value returned by seq number check */
2707 if (!NT_STATUS_IS_OK(domain
->last_status
))
2708 return domain
->last_status
;
2710 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2713 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
,
2715 sid_mem
, names
, name_types
);
2717 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2718 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2719 if (!domain
->internal
&& old_status
) {
2720 set_domain_offline(domain
);
2722 if (!domain
->internal
&&
2725 NTSTATUS cache_status
;
2726 cache_status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
,
2727 num_names
, sid_mem
, names
,
2729 return cache_status
;
2733 refresh_sequence_number(domain
, false);
2734 if (!NT_STATUS_IS_OK(status
)) {
2737 centry
= centry_start(domain
, status
);
2740 centry_put_uint32(centry
, *num_names
);
2741 for (i
=0; i
<(*num_names
); i
++) {
2742 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2743 centry_put_string(centry
, (*names
)[i
]);
2744 centry_put_uint32(centry
, (*name_types
)[i
]);
2746 centry_end(centry
, "GM/%s", sid_to_fstring(sid_string
, group_sid
));
2747 centry_free(centry
);
2753 /* find the sequence number for a domain */
2754 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
2756 refresh_sequence_number(domain
, false);
2758 *seq
= domain
->sequence_number
;
2760 return NT_STATUS_OK
;
2763 /* enumerate trusted domains
2764 * (we need to have the list of trustdoms in the cache when we go offline) -
2766 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
2767 TALLOC_CTX
*mem_ctx
,
2768 struct netr_DomainTrustList
*trusts
)
2771 struct winbind_cache
*cache
;
2772 struct winbindd_tdc_domain
*dom_list
= NULL
;
2773 size_t num_domains
= 0;
2774 bool retval
= false;
2778 old_status
= domain
->online
;
2780 trusts
->array
= NULL
;
2782 cache
= get_cache(domain
);
2783 if (!cache
|| !cache
->tdb
) {
2787 if (domain
->online
) {
2791 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2792 if (!retval
|| !num_domains
|| !dom_list
) {
2793 TALLOC_FREE(dom_list
);
2798 trusts
->array
= TALLOC_ZERO_ARRAY(mem_ctx
, struct netr_DomainTrust
, num_domains
);
2799 if (!trusts
->array
) {
2800 TALLOC_FREE(dom_list
);
2801 return NT_STATUS_NO_MEMORY
;
2804 for (i
= 0; i
< num_domains
; i
++) {
2805 struct netr_DomainTrust
*trust
;
2806 struct dom_sid
*sid
;
2807 struct winbindd_domain
*dom
;
2809 dom
= find_domain_from_name_noinit(dom_list
[i
].domain_name
);
2810 if (dom
&& dom
->internal
) {
2814 trust
= &trusts
->array
[trusts
->count
];
2815 trust
->netbios_name
= talloc_strdup(trusts
->array
, dom_list
[i
].domain_name
);
2816 trust
->dns_name
= talloc_strdup(trusts
->array
, dom_list
[i
].dns_name
);
2817 sid
= talloc(trusts
->array
, struct dom_sid
);
2818 if (!trust
->netbios_name
|| !trust
->dns_name
||
2820 TALLOC_FREE(dom_list
);
2821 TALLOC_FREE(trusts
->array
);
2822 return NT_STATUS_NO_MEMORY
;
2825 trust
->trust_flags
= dom_list
[i
].trust_flags
;
2826 trust
->trust_attributes
= dom_list
[i
].trust_attribs
;
2827 trust
->trust_type
= dom_list
[i
].trust_type
;
2828 sid_copy(sid
, &dom_list
[i
].sid
);
2833 TALLOC_FREE(dom_list
);
2834 return NT_STATUS_OK
;
2837 /* Return status value returned by seq number check */
2839 if (!NT_STATUS_IS_OK(domain
->last_status
))
2840 return domain
->last_status
;
2842 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2845 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, trusts
);
2847 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2848 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2849 if (!domain
->internal
&& old_status
) {
2850 set_domain_offline(domain
);
2852 if (!domain
->internal
&&
2855 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2856 if (retval
&& num_domains
&& dom_list
) {
2857 TALLOC_FREE(trusts
->array
);
2859 goto do_fetch_cache
;
2863 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2864 * so that the generic centry handling still applies correctly -
2867 if (!NT_STATUS_IS_ERR(status
)) {
2868 status
= NT_STATUS_OK
;
2873 /* get lockout policy */
2874 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
2875 TALLOC_CTX
*mem_ctx
,
2876 struct samr_DomInfo12
*policy
)
2878 struct winbind_cache
*cache
= get_cache(domain
);
2879 struct cache_entry
*centry
= NULL
;
2883 old_status
= domain
->online
;
2887 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2893 policy
->lockout_duration
= centry_nttime(centry
);
2894 policy
->lockout_window
= centry_nttime(centry
);
2895 policy
->lockout_threshold
= centry_uint16(centry
);
2897 status
= centry
->status
;
2899 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2900 domain
->name
, nt_errstr(status
) ));
2902 centry_free(centry
);
2906 ZERO_STRUCTP(policy
);
2908 /* Return status value returned by seq number check */
2910 if (!NT_STATUS_IS_OK(domain
->last_status
))
2911 return domain
->last_status
;
2913 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2916 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2918 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2919 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2920 if (!domain
->internal
&& old_status
) {
2921 set_domain_offline(domain
);
2924 !domain
->internal
&&
2927 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2929 goto do_fetch_cache
;
2934 refresh_sequence_number(domain
, false);
2935 if (!NT_STATUS_IS_OK(status
)) {
2938 wcache_save_lockout_policy(domain
, status
, policy
);
2943 /* get password policy */
2944 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
2945 TALLOC_CTX
*mem_ctx
,
2946 struct samr_DomInfo1
*policy
)
2948 struct winbind_cache
*cache
= get_cache(domain
);
2949 struct cache_entry
*centry
= NULL
;
2953 old_status
= domain
->online
;
2957 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2963 policy
->min_password_length
= centry_uint16(centry
);
2964 policy
->password_history_length
= centry_uint16(centry
);
2965 policy
->password_properties
= centry_uint32(centry
);
2966 policy
->max_password_age
= centry_nttime(centry
);
2967 policy
->min_password_age
= centry_nttime(centry
);
2969 status
= centry
->status
;
2971 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2972 domain
->name
, nt_errstr(status
) ));
2974 centry_free(centry
);
2978 ZERO_STRUCTP(policy
);
2980 /* Return status value returned by seq number check */
2982 if (!NT_STATUS_IS_OK(domain
->last_status
))
2983 return domain
->last_status
;
2985 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2988 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
2990 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2991 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2992 if (!domain
->internal
&& old_status
) {
2993 set_domain_offline(domain
);
2996 !domain
->internal
&&
2999 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
3001 goto do_fetch_cache
;
3006 refresh_sequence_number(domain
, false);
3007 if (!NT_STATUS_IS_OK(status
)) {
3010 wcache_save_password_policy(domain
, status
, policy
);
3016 /* Invalidate cached user and group lists coherently */
3018 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3021 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
3022 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
3023 tdb_delete(the_tdb
, kbuf
);
3028 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3030 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
3031 const struct dom_sid
*sid
)
3033 fstring key_str
, sid_string
;
3034 struct winbind_cache
*cache
;
3036 /* dont clear cached U/SID and UG/SID entries when we want to logon
3039 if (lp_winbind_offline_logon()) {
3046 cache
= get_cache(domain
);
3052 /* Clear U/SID cache entry */
3053 fstr_sprintf(key_str
, "U/%s", sid_to_fstring(sid_string
, sid
));
3054 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3055 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3057 /* Clear UG/SID cache entry */
3058 fstr_sprintf(key_str
, "UG/%s", sid_to_fstring(sid_string
, sid
));
3059 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3060 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3062 /* Samba/winbindd never needs this. */
3063 netsamlogon_clear_cached_user(sid
);
3066 bool wcache_invalidate_cache(void)
3068 struct winbindd_domain
*domain
;
3070 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3071 struct winbind_cache
*cache
= get_cache(domain
);
3073 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3074 "entries for %s\n", domain
->name
));
3077 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3086 bool wcache_invalidate_cache_noinit(void)
3088 struct winbindd_domain
*domain
;
3090 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3091 struct winbind_cache
*cache
;
3093 /* Skip uninitialized domains. */
3094 if (!domain
->initialized
&& !domain
->internal
) {
3098 cache
= get_cache(domain
);
3100 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3101 "entries for %s\n", domain
->name
));
3104 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3106 * Flushing cache has nothing to with domains.
3107 * return here if we successfully flushed once.
3108 * To avoid unnecessary traversing the cache.
3119 bool init_wcache(void)
3121 if (wcache
== NULL
) {
3122 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
3123 ZERO_STRUCTP(wcache
);
3126 if (wcache
->tdb
!= NULL
)
3129 /* when working offline we must not clear the cache on restart */
3130 wcache
->tdb
= tdb_open_log(cache_path("winbindd_cache.tdb"),
3131 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3132 TDB_INCOMPATIBLE_HASH
|
3133 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3134 O_RDWR
|O_CREAT
, 0600);
3136 if (wcache
->tdb
== NULL
) {
3137 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3144 /************************************************************************
3145 This is called by the parent to initialize the cache file.
3146 We don't need sophisticated locking here as we know we're the
3148 ************************************************************************/
3150 bool initialize_winbindd_cache(void)
3152 bool cache_bad
= true;
3155 if (!init_wcache()) {
3156 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3160 /* Check version number. */
3161 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
3162 vers
== WINBINDD_CACHE_VERSION
) {
3167 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3168 "and re-creating with version number %d\n",
3169 WINBINDD_CACHE_VERSION
));
3171 tdb_close(wcache
->tdb
);
3174 if (unlink(cache_path("winbindd_cache.tdb")) == -1) {
3175 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3176 cache_path("winbindd_cache.tdb"),
3180 if (!init_wcache()) {
3181 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3182 "init_wcache failed.\n"));
3186 /* Write the version. */
3187 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
3188 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3189 tdb_errorstr(wcache
->tdb
) ));
3194 tdb_close(wcache
->tdb
);
3199 void close_winbindd_cache(void)
3205 tdb_close(wcache
->tdb
);
3210 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*sid
,
3211 char **domain_name
, char **name
,
3212 enum lsa_SidType
*type
)
3214 struct winbindd_domain
*domain
;
3217 domain
= find_lookup_domain_from_sid(sid
);
3218 if (domain
== NULL
) {
3221 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
3223 return NT_STATUS_IS_OK(status
);
3226 bool lookup_cached_name(const char *domain_name
,
3228 struct dom_sid
*sid
,
3229 enum lsa_SidType
*type
)
3231 struct winbindd_domain
*domain
;
3233 bool original_online_state
;
3235 domain
= find_lookup_domain_from_name(domain_name
);
3236 if (domain
== NULL
) {
3240 /* If we are doing a cached logon, temporarily set the domain
3241 offline so the cache won't expire the entry */
3243 original_online_state
= domain
->online
;
3244 domain
->online
= false;
3245 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
3246 domain
->online
= original_online_state
;
3248 return NT_STATUS_IS_OK(status
);
3251 void cache_name2sid(struct winbindd_domain
*domain
,
3252 const char *domain_name
, const char *name
,
3253 enum lsa_SidType type
, const struct dom_sid
*sid
)
3255 refresh_sequence_number(domain
, false);
3256 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
3261 * The original idea that this cache only contains centries has
3262 * been blurred - now other stuff gets put in here. Ensure we
3263 * ignore these things on cleanup.
3266 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
3267 TDB_DATA dbuf
, void *state
)
3269 struct cache_entry
*centry
;
3271 if (is_non_centry_key(kbuf
)) {
3275 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
3280 if (!NT_STATUS_IS_OK(centry
->status
)) {
3281 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
3282 tdb_delete(the_tdb
, kbuf
);
3285 centry_free(centry
);
3289 /* flush the cache */
3290 void wcache_flush_cache(void)
3295 tdb_close(wcache
->tdb
);
3298 if (!winbindd_use_cache()) {
3302 /* when working offline we must not clear the cache on restart */
3303 wcache
->tdb
= tdb_open_log(cache_path("winbindd_cache.tdb"),
3304 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3305 TDB_INCOMPATIBLE_HASH
|
3306 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3307 O_RDWR
|O_CREAT
, 0600);
3310 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3314 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
3316 DEBUG(10,("wcache_flush_cache success\n"));
3319 /* Count cached creds */
3321 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3324 int *cred_count
= (int*)state
;
3326 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3332 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
3334 struct winbind_cache
*cache
= get_cache(domain
);
3339 return NT_STATUS_INTERNAL_DB_ERROR
;
3342 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
3344 return NT_STATUS_OK
;
3348 struct cred_list
*prev
, *next
;
3353 static struct cred_list
*wcache_cred_list
;
3355 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3358 struct cred_list
*cred
;
3360 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3362 cred
= SMB_MALLOC_P(struct cred_list
);
3364 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3370 /* save a copy of the key */
3372 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
3373 DLIST_ADD(wcache_cred_list
, cred
);
3379 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
3381 struct winbind_cache
*cache
= get_cache(domain
);
3384 struct cred_list
*cred
, *oldest
= NULL
;
3387 return NT_STATUS_INTERNAL_DB_ERROR
;
3390 /* we possibly already have an entry */
3391 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
3393 fstring key_str
, tmp
;
3395 DEBUG(11,("we already have an entry, deleting that\n"));
3397 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
3399 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3401 return NT_STATUS_OK
;
3404 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
3406 return NT_STATUS_OK
;
3407 } else if ((ret
== -1) || (wcache_cred_list
== NULL
)) {
3408 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3411 ZERO_STRUCTP(oldest
);
3413 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
3418 data
= tdb_fetch(cache
->tdb
, string_tdb_data(cred
->name
));
3420 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3422 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3426 t
= IVAL(data
.dptr
, 0);
3427 SAFE_FREE(data
.dptr
);
3430 oldest
= SMB_MALLOC_P(struct cred_list
);
3431 if (oldest
== NULL
) {
3432 status
= NT_STATUS_NO_MEMORY
;
3436 fstrcpy(oldest
->name
, cred
->name
);
3437 oldest
->created
= t
;
3441 if (t
< oldest
->created
) {
3442 fstrcpy(oldest
->name
, cred
->name
);
3443 oldest
->created
= t
;
3447 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3448 status
= NT_STATUS_OK
;
3450 status
= NT_STATUS_UNSUCCESSFUL
;
3453 SAFE_FREE(wcache_cred_list
);
3459 /* Change the global online/offline state. */
3460 bool set_global_winbindd_state_offline(void)
3464 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3466 /* Only go offline if someone has created
3467 the key "WINBINDD_OFFLINE" in the cache tdb. */
3469 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3470 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3474 if (!lp_winbind_offline_logon()) {
3475 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3479 if (global_winbindd_offline_state
) {
3480 /* Already offline. */
3484 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
3486 if (!data
.dptr
|| data
.dsize
!= 4) {
3487 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3488 SAFE_FREE(data
.dptr
);
3491 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3492 global_winbindd_offline_state
= true;
3493 SAFE_FREE(data
.dptr
);
3498 void set_global_winbindd_state_online(void)
3500 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3502 if (!lp_winbind_offline_logon()) {
3503 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3507 if (!global_winbindd_offline_state
) {
3508 /* Already online. */
3511 global_winbindd_offline_state
= false;
3517 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3518 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3521 bool get_global_winbindd_state_offline(void)
3523 return global_winbindd_offline_state
;
3526 /***********************************************************************
3527 Validate functions for all possible cache tdb keys.
3528 ***********************************************************************/
3530 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3531 struct tdb_validation_status
*state
)
3533 struct cache_entry
*centry
;
3535 centry
= SMB_XMALLOC_P(struct cache_entry
);
3536 centry
->data
= (unsigned char *)memdup(data
.dptr
, data
.dsize
);
3537 if (!centry
->data
) {
3541 centry
->len
= data
.dsize
;
3544 if (centry
->len
< 16) {
3545 /* huh? corrupt cache? */
3546 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3547 "(len < 16) ?\n", kstr
));
3548 centry_free(centry
);
3549 state
->bad_entry
= true;
3550 state
->success
= false;
3554 centry
->status
= NT_STATUS(centry_uint32(centry
));
3555 centry
->sequence_number
= centry_uint32(centry
);
3556 centry
->timeout
= centry_uint64_t(centry
);
3560 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3561 struct tdb_validation_status
*state
)
3563 if (dbuf
.dsize
!= 8) {
3564 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3565 keystr
, (unsigned int)dbuf
.dsize
));
3566 state
->bad_entry
= true;
3572 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3573 struct tdb_validation_status
*state
)
3575 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3580 (void)centry_uint32(centry
);
3581 if (NT_STATUS_IS_OK(centry
->status
)) {
3583 (void)centry_sid(centry
, &sid
);
3586 centry_free(centry
);
3588 if (!(state
->success
)) {
3591 DEBUG(10,("validate_ns: %s ok\n", keystr
));
3595 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3596 struct tdb_validation_status
*state
)
3598 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3603 if (NT_STATUS_IS_OK(centry
->status
)) {
3604 (void)centry_uint32(centry
);
3605 (void)centry_string(centry
, mem_ctx
);
3606 (void)centry_string(centry
, mem_ctx
);
3609 centry_free(centry
);
3611 if (!(state
->success
)) {
3614 DEBUG(10,("validate_sn: %s ok\n", keystr
));
3618 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3619 struct tdb_validation_status
*state
)
3621 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3628 (void)centry_string(centry
, mem_ctx
);
3629 (void)centry_string(centry
, mem_ctx
);
3630 (void)centry_string(centry
, mem_ctx
);
3631 (void)centry_string(centry
, mem_ctx
);
3632 (void)centry_uint32(centry
);
3633 (void)centry_sid(centry
, &sid
);
3634 (void)centry_sid(centry
, &sid
);
3636 centry_free(centry
);
3638 if (!(state
->success
)) {
3641 DEBUG(10,("validate_u: %s ok\n", keystr
));
3645 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3646 struct tdb_validation_status
*state
)
3648 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3654 (void)centry_nttime(centry
);
3655 (void)centry_nttime(centry
);
3656 (void)centry_uint16(centry
);
3658 centry_free(centry
);
3660 if (!(state
->success
)) {
3663 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3667 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3668 struct tdb_validation_status
*state
)
3670 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3676 (void)centry_uint16(centry
);
3677 (void)centry_uint16(centry
);
3678 (void)centry_uint32(centry
);
3679 (void)centry_nttime(centry
);
3680 (void)centry_nttime(centry
);
3682 centry_free(centry
);
3684 if (!(state
->success
)) {
3687 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3691 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3692 struct tdb_validation_status
*state
)
3694 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3700 (void)centry_time(centry
);
3701 (void)centry_hash16(centry
, mem_ctx
);
3703 /* We only have 17 bytes more data in the salted cred case. */
3704 if (centry
->len
- centry
->ofs
== 17) {
3705 (void)centry_hash16(centry
, mem_ctx
);
3708 centry_free(centry
);
3710 if (!(state
->success
)) {
3713 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3717 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3718 struct tdb_validation_status
*state
)
3720 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3721 int32 num_entries
, i
;
3727 num_entries
= (int32
)centry_uint32(centry
);
3729 for (i
=0; i
< num_entries
; i
++) {
3731 (void)centry_string(centry
, mem_ctx
);
3732 (void)centry_string(centry
, mem_ctx
);
3733 (void)centry_string(centry
, mem_ctx
);
3734 (void)centry_string(centry
, mem_ctx
);
3735 (void)centry_sid(centry
, &sid
);
3736 (void)centry_sid(centry
, &sid
);
3739 centry_free(centry
);
3741 if (!(state
->success
)) {
3744 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3748 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3749 struct tdb_validation_status
*state
)
3751 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3752 int32 num_entries
, i
;
3758 num_entries
= centry_uint32(centry
);
3760 for (i
=0; i
< num_entries
; i
++) {
3761 (void)centry_string(centry
, mem_ctx
);
3762 (void)centry_string(centry
, mem_ctx
);
3763 (void)centry_uint32(centry
);
3766 centry_free(centry
);
3768 if (!(state
->success
)) {
3771 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3775 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3776 struct tdb_validation_status
*state
)
3778 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3779 int32 num_groups
, i
;
3785 num_groups
= centry_uint32(centry
);
3787 for (i
=0; i
< num_groups
; i
++) {
3789 centry_sid(centry
, &sid
);
3792 centry_free(centry
);
3794 if (!(state
->success
)) {
3797 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3801 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3802 struct tdb_validation_status
*state
)
3804 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3805 int32 num_aliases
, i
;
3811 num_aliases
= centry_uint32(centry
);
3813 for (i
=0; i
< num_aliases
; i
++) {
3814 (void)centry_uint32(centry
);
3817 centry_free(centry
);
3819 if (!(state
->success
)) {
3822 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3826 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3827 struct tdb_validation_status
*state
)
3829 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3836 num_names
= centry_uint32(centry
);
3838 for (i
=0; i
< num_names
; i
++) {
3840 centry_sid(centry
, &sid
);
3841 (void)centry_string(centry
, mem_ctx
);
3842 (void)centry_uint32(centry
);
3845 centry_free(centry
);
3847 if (!(state
->success
)) {
3850 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3854 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3855 struct tdb_validation_status
*state
)
3857 /* Can't say anything about this other than must be nonzero. */
3858 if (dbuf
.dsize
== 0) {
3859 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3861 state
->bad_entry
= true;
3862 state
->success
= false;
3866 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3870 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3871 struct tdb_validation_status
*state
)
3873 /* Can't say anything about this other than must be nonzero. */
3874 if (dbuf
.dsize
== 0) {
3875 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3877 state
->bad_entry
= true;
3878 state
->success
= false;
3882 DEBUG(10,("validate_de: %s ok\n", keystr
));
3886 static int validate_pwinfo(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3887 TDB_DATA dbuf
, struct tdb_validation_status
*state
)
3889 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3895 (void)centry_string(centry
, mem_ctx
);
3896 (void)centry_string(centry
, mem_ctx
);
3897 (void)centry_string(centry
, mem_ctx
);
3898 (void)centry_uint32(centry
);
3900 centry_free(centry
);
3902 if (!(state
->success
)) {
3905 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3909 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3911 struct tdb_validation_status
*state
)
3913 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3919 (void)centry_string( centry
, mem_ctx
);
3921 centry_free(centry
);
3923 if (!(state
->success
)) {
3926 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3930 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3932 struct tdb_validation_status
*state
)
3934 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3940 (void)centry_string( centry
, mem_ctx
);
3942 centry_free(centry
);
3944 if (!(state
->success
)) {
3947 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3951 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3953 struct tdb_validation_status
*state
)
3955 if (dbuf
.dsize
== 0) {
3956 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3957 "key %s (len ==0) ?\n", keystr
));
3958 state
->bad_entry
= true;
3959 state
->success
= false;
3963 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3964 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3968 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3969 struct tdb_validation_status
*state
)
3971 if (dbuf
.dsize
!= 4) {
3972 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3973 keystr
, (unsigned int)dbuf
.dsize
));
3974 state
->bad_entry
= true;
3975 state
->success
= false;
3978 DEBUG(10,("validate_offline: %s ok\n", keystr
));
3982 static int validate_ndr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3983 struct tdb_validation_status
*state
)
3986 * Ignore validation for now. The proper way to do this is with a
3987 * checksum. Just pure parsing does not really catch much.
3992 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3993 struct tdb_validation_status
*state
)
3995 if (dbuf
.dsize
!= 4) {
3996 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3997 "key %s (len %u != 4) ?\n",
3998 keystr
, (unsigned int)dbuf
.dsize
));
3999 state
->bad_entry
= true;
4000 state
->success
= false;
4004 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
4008 /***********************************************************************
4009 A list of all possible cache tdb keys with associated validation
4011 ***********************************************************************/
4013 struct key_val_struct
{
4014 const char *keyname
;
4015 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
4017 {"SEQNUM/", validate_seqnum
},
4018 {"NS/", validate_ns
},
4019 {"SN/", validate_sn
},
4021 {"LOC_POL/", validate_loc_pol
},
4022 {"PWD_POL/", validate_pwd_pol
},
4023 {"CRED/", validate_cred
},
4024 {"UL/", validate_ul
},
4025 {"GL/", validate_gl
},
4026 {"UG/", validate_ug
},
4027 {"UA", validate_ua
},
4028 {"GM/", validate_gm
},
4029 {"DR/", validate_dr
},
4030 {"DE/", validate_de
},
4031 {"NSS/PWINFO/", validate_pwinfo
},
4032 {"TRUSTDOMCACHE/", validate_trustdomcache
},
4033 {"NSS/NA/", validate_nss_na
},
4034 {"NSS/AN/", validate_nss_an
},
4035 {"WINBINDD_OFFLINE", validate_offline
},
4036 {"NDR/", validate_ndr
},
4037 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
4041 /***********************************************************************
4042 Function to look at every entry in the tdb and validate it as far as
4044 ***********************************************************************/
4046 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
4049 unsigned int max_key_len
= 1024;
4050 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
4052 /* Paranoia check. */
4053 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0) {
4054 max_key_len
= 1024 * 1024;
4056 if (kbuf
.dsize
> max_key_len
) {
4057 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4059 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
4063 for (i
= 0; key_val
[i
].keyname
; i
++) {
4064 size_t namelen
= strlen(key_val
[i
].keyname
);
4065 if (kbuf
.dsize
>= namelen
&& (
4066 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
4067 TALLOC_CTX
*mem_ctx
;
4071 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
4075 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
4076 keystr
[kbuf
.dsize
] = '\0';
4078 mem_ctx
= talloc_init("validate_ctx");
4084 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
4088 talloc_destroy(mem_ctx
);
4093 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4094 dump_data(0, (uint8
*)kbuf
.dptr
, kbuf
.dsize
);
4095 DEBUG(0,("data :\n"));
4096 dump_data(0, (uint8
*)dbuf
.dptr
, dbuf
.dsize
);
4097 v_state
->unknown_key
= true;
4098 v_state
->success
= false;
4099 return 1; /* terminate. */
4102 static void validate_panic(const char *const why
)
4104 DEBUG(0,("validating cache: would panic %s\n", why
));
4105 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4109 static int wbcache_update_centry_fn(TDB_CONTEXT
*tdb
,
4117 if (is_non_centry_key(key
)) {
4121 if (data
.dptr
== NULL
|| data
.dsize
== 0) {
4122 if (tdb_delete(tdb
, key
) < 0) {
4123 DEBUG(0, ("tdb_delete for [%s] failed!\n",
4129 /* add timeout to blob (uint64_t) */
4130 blob
.dsize
= data
.dsize
+ 8;
4132 blob
.dptr
= SMB_XMALLOC_ARRAY(uint8_t, blob
.dsize
);
4133 if (blob
.dptr
== NULL
) {
4136 memset(blob
.dptr
, 0, blob
.dsize
);
4138 /* copy status and seqnum */
4139 memcpy(blob
.dptr
, data
.dptr
, 8);
4142 ctimeout
= lp_winbind_cache_time() + time(NULL
);
4143 SBVAL(blob
.dptr
, 8, ctimeout
);
4146 memcpy(blob
.dptr
+ 16, data
.dptr
+ 8, data
.dsize
- 8);
4148 if (tdb_store(tdb
, key
, blob
, TDB_REPLACE
) < 0) {
4149 DEBUG(0, ("tdb_store to update [%s] failed!\n",
4151 SAFE_FREE(blob
.dptr
);
4155 SAFE_FREE(blob
.dptr
);
4159 static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT
*tdb
)
4163 DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
4165 rc
= tdb_traverse(tdb
, wbcache_update_centry_fn
, NULL
);
4173 /***********************************************************************
4174 Try and validate every entry in the winbindd cache. If we fail here,
4175 delete the cache tdb and return non-zero.
4176 ***********************************************************************/
4178 int winbindd_validate_cache(void)
4181 const char *tdb_path
= cache_path("winbindd_cache.tdb");
4182 TDB_CONTEXT
*tdb
= NULL
;
4186 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4187 smb_panic_fn
= validate_panic
;
4189 tdb
= tdb_open_log(tdb_path
,
4190 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
4191 TDB_INCOMPATIBLE_HASH
|
4192 ( lp_winbind_offline_logon()
4194 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
4198 DEBUG(0, ("winbindd_validate_cache: "
4199 "error opening/initializing tdb\n"));
4203 /* Version check and upgrade code. */
4204 if (!tdb_fetch_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers_id
)) {
4205 DEBUG(10, ("Fresh database\n"));
4206 tdb_store_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
);
4207 vers_id
= WINBINDD_CACHE_VERSION
;
4210 if (vers_id
!= WINBINDD_CACHE_VERSION
) {
4211 if (vers_id
== WINBINDD_CACHE_VER1
) {
4212 ok
= wbcache_upgrade_v1_to_v2(tdb
);
4214 DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
4219 tdb_store_uint32(tdb
,
4220 WINBINDD_CACHE_VERSION_KEYSTR
,
4221 WINBINDD_CACHE_VERSION
);
4222 vers_id
= WINBINDD_CACHE_VER2
;
4228 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
4231 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4232 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
4237 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4238 smb_panic_fn
= smb_panic
;
4242 /***********************************************************************
4243 Try and validate every entry in the winbindd cache.
4244 ***********************************************************************/
4246 int winbindd_validate_cache_nobackup(void)
4249 const char *tdb_path
= cache_path("winbindd_cache.tdb");
4251 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4252 smb_panic_fn
= validate_panic
;
4255 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
4256 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
4258 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
4262 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4266 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4268 smb_panic_fn
= smb_panic
;
4272 bool winbindd_cache_validate_and_initialize(void)
4274 close_winbindd_cache();
4276 if (lp_winbind_offline_logon()) {
4277 if (winbindd_validate_cache() < 0) {
4278 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4279 "could be restored.\n"));
4283 return initialize_winbindd_cache();
4286 /*********************************************************************
4287 ********************************************************************/
4289 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
4290 struct winbindd_tdc_domain
**domains
,
4291 size_t *num_domains
)
4293 struct winbindd_tdc_domain
*list
= NULL
;
4296 bool set_only
= false;
4298 /* don't allow duplicates */
4303 for ( i
=0; i
< (*num_domains
); i
++ ) {
4304 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
4305 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4316 list
= TALLOC_ARRAY( NULL
, struct winbindd_tdc_domain
, 1 );
4319 list
= TALLOC_REALLOC_ARRAY( *domains
, *domains
,
4320 struct winbindd_tdc_domain
,
4325 ZERO_STRUCT( list
[idx
] );
4331 list
[idx
].domain_name
= talloc_strdup( list
, new_dom
->name
);
4332 list
[idx
].dns_name
= talloc_strdup( list
, new_dom
->alt_name
);
4334 if ( !is_null_sid( &new_dom
->sid
) ) {
4335 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
4337 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
4340 if ( new_dom
->domain_flags
!= 0x0 )
4341 list
[idx
].trust_flags
= new_dom
->domain_flags
;
4343 if ( new_dom
->domain_type
!= 0x0 )
4344 list
[idx
].trust_type
= new_dom
->domain_type
;
4346 if ( new_dom
->domain_trust_attribs
!= 0x0 )
4347 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
4351 *num_domains
= idx
+ 1;
4357 /*********************************************************************
4358 ********************************************************************/
4360 static TDB_DATA
make_tdc_key( const char *domain_name
)
4362 char *keystr
= NULL
;
4363 TDB_DATA key
= { NULL
, 0 };
4365 if ( !domain_name
) {
4366 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4370 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
4373 key
= string_term_tdb_data(keystr
);
4378 /*********************************************************************
4379 ********************************************************************/
4381 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
4383 unsigned char **buf
)
4385 unsigned char *buffer
= NULL
;
4390 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4398 /* Store the number of array items first */
4399 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
4402 /* now pack each domain trust record */
4403 for ( i
=0; i
<num_domains
; i
++ ) {
4408 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4409 domains
[i
].domain_name
,
4410 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
4413 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
4414 domains
[i
].domain_name
,
4415 domains
[i
].dns_name
,
4416 sid_to_fstring(tmp
, &domains
[i
].sid
),
4417 domains
[i
].trust_flags
,
4418 domains
[i
].trust_attribs
,
4419 domains
[i
].trust_type
);
4422 if ( buflen
< len
) {
4424 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
4425 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4439 /*********************************************************************
4440 ********************************************************************/
4442 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
4443 struct winbindd_tdc_domain
**domains
)
4445 fstring domain_name
, dns_name
, sid_string
;
4446 uint32 type
, attribs
, flags
;
4450 struct winbindd_tdc_domain
*list
= NULL
;
4452 /* get the number of domains */
4453 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
4455 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4459 list
= TALLOC_ARRAY( NULL
, struct winbindd_tdc_domain
, num_domains
);
4461 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4465 for ( i
=0; i
<num_domains
; i
++ ) {
4466 len
+= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
4475 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4476 TALLOC_FREE( list
);
4480 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4481 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4482 domain_name
, dns_name
, sid_string
,
4483 flags
, attribs
, type
));
4485 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
4486 list
[i
].dns_name
= talloc_strdup( list
, dns_name
);
4487 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
4488 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4491 list
[i
].trust_flags
= flags
;
4492 list
[i
].trust_attribs
= attribs
;
4493 list
[i
].trust_type
= type
;
4501 /*********************************************************************
4502 ********************************************************************/
4504 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
4506 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4507 TDB_DATA data
= { NULL
, 0 };
4513 /* See if we were asked to delete the cache entry */
4516 ret
= tdb_delete( wcache
->tdb
, key
);
4520 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4527 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4530 SAFE_FREE( data
.dptr
);
4531 SAFE_FREE( key
.dptr
);
4533 return ( ret
!= -1 );
4536 /*********************************************************************
4537 ********************************************************************/
4539 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4541 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4542 TDB_DATA data
= { NULL
, 0 };
4550 data
= tdb_fetch( wcache
->tdb
, key
);
4552 SAFE_FREE( key
.dptr
);
4557 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4559 SAFE_FREE( data
.dptr
);
4567 /*********************************************************************
4568 ********************************************************************/
4570 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4572 struct winbindd_tdc_domain
*dom_list
= NULL
;
4573 size_t num_domains
= 0;
4576 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4577 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4578 domain
->name
, domain
->alt_name
,
4579 sid_string_dbg(&domain
->sid
),
4580 domain
->domain_flags
,
4581 domain
->domain_trust_attribs
,
4582 domain
->domain_type
));
4584 if ( !init_wcache() ) {
4588 /* fetch the list */
4590 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4592 /* add the new domain */
4594 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4598 /* pack the domain */
4600 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4608 TALLOC_FREE( dom_list
);
4613 /*********************************************************************
4614 ********************************************************************/
4616 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4618 struct winbindd_tdc_domain
*dom_list
= NULL
;
4619 size_t num_domains
= 0;
4621 struct winbindd_tdc_domain
*d
= NULL
;
4623 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4625 if ( !init_wcache() ) {
4629 /* fetch the list */
4631 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4633 for ( i
=0; i
<num_domains
; i
++ ) {
4634 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4635 strequal(name
, dom_list
[i
].dns_name
) )
4637 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4640 d
= TALLOC_P( ctx
, struct winbindd_tdc_domain
);
4644 d
->domain_name
= talloc_strdup( d
, dom_list
[i
].domain_name
);
4645 d
->dns_name
= talloc_strdup( d
, dom_list
[i
].dns_name
);
4646 sid_copy( &d
->sid
, &dom_list
[i
].sid
);
4647 d
->trust_flags
= dom_list
[i
].trust_flags
;
4648 d
->trust_type
= dom_list
[i
].trust_type
;
4649 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
4655 TALLOC_FREE( dom_list
);
4660 /*********************************************************************
4661 ********************************************************************/
4663 struct winbindd_tdc_domain
*
4664 wcache_tdc_fetch_domainbysid(TALLOC_CTX
*ctx
,
4665 const struct dom_sid
*sid
)
4667 struct winbindd_tdc_domain
*dom_list
= NULL
;
4668 size_t num_domains
= 0;
4670 struct winbindd_tdc_domain
*d
= NULL
;
4672 DEBUG(10,("wcache_tdc_fetch_domainbysid: Searching for domain %s\n",
4673 sid_string_dbg(sid
)));
4675 if (!init_wcache()) {
4679 /* fetch the list */
4681 wcache_tdc_fetch_list(&dom_list
, &num_domains
);
4683 for (i
= 0; i
<num_domains
; i
++) {
4684 if (sid_equal(sid
, &(dom_list
[i
].sid
))) {
4685 DEBUG(10, ("wcache_tdc_fetch_domainbysid: "
4686 "Found domain %s for SID %s\n",
4687 dom_list
[i
].domain_name
,
4688 sid_string_dbg(sid
)));
4690 d
= TALLOC_P(ctx
, struct winbindd_tdc_domain
);
4694 d
->domain_name
= talloc_strdup(d
,
4695 dom_list
[i
].domain_name
);
4697 d
->dns_name
= talloc_strdup(d
, dom_list
[i
].dns_name
);
4698 sid_copy(&d
->sid
, &dom_list
[i
].sid
);
4699 d
->trust_flags
= dom_list
[i
].trust_flags
;
4700 d
->trust_type
= dom_list
[i
].trust_type
;
4701 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
4707 TALLOC_FREE(dom_list
);
4713 /*********************************************************************
4714 ********************************************************************/
4716 void wcache_tdc_clear( void )
4718 if ( !init_wcache() )
4721 wcache_tdc_store_list( NULL
, 0 );
4727 /*********************************************************************
4728 ********************************************************************/
4730 static void wcache_save_user_pwinfo(struct winbindd_domain
*domain
,
4732 const struct dom_sid
*user_sid
,
4733 const char *homedir
,
4738 struct cache_entry
*centry
;
4741 if ( (centry
= centry_start(domain
, status
)) == NULL
)
4744 centry_put_string( centry
, homedir
);
4745 centry_put_string( centry
, shell
);
4746 centry_put_string( centry
, gecos
);
4747 centry_put_uint32( centry
, gid
);
4749 centry_end(centry
, "NSS/PWINFO/%s", sid_to_fstring(tmp
, user_sid
) );
4751 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid
) ));
4753 centry_free(centry
);
4758 NTSTATUS
nss_get_info_cached( struct winbindd_domain
*domain
,
4759 const struct dom_sid
*user_sid
,
4761 const char **homedir
, const char **shell
,
4762 const char **gecos
, gid_t
*p_gid
)
4764 struct winbind_cache
*cache
= get_cache(domain
);
4765 struct cache_entry
*centry
= NULL
;
4772 centry
= wcache_fetch(cache
, domain
, "NSS/PWINFO/%s",
4773 sid_to_fstring(tmp
, user_sid
));
4778 *homedir
= centry_string( centry
, ctx
);
4779 *shell
= centry_string( centry
, ctx
);
4780 *gecos
= centry_string( centry
, ctx
);
4781 *p_gid
= centry_uint32( centry
);
4783 centry_free(centry
);
4785 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4786 sid_string_dbg(user_sid
)));
4788 return NT_STATUS_OK
;
4792 nt_status
= nss_get_info( domain
->name
, user_sid
, ctx
,
4793 homedir
, shell
, gecos
, p_gid
);
4795 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status
)));
4797 if ( NT_STATUS_IS_OK(nt_status
) ) {
4798 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir
));
4799 DEBUGADD(10, ("\tshell = '%s'\n", *shell
));
4800 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos
));
4801 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid
));
4803 wcache_save_user_pwinfo( domain
, nt_status
, user_sid
,
4804 *homedir
, *shell
, *gecos
, *p_gid
);
4807 if ( NT_STATUS_EQUAL( nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
4808 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4810 set_domain_offline( domain
);
4818 /* the cache backend methods are exposed via this structure */
4819 struct winbindd_methods cache_methods
= {
4837 static bool wcache_ndr_key(TALLOC_CTX
*mem_ctx
, char *domain_name
,
4838 uint32_t opnum
, const DATA_BLOB
*req
,
4844 key
= talloc_asprintf(mem_ctx
, "NDR/%s/%d/", domain_name
, (int)opnum
);
4848 keylen
= talloc_get_size(key
) - 1;
4850 key
= talloc_realloc(mem_ctx
, key
, char, keylen
+ req
->length
);
4854 memcpy(key
+ keylen
, req
->data
, req
->length
);
4856 pkey
->dptr
= (uint8_t *)key
;
4857 pkey
->dsize
= talloc_get_size(key
);
4861 static bool wcache_opnum_cacheable(uint32_t opnum
)
4864 case NDR_WBINT_PING
:
4865 case NDR_WBINT_QUERYSEQUENCENUMBER
:
4866 case NDR_WBINT_ALLOCATEUID
:
4867 case NDR_WBINT_ALLOCATEGID
:
4868 case NDR_WBINT_CHECKMACHINEACCOUNT
:
4869 case NDR_WBINT_CHANGEMACHINEACCOUNT
:
4870 case NDR_WBINT_PINGDC
:
4876 bool wcache_fetch_ndr(TALLOC_CTX
*mem_ctx
, struct winbindd_domain
*domain
,
4877 uint32_t opnum
, const DATA_BLOB
*req
, DATA_BLOB
*resp
)
4882 if (!wcache_opnum_cacheable(opnum
) ||
4883 is_my_own_sam_domain(domain
) ||
4884 is_builtin_domain(domain
)) {
4888 if (wcache
->tdb
== NULL
) {
4892 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4895 data
= tdb_fetch(wcache
->tdb
, key
);
4896 TALLOC_FREE(key
.dptr
);
4898 if (data
.dptr
== NULL
) {
4901 if (data
.dsize
< 12) {
4905 if (!is_domain_offline(domain
)) {
4906 uint32_t entry_seqnum
, dom_seqnum
, last_check
;
4907 uint64_t entry_timeout
;
4909 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
,
4913 entry_seqnum
= IVAL(data
.dptr
, 0);
4914 if (entry_seqnum
!= dom_seqnum
) {
4915 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4916 (int)entry_seqnum
));
4919 entry_timeout
= BVAL(data
.dptr
, 4);
4920 if (time(NULL
) > entry_timeout
) {
4921 DEBUG(10, ("Entry has timed out\n"));
4926 resp
->data
= (uint8_t *)talloc_memdup(mem_ctx
, data
.dptr
+ 12,
4928 if (resp
->data
== NULL
) {
4929 DEBUG(10, ("talloc failed\n"));
4932 resp
->length
= data
.dsize
- 12;
4936 SAFE_FREE(data
.dptr
);
4940 void wcache_store_ndr(struct winbindd_domain
*domain
, uint32_t opnum
,
4941 const DATA_BLOB
*req
, const DATA_BLOB
*resp
)
4944 uint32_t dom_seqnum
, last_check
;
4947 if (!wcache_opnum_cacheable(opnum
) ||
4948 is_my_own_sam_domain(domain
) ||
4949 is_builtin_domain(domain
)) {
4953 if (wcache
->tdb
== NULL
) {
4957 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
, &last_check
)) {
4958 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4963 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4967 timeout
= time(NULL
) + lp_winbind_cache_time();
4969 data
.dsize
= resp
->length
+ 12;
4970 data
.dptr
= talloc_array(key
.dptr
, uint8_t, data
.dsize
);
4971 if (data
.dptr
== NULL
) {
4975 SIVAL(data
.dptr
, 0, dom_seqnum
);
4976 SBVAL(data
.dptr
, 4, timeout
);
4977 memcpy(data
.dptr
+ 12, resp
->data
, resp
->length
);
4979 tdb_store(wcache
->tdb
, key
, data
, 0);
4982 TALLOC_FREE(key
.dptr
);