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/>.
28 #include "tdb_validate.h"
29 #include "../libcli/auth/libcli_auth.h"
30 #include "../librpc/gen_ndr/ndr_wbint.h"
35 #define DBGC_CLASS DBGC_WINBIND
37 #define WINBINDD_CACHE_VERSION 1
38 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
40 extern struct winbindd_methods reconnect_methods
;
42 extern struct winbindd_methods ads_methods
;
44 extern struct winbindd_methods builtin_passdb_methods
;
45 extern struct winbindd_methods sam_passdb_methods
;
48 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
49 * Here are the list of entry types that are *not* stored
50 * as form struct cache_entry in the cache.
53 static const char *non_centry_keys
[] = {
58 WINBINDD_CACHE_VERSION_KEYSTR
,
62 /************************************************************************
63 Is this key a non-centry type ?
64 ************************************************************************/
66 static bool is_non_centry_key(TDB_DATA kbuf
)
70 if (kbuf
.dptr
== NULL
|| kbuf
.dsize
== 0) {
73 for (i
= 0; non_centry_keys
[i
] != NULL
; i
++) {
74 size_t namelen
= strlen(non_centry_keys
[i
]);
75 if (kbuf
.dsize
< namelen
) {
78 if (strncmp(non_centry_keys
[i
], (const char *)kbuf
.dptr
, namelen
) == 0) {
85 /* Global online/offline state - False when online. winbindd starts up online
86 and sets this to true if the first query fails and there's an entry in
87 the cache tdb telling us to stay offline. */
89 static bool global_winbindd_offline_state
;
91 struct winbind_cache
{
97 uint32 sequence_number
;
102 void (*smb_panic_fn
)(const char *const why
) = smb_panic
;
104 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
106 static struct winbind_cache
*wcache
;
108 void winbindd_check_cache_size(time_t t
)
110 static time_t last_check_time
;
113 if (last_check_time
== (time_t)0)
116 if (t
- last_check_time
< 60 && t
- last_check_time
> 0)
119 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
120 DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
124 if (fstat(tdb_fd(wcache
->tdb
), &st
) == -1) {
125 DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno
) ));
129 if (st
.st_size
> WINBINDD_MAX_CACHE_SIZE
) {
130 DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
131 (unsigned long)st
.st_size
,
132 (unsigned long)WINBINDD_MAX_CACHE_SIZE
));
133 wcache_flush_cache();
137 /* get the winbind_cache structure */
138 static struct winbind_cache
*get_cache(struct winbindd_domain
*domain
)
140 struct winbind_cache
*ret
= wcache
;
142 /* We have to know what type of domain we are dealing with first. */
144 if (domain
->internal
) {
145 domain
->backend
= &builtin_passdb_methods
;
146 domain
->initialized
= True
;
149 if (strequal(domain
->name
, get_global_sam_name()) &&
150 sid_equal(&domain
->sid
, get_global_sam_sid())) {
151 domain
->backend
= &sam_passdb_methods
;
152 domain
->initialized
= True
;
155 if ( !domain
->initialized
) {
156 init_dc_connection( domain
);
160 OK. listen up becasue I'm only going to say this once.
161 We have the following scenarios to consider
162 (a) trusted AD domains on a Samba DC,
163 (b) trusted AD domains and we are joined to a non-kerberos domain
164 (c) trusted AD domains and we are joined to a kerberos (AD) domain
166 For (a) we can always contact the trusted domain using krb5
167 since we have the domain trust account password
169 For (b) we can only use RPC since we have no way of
170 getting a krb5 ticket in our own domain
172 For (c) we can always use krb5 since we have a kerberos trust
177 if (!domain
->backend
) {
179 struct winbindd_domain
*our_domain
= domain
;
181 /* find our domain first so we can figure out if we
182 are joined to a kerberized domain */
184 if ( !domain
->primary
)
185 our_domain
= find_our_domain();
187 if ((our_domain
->active_directory
|| IS_DC
)
188 && domain
->active_directory
189 && !lp_winbind_rpc_only()) {
190 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain
->name
));
191 domain
->backend
= &ads_methods
;
193 #endif /* HAVE_ADS */
194 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain
->name
));
195 domain
->backend
= &reconnect_methods
;
198 #endif /* HAVE_ADS */
204 ret
= SMB_XMALLOC_P(struct winbind_cache
);
208 wcache_flush_cache();
214 free a centry structure
216 static void centry_free(struct cache_entry
*centry
)
220 SAFE_FREE(centry
->data
);
224 static bool centry_check_bytes(struct cache_entry
*centry
, size_t nbytes
)
226 if (centry
->len
- centry
->ofs
< nbytes
) {
227 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
228 (unsigned int)nbytes
,
229 centry
->len
- centry
->ofs
));
236 pull a uint32 from a cache entry
238 static uint32
centry_uint32(struct cache_entry
*centry
)
242 if (!centry_check_bytes(centry
, 4)) {
243 smb_panic_fn("centry_uint32");
245 ret
= IVAL(centry
->data
, centry
->ofs
);
251 pull a uint16 from a cache entry
253 static uint16
centry_uint16(struct cache_entry
*centry
)
256 if (!centry_check_bytes(centry
, 2)) {
257 smb_panic_fn("centry_uint16");
259 ret
= CVAL(centry
->data
, centry
->ofs
);
265 pull a uint8 from a cache entry
267 static uint8
centry_uint8(struct cache_entry
*centry
)
270 if (!centry_check_bytes(centry
, 1)) {
271 smb_panic_fn("centry_uint8");
273 ret
= CVAL(centry
->data
, centry
->ofs
);
279 pull a NTTIME from a cache entry
281 static NTTIME
centry_nttime(struct cache_entry
*centry
)
284 if (!centry_check_bytes(centry
, 8)) {
285 smb_panic_fn("centry_nttime");
287 ret
= IVAL(centry
->data
, centry
->ofs
);
289 ret
+= (uint64_t)IVAL(centry
->data
, centry
->ofs
) << 32;
295 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
297 static time_t centry_time(struct cache_entry
*centry
)
299 return (time_t)centry_nttime(centry
);
302 /* pull a string from a cache entry, using the supplied
305 static char *centry_string(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
310 len
= centry_uint8(centry
);
313 /* a deliberate NULL string */
317 if (!centry_check_bytes(centry
, (size_t)len
)) {
318 smb_panic_fn("centry_string");
321 ret
= TALLOC_ARRAY(mem_ctx
, char, len
+1);
323 smb_panic_fn("centry_string out of memory\n");
325 memcpy(ret
,centry
->data
+ centry
->ofs
, len
);
331 /* pull a hash16 from a cache entry, using the supplied
334 static char *centry_hash16(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
339 len
= centry_uint8(centry
);
342 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
347 if (!centry_check_bytes(centry
, 16)) {
351 ret
= TALLOC_ARRAY(mem_ctx
, char, 16);
353 smb_panic_fn("centry_hash out of memory\n");
355 memcpy(ret
,centry
->data
+ centry
->ofs
, 16);
360 /* pull a sid from a cache entry, using the supplied
363 static bool centry_sid(struct cache_entry
*centry
, struct dom_sid
*sid
)
368 sid_string
= centry_string(centry
, talloc_tos());
369 if (sid_string
== NULL
) {
372 ret
= string_to_sid(sid
, sid_string
);
373 TALLOC_FREE(sid_string
);
379 pull a NTSTATUS from a cache entry
381 static NTSTATUS
centry_ntstatus(struct cache_entry
*centry
)
385 status
= NT_STATUS(centry_uint32(centry
));
390 /* the server is considered down if it can't give us a sequence number */
391 static bool wcache_server_down(struct winbindd_domain
*domain
)
398 ret
= (domain
->sequence_number
== DOM_SEQUENCE_NONE
);
401 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
406 static bool wcache_fetch_seqnum(const char *domain_name
, uint32_t *seqnum
,
407 uint32_t *last_seq_check
)
412 if (wcache
->tdb
== NULL
) {
413 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
417 key
= talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name
);
419 DEBUG(10, ("talloc failed\n"));
423 data
= tdb_fetch_bystring(wcache
->tdb
, key
);
426 if (data
.dptr
== NULL
) {
427 DEBUG(10, ("wcache_fetch_seqnum: %s not found\n",
431 if (data
.dsize
!= 8) {
432 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
434 SAFE_FREE(data
.dptr
);
438 *seqnum
= IVAL(data
.dptr
, 0);
439 *last_seq_check
= IVAL(data
.dptr
, 4);
440 SAFE_FREE(data
.dptr
);
445 static NTSTATUS
fetch_cache_seqnum( struct winbindd_domain
*domain
, time_t now
)
447 uint32 last_check
, time_diff
;
449 if (!wcache_fetch_seqnum(domain
->name
, &domain
->sequence_number
,
451 return NT_STATUS_UNSUCCESSFUL
;
453 domain
->last_seq_check
= last_check
;
455 /* have we expired? */
457 time_diff
= now
- domain
->last_seq_check
;
458 if ( time_diff
> lp_winbind_cache_time() ) {
459 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
460 domain
->name
, domain
->sequence_number
,
461 (uint32
)domain
->last_seq_check
));
462 return NT_STATUS_UNSUCCESSFUL
;
465 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
466 domain
->name
, domain
->sequence_number
,
467 (uint32
)domain
->last_seq_check
));
472 bool wcache_store_seqnum(const char *domain_name
, uint32_t seqnum
,
473 time_t last_seq_check
)
479 if (wcache
->tdb
== NULL
) {
480 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
484 key_str
= talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name
);
485 if (key_str
== NULL
) {
486 DEBUG(10, ("talloc_asprintf failed\n"));
490 SIVAL(buf
, 0, seqnum
);
491 SIVAL(buf
, 4, last_seq_check
);
493 ret
= tdb_store_bystring(wcache
->tdb
, key_str
,
494 make_tdb_data(buf
, sizeof(buf
)), TDB_REPLACE
);
495 TALLOC_FREE(key_str
);
497 DEBUG(10, ("tdb_store_bystring failed: %s\n",
498 tdb_errorstr(wcache
->tdb
)));
499 TALLOC_FREE(key_str
);
503 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
504 domain_name
, seqnum
, (unsigned)last_seq_check
));
509 static bool store_cache_seqnum( struct winbindd_domain
*domain
)
511 return wcache_store_seqnum(domain
->name
, domain
->sequence_number
,
512 domain
->last_seq_check
);
516 refresh the domain sequence number. If force is true
517 then always refresh it, no matter how recently we fetched it
520 static void refresh_sequence_number(struct winbindd_domain
*domain
, bool force
)
524 time_t t
= time(NULL
);
525 unsigned cache_time
= lp_winbind_cache_time();
527 if (is_domain_offline(domain
)) {
533 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
534 /* trying to reconnect is expensive, don't do it too often */
535 if (domain
->sequence_number
== DOM_SEQUENCE_NONE
) {
540 time_diff
= t
- domain
->last_seq_check
;
542 /* see if we have to refetch the domain sequence number */
543 if (!force
&& (time_diff
< cache_time
) &&
544 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
545 NT_STATUS_IS_OK(domain
->last_status
)) {
546 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain
->name
));
550 /* try to get the sequence number from the tdb cache first */
551 /* this will update the timestamp as well */
553 status
= fetch_cache_seqnum( domain
, t
);
554 if (NT_STATUS_IS_OK(status
) &&
555 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
556 NT_STATUS_IS_OK(domain
->last_status
)) {
560 /* important! make sure that we know if this is a native
561 mode domain or not. And that we can contact it. */
563 if ( winbindd_can_contact_domain( domain
) ) {
564 status
= domain
->backend
->sequence_number(domain
,
565 &domain
->sequence_number
);
567 /* just use the current time */
568 status
= NT_STATUS_OK
;
569 domain
->sequence_number
= time(NULL
);
573 /* the above call could have set our domain->backend to NULL when
574 * coming from offline to online mode, make sure to reinitialize the
575 * backend - Guenther */
578 if (!NT_STATUS_IS_OK(status
)) {
579 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status
)));
580 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
583 domain
->last_status
= status
;
584 domain
->last_seq_check
= time(NULL
);
586 /* save the new sequence number in the cache */
587 store_cache_seqnum( domain
);
590 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
591 domain
->name
, domain
->sequence_number
));
597 decide if a cache entry has expired
599 static bool centry_expired(struct winbindd_domain
*domain
, const char *keystr
, struct cache_entry
*centry
)
601 /* If we've been told to be offline - stay in that state... */
602 if (lp_winbind_offline_logon() && global_winbindd_offline_state
) {
603 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
604 keystr
, domain
->name
));
608 /* when the domain is offline return the cached entry.
609 * This deals with transient offline states... */
611 if (!domain
->online
) {
612 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
613 keystr
, domain
->name
));
617 /* if the server is OK and our cache entry came from when it was down then
618 the entry is invalid */
619 if ((domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
620 (centry
->sequence_number
== DOM_SEQUENCE_NONE
)) {
621 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
622 keystr
, domain
->name
));
626 /* if the server is down or the cache entry is not older than the
627 current sequence number then it is OK */
628 if (wcache_server_down(domain
) ||
629 centry
->sequence_number
== domain
->sequence_number
) {
630 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
631 keystr
, domain
->name
));
635 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
636 keystr
, domain
->name
));
642 static struct cache_entry
*wcache_fetch_raw(char *kstr
)
645 struct cache_entry
*centry
;
648 key
= string_tdb_data(kstr
);
649 data
= tdb_fetch(wcache
->tdb
, key
);
655 centry
= SMB_XMALLOC_P(struct cache_entry
);
656 centry
->data
= (unsigned char *)data
.dptr
;
657 centry
->len
= data
.dsize
;
660 if (centry
->len
< 8) {
661 /* huh? corrupt cache? */
662 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr
));
667 centry
->status
= centry_ntstatus(centry
);
668 centry
->sequence_number
= centry_uint32(centry
);
673 static bool is_my_own_sam_domain(struct winbindd_domain
*domain
)
675 if (strequal(domain
->name
, get_global_sam_name()) &&
676 sid_equal(&domain
->sid
, get_global_sam_sid())) {
683 static bool is_builtin_domain(struct winbindd_domain
*domain
)
685 if (strequal(domain
->name
, "BUILTIN") &&
686 sid_equal(&domain
->sid
, &global_sid_Builtin
)) {
694 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
695 number and return status
697 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
698 struct winbindd_domain
*domain
,
699 const char *format
, ...) PRINTF_ATTRIBUTE(3,4);
700 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
701 struct winbindd_domain
*domain
,
702 const char *format
, ...)
706 struct cache_entry
*centry
;
708 if (!winbindd_use_cache() ||
709 is_my_own_sam_domain(domain
) ||
710 is_builtin_domain(domain
)) {
714 refresh_sequence_number(domain
, false);
716 va_start(ap
, format
);
717 smb_xvasprintf(&kstr
, format
, ap
);
720 centry
= wcache_fetch_raw(kstr
);
721 if (centry
== NULL
) {
726 if (centry_expired(domain
, kstr
, centry
)) {
728 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
729 kstr
, domain
->name
));
736 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
737 kstr
, domain
->name
));
743 static void wcache_delete(const char *format
, ...) PRINTF_ATTRIBUTE(1,2);
744 static void wcache_delete(const char *format
, ...)
750 va_start(ap
, format
);
751 smb_xvasprintf(&kstr
, format
, ap
);
754 key
= string_tdb_data(kstr
);
756 tdb_delete(wcache
->tdb
, key
);
761 make sure we have at least len bytes available in a centry
763 static void centry_expand(struct cache_entry
*centry
, uint32 len
)
765 if (centry
->len
- centry
->ofs
>= len
)
768 centry
->data
= SMB_REALLOC_ARRAY(centry
->data
, unsigned char,
771 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry
->len
));
772 smb_panic_fn("out of memory in centry_expand");
777 push a uint32 into a centry
779 static void centry_put_uint32(struct cache_entry
*centry
, uint32 v
)
781 centry_expand(centry
, 4);
782 SIVAL(centry
->data
, centry
->ofs
, v
);
787 push a uint16 into a centry
789 static void centry_put_uint16(struct cache_entry
*centry
, uint16 v
)
791 centry_expand(centry
, 2);
792 SIVAL(centry
->data
, centry
->ofs
, v
);
797 push a uint8 into a centry
799 static void centry_put_uint8(struct cache_entry
*centry
, uint8 v
)
801 centry_expand(centry
, 1);
802 SCVAL(centry
->data
, centry
->ofs
, v
);
807 push a string into a centry
809 static void centry_put_string(struct cache_entry
*centry
, const char *s
)
814 /* null strings are marked as len 0xFFFF */
815 centry_put_uint8(centry
, 0xFF);
820 /* can't handle more than 254 char strings. Truncating is probably best */
822 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len
));
825 centry_put_uint8(centry
, len
);
826 centry_expand(centry
, len
);
827 memcpy(centry
->data
+ centry
->ofs
, s
, len
);
832 push a 16 byte hash into a centry - treat as 16 byte string.
834 static void centry_put_hash16(struct cache_entry
*centry
, const uint8 val
[16])
836 centry_put_uint8(centry
, 16);
837 centry_expand(centry
, 16);
838 memcpy(centry
->data
+ centry
->ofs
, val
, 16);
842 static void centry_put_sid(struct cache_entry
*centry
, const struct dom_sid
*sid
)
845 centry_put_string(centry
, sid_to_fstring(sid_string
, sid
));
850 put NTSTATUS into a centry
852 static void centry_put_ntstatus(struct cache_entry
*centry
, NTSTATUS status
)
854 uint32 status_value
= NT_STATUS_V(status
);
855 centry_put_uint32(centry
, status_value
);
860 push a NTTIME into a centry
862 static void centry_put_nttime(struct cache_entry
*centry
, NTTIME nt
)
864 centry_expand(centry
, 8);
865 SIVAL(centry
->data
, centry
->ofs
, nt
& 0xFFFFFFFF);
867 SIVAL(centry
->data
, centry
->ofs
, nt
>> 32);
872 push a time_t into a centry - use a 64 bit size.
873 NTTIME here is being used as a convenient 64-bit size.
875 static void centry_put_time(struct cache_entry
*centry
, time_t t
)
877 NTTIME nt
= (NTTIME
)t
;
878 centry_put_nttime(centry
, nt
);
882 start a centry for output. When finished, call centry_end()
884 struct cache_entry
*centry_start(struct winbindd_domain
*domain
, NTSTATUS status
)
886 struct cache_entry
*centry
;
891 centry
= SMB_XMALLOC_P(struct cache_entry
);
893 centry
->len
= 8192; /* reasonable default */
894 centry
->data
= SMB_XMALLOC_ARRAY(uint8
, centry
->len
);
896 centry
->sequence_number
= domain
->sequence_number
;
897 centry_put_ntstatus(centry
, status
);
898 centry_put_uint32(centry
, centry
->sequence_number
);
903 finish a centry and write it to the tdb
905 static void centry_end(struct cache_entry
*centry
, const char *format
, ...) PRINTF_ATTRIBUTE(2,3);
906 static void centry_end(struct cache_entry
*centry
, const char *format
, ...)
912 if (!winbindd_use_cache()) {
916 va_start(ap
, format
);
917 smb_xvasprintf(&kstr
, format
, ap
);
920 key
= string_tdb_data(kstr
);
921 data
.dptr
= centry
->data
;
922 data
.dsize
= centry
->ofs
;
924 tdb_store(wcache
->tdb
, key
, data
, TDB_REPLACE
);
928 static void wcache_save_name_to_sid(struct winbindd_domain
*domain
,
929 NTSTATUS status
, const char *domain_name
,
930 const char *name
, const struct dom_sid
*sid
,
931 enum lsa_SidType type
)
933 struct cache_entry
*centry
;
936 centry
= centry_start(domain
, status
);
939 centry_put_uint32(centry
, type
);
940 centry_put_sid(centry
, sid
);
941 fstrcpy(uname
, name
);
943 centry_end(centry
, "NS/%s/%s", domain_name
, uname
);
944 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name
,
945 uname
, sid_string_dbg(sid
), nt_errstr(status
)));
949 static void wcache_save_sid_to_name(struct winbindd_domain
*domain
, NTSTATUS status
,
950 const struct dom_sid
*sid
, const char *domain_name
, const char *name
, enum lsa_SidType type
)
952 struct cache_entry
*centry
;
955 centry
= centry_start(domain
, status
);
959 if (NT_STATUS_IS_OK(status
)) {
960 centry_put_uint32(centry
, type
);
961 centry_put_string(centry
, domain_name
);
962 centry_put_string(centry
, name
);
965 centry_end(centry
, "SN/%s", sid_to_fstring(sid_string
, sid
));
966 DEBUG(10,("wcache_save_sid_to_name: %s -> %s (%s)\n", sid_string
,
967 name
, nt_errstr(status
)));
972 static void wcache_save_user(struct winbindd_domain
*domain
, NTSTATUS status
,
973 struct wbint_userinfo
*info
)
975 struct cache_entry
*centry
;
978 if (is_null_sid(&info
->user_sid
)) {
982 centry
= centry_start(domain
, status
);
985 centry_put_string(centry
, info
->acct_name
);
986 centry_put_string(centry
, info
->full_name
);
987 centry_put_string(centry
, info
->homedir
);
988 centry_put_string(centry
, info
->shell
);
989 centry_put_uint32(centry
, info
->primary_gid
);
990 centry_put_sid(centry
, &info
->user_sid
);
991 centry_put_sid(centry
, &info
->group_sid
);
992 centry_end(centry
, "U/%s", sid_to_fstring(sid_string
,
994 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string
, info
->acct_name
));
998 static void wcache_save_lockout_policy(struct winbindd_domain
*domain
,
1000 struct samr_DomInfo12
*lockout_policy
)
1002 struct cache_entry
*centry
;
1004 centry
= centry_start(domain
, status
);
1008 centry_put_nttime(centry
, lockout_policy
->lockout_duration
);
1009 centry_put_nttime(centry
, lockout_policy
->lockout_window
);
1010 centry_put_uint16(centry
, lockout_policy
->lockout_threshold
);
1012 centry_end(centry
, "LOC_POL/%s", domain
->name
);
1014 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain
->name
));
1016 centry_free(centry
);
1021 static void wcache_save_password_policy(struct winbindd_domain
*domain
,
1023 struct samr_DomInfo1
*policy
)
1025 struct cache_entry
*centry
;
1027 centry
= centry_start(domain
, status
);
1031 centry_put_uint16(centry
, policy
->min_password_length
);
1032 centry_put_uint16(centry
, policy
->password_history_length
);
1033 centry_put_uint32(centry
, policy
->password_properties
);
1034 centry_put_nttime(centry
, policy
->max_password_age
);
1035 centry_put_nttime(centry
, policy
->min_password_age
);
1037 centry_end(centry
, "PWD_POL/%s", domain
->name
);
1039 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
1041 centry_free(centry
);
1044 /***************************************************************************
1045 ***************************************************************************/
1047 static void wcache_save_username_alias(struct winbindd_domain
*domain
,
1049 const char *name
, const char *alias
)
1051 struct cache_entry
*centry
;
1054 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1057 centry_put_string( centry
, alias
);
1059 fstrcpy(uname
, name
);
1061 centry_end(centry
, "NSS/NA/%s", uname
);
1063 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name
, alias
));
1065 centry_free(centry
);
1068 static void wcache_save_alias_username(struct winbindd_domain
*domain
,
1070 const char *alias
, const char *name
)
1072 struct cache_entry
*centry
;
1075 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1078 centry_put_string( centry
, name
);
1080 fstrcpy(uname
, alias
);
1082 centry_end(centry
, "NSS/AN/%s", uname
);
1084 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias
, name
));
1086 centry_free(centry
);
1089 /***************************************************************************
1090 ***************************************************************************/
1092 NTSTATUS
resolve_username_to_alias( TALLOC_CTX
*mem_ctx
,
1093 struct winbindd_domain
*domain
,
1094 const char *name
, char **alias
)
1096 struct winbind_cache
*cache
= get_cache(domain
);
1097 struct cache_entry
*centry
= NULL
;
1101 if ( domain
->internal
)
1102 return NT_STATUS_NOT_SUPPORTED
;
1107 if ( (upper_name
= SMB_STRDUP(name
)) == NULL
)
1108 return NT_STATUS_NO_MEMORY
;
1109 strupper_m(upper_name
);
1111 centry
= wcache_fetch(cache
, domain
, "NSS/NA/%s", upper_name
);
1113 SAFE_FREE( upper_name
);
1118 status
= centry
->status
;
1120 if (!NT_STATUS_IS_OK(status
)) {
1121 centry_free(centry
);
1125 *alias
= centry_string( centry
, mem_ctx
);
1127 centry_free(centry
);
1129 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1130 name
, *alias
? *alias
: "(none)"));
1132 return (*alias
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1136 /* If its not in cache and we are offline, then fail */
1138 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1139 DEBUG(8,("resolve_username_to_alias: rejecting query "
1140 "in offline mode\n"));
1141 return NT_STATUS_NOT_FOUND
;
1144 status
= nss_map_to_alias( mem_ctx
, domain
->name
, name
, alias
);
1146 if ( NT_STATUS_IS_OK( status
) ) {
1147 wcache_save_username_alias(domain
, status
, name
, *alias
);
1150 if ( NT_STATUS_EQUAL( status
, NT_STATUS_NONE_MAPPED
) ) {
1151 wcache_save_username_alias(domain
, status
, name
, "(NULL)");
1154 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1155 nt_errstr(status
)));
1157 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1158 set_domain_offline( domain
);
1164 /***************************************************************************
1165 ***************************************************************************/
1167 NTSTATUS
resolve_alias_to_username( TALLOC_CTX
*mem_ctx
,
1168 struct winbindd_domain
*domain
,
1169 const char *alias
, char **name
)
1171 struct winbind_cache
*cache
= get_cache(domain
);
1172 struct cache_entry
*centry
= NULL
;
1176 if ( domain
->internal
)
1177 return NT_STATUS_NOT_SUPPORTED
;
1182 if ( (upper_name
= SMB_STRDUP(alias
)) == NULL
)
1183 return NT_STATUS_NO_MEMORY
;
1184 strupper_m(upper_name
);
1186 centry
= wcache_fetch(cache
, domain
, "NSS/AN/%s", upper_name
);
1188 SAFE_FREE( upper_name
);
1193 status
= centry
->status
;
1195 if (!NT_STATUS_IS_OK(status
)) {
1196 centry_free(centry
);
1200 *name
= centry_string( centry
, mem_ctx
);
1202 centry_free(centry
);
1204 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1205 alias
, *name
? *name
: "(none)"));
1207 return (*name
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1211 /* If its not in cache and we are offline, then fail */
1213 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1214 DEBUG(8,("resolve_alias_to_username: rejecting query "
1215 "in offline mode\n"));
1216 return NT_STATUS_NOT_FOUND
;
1219 /* an alias cannot contain a domain prefix or '@' */
1221 if (strchr(alias
, '\\') || strchr(alias
, '@')) {
1222 DEBUG(10,("resolve_alias_to_username: skipping fully "
1223 "qualified name %s\n", alias
));
1224 return NT_STATUS_OBJECT_NAME_INVALID
;
1227 status
= nss_map_from_alias( mem_ctx
, domain
->name
, alias
, name
);
1229 if ( NT_STATUS_IS_OK( status
) ) {
1230 wcache_save_alias_username( domain
, status
, alias
, *name
);
1233 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1234 wcache_save_alias_username(domain
, status
, alias
, "(NULL)");
1237 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1238 nt_errstr(status
)));
1240 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1241 set_domain_offline( domain
);
1247 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
1249 struct winbind_cache
*cache
= get_cache(domain
);
1251 fstring key_str
, tmp
;
1255 return NT_STATUS_INTERNAL_DB_ERROR
;
1258 if (is_null_sid(sid
)) {
1259 return NT_STATUS_INVALID_SID
;
1262 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1263 return NT_STATUS_INVALID_SID
;
1266 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
1268 data
= tdb_fetch(cache
->tdb
, string_tdb_data(key_str
));
1270 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1273 SAFE_FREE(data
.dptr
);
1274 return NT_STATUS_OK
;
1277 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1278 as new salted ones. */
1280 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
1281 TALLOC_CTX
*mem_ctx
,
1282 const struct dom_sid
*sid
,
1283 const uint8
**cached_nt_pass
,
1284 const uint8
**cached_salt
)
1286 struct winbind_cache
*cache
= get_cache(domain
);
1287 struct cache_entry
*centry
= NULL
;
1294 return NT_STATUS_INTERNAL_DB_ERROR
;
1297 if (is_null_sid(sid
)) {
1298 return NT_STATUS_INVALID_SID
;
1301 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1302 return NT_STATUS_INVALID_SID
;
1305 /* Try and get a salted cred first. If we can't
1306 fall back to an unsalted cred. */
1308 centry
= wcache_fetch(cache
, domain
, "CRED/%s",
1309 sid_to_fstring(tmp
, sid
));
1311 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1312 sid_string_dbg(sid
)));
1313 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1316 t
= centry_time(centry
);
1318 /* In the salted case this isn't actually the nt_hash itself,
1319 but the MD5 of the salt + nt_hash. Let the caller
1320 sort this out. It can tell as we only return the cached_salt
1321 if we are returning a salted cred. */
1323 *cached_nt_pass
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1324 if (*cached_nt_pass
== NULL
) {
1327 sid_to_fstring(sidstr
, sid
);
1329 /* Bad (old) cred cache. Delete and pretend we
1331 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1333 wcache_delete("CRED/%s", sidstr
);
1334 centry_free(centry
);
1335 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1338 /* We only have 17 bytes more data in the salted cred case. */
1339 if (centry
->len
- centry
->ofs
== 17) {
1340 *cached_salt
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1342 *cached_salt
= NULL
;
1345 dump_data_pw("cached_nt_pass", *cached_nt_pass
, NT_HASH_LEN
);
1347 dump_data_pw("cached_salt", *cached_salt
, NT_HASH_LEN
);
1350 status
= centry
->status
;
1352 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1353 sid_string_dbg(sid
), nt_errstr(status
) ));
1355 centry_free(centry
);
1359 /* Store creds for a SID - only writes out new salted ones. */
1361 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1362 TALLOC_CTX
*mem_ctx
,
1363 const struct dom_sid
*sid
,
1364 const uint8 nt_pass
[NT_HASH_LEN
])
1366 struct cache_entry
*centry
;
1369 uint8 cred_salt
[NT_HASH_LEN
];
1370 uint8 salted_hash
[NT_HASH_LEN
];
1372 if (is_null_sid(sid
)) {
1373 return NT_STATUS_INVALID_SID
;
1376 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1377 return NT_STATUS_INVALID_SID
;
1380 centry
= centry_start(domain
, NT_STATUS_OK
);
1382 return NT_STATUS_INTERNAL_DB_ERROR
;
1385 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1387 centry_put_time(centry
, time(NULL
));
1389 /* Create a salt and then salt the hash. */
1390 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1391 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1393 centry_put_hash16(centry
, salted_hash
);
1394 centry_put_hash16(centry
, cred_salt
);
1395 centry_end(centry
, "CRED/%s", sid_to_fstring(sid_string
, sid
));
1397 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1399 centry_free(centry
);
1401 return NT_STATUS_OK
;
1405 /* Query display info. This is the basic user list fn */
1406 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
1407 TALLOC_CTX
*mem_ctx
,
1408 uint32
*num_entries
,
1409 struct wbint_userinfo
**info
)
1411 struct winbind_cache
*cache
= get_cache(domain
);
1412 struct cache_entry
*centry
= NULL
;
1414 unsigned int i
, retry
;
1415 bool old_status
= domain
->online
;
1420 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1425 *num_entries
= centry_uint32(centry
);
1427 if (*num_entries
== 0)
1430 (*info
) = TALLOC_ARRAY(mem_ctx
, struct wbint_userinfo
, *num_entries
);
1432 smb_panic_fn("query_user_list out of memory");
1434 for (i
=0; i
<(*num_entries
); i
++) {
1435 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
1436 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
1437 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
1438 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
1439 centry_sid(centry
, &(*info
)[i
].user_sid
);
1440 centry_sid(centry
, &(*info
)[i
].group_sid
);
1444 status
= centry
->status
;
1446 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1447 domain
->name
, nt_errstr(status
) ));
1449 centry_free(centry
);
1456 /* Return status value returned by seq number check */
1458 if (!NT_STATUS_IS_OK(domain
->last_status
))
1459 return domain
->last_status
;
1461 /* Put the query_user_list() in a retry loop. There appears to be
1462 * some bug either with Windows 2000 or Samba's handling of large
1463 * rpc replies. This manifests itself as sudden disconnection
1464 * at a random point in the enumeration of a large (60k) user list.
1465 * The retry loop simply tries the operation again. )-: It's not
1466 * pretty but an acceptable workaround until we work out what the
1467 * real problem is. */
1472 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1475 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
1476 if (!NT_STATUS_IS_OK(status
)) {
1477 DEBUG(3, ("query_user_list: returned 0x%08x, "
1478 "retrying\n", NT_STATUS_V(status
)));
1480 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1481 DEBUG(3, ("query_user_list: flushing "
1482 "connection cache\n"));
1483 invalidate_cm_connection(&domain
->conn
);
1485 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1486 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1487 if (!domain
->internal
&& old_status
) {
1488 set_domain_offline(domain
);
1490 /* store partial response. */
1491 if (*num_entries
> 0) {
1493 * humm, what about the status used for cache?
1494 * Should it be NT_STATUS_OK?
1499 * domain is offline now, and there is no user entries,
1500 * try to fetch from cache again.
1502 if (cache
->tdb
&& !domain
->online
&& !domain
->internal
&& old_status
) {
1503 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1504 /* partial response... */
1508 goto do_fetch_cache
;
1515 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1519 refresh_sequence_number(domain
, false);
1520 if (!NT_STATUS_IS_OK(status
)) {
1523 centry
= centry_start(domain
, status
);
1526 centry_put_uint32(centry
, *num_entries
);
1527 for (i
=0; i
<(*num_entries
); i
++) {
1528 centry_put_string(centry
, (*info
)[i
].acct_name
);
1529 centry_put_string(centry
, (*info
)[i
].full_name
);
1530 centry_put_string(centry
, (*info
)[i
].homedir
);
1531 centry_put_string(centry
, (*info
)[i
].shell
);
1532 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1533 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1534 if (domain
->backend
&& domain
->backend
->consistent
) {
1535 /* when the backend is consistent we can pre-prime some mappings */
1536 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1538 (*info
)[i
].acct_name
,
1539 &(*info
)[i
].user_sid
,
1541 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1542 &(*info
)[i
].user_sid
,
1544 (*info
)[i
].acct_name
,
1546 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1549 centry_end(centry
, "UL/%s", domain
->name
);
1550 centry_free(centry
);
1556 /* list all domain groups */
1557 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
1558 TALLOC_CTX
*mem_ctx
,
1559 uint32
*num_entries
,
1560 struct acct_info
**info
)
1562 struct winbind_cache
*cache
= get_cache(domain
);
1563 struct cache_entry
*centry
= NULL
;
1568 old_status
= domain
->online
;
1572 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1577 *num_entries
= centry_uint32(centry
);
1579 if (*num_entries
== 0)
1582 (*info
) = TALLOC_ARRAY(mem_ctx
, struct acct_info
, *num_entries
);
1584 smb_panic_fn("enum_dom_groups out of memory");
1586 for (i
=0; i
<(*num_entries
); i
++) {
1587 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1588 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1589 (*info
)[i
].rid
= centry_uint32(centry
);
1593 status
= centry
->status
;
1595 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1596 domain
->name
, nt_errstr(status
) ));
1598 centry_free(centry
);
1605 /* Return status value returned by seq number check */
1607 if (!NT_STATUS_IS_OK(domain
->last_status
))
1608 return domain
->last_status
;
1610 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1613 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1615 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1616 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1617 if (!domain
->internal
&& old_status
) {
1618 set_domain_offline(domain
);
1622 !domain
->internal
&&
1624 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1626 goto do_fetch_cache
;
1631 refresh_sequence_number(domain
, false);
1632 if (!NT_STATUS_IS_OK(status
)) {
1635 centry
= centry_start(domain
, status
);
1638 centry_put_uint32(centry
, *num_entries
);
1639 for (i
=0; i
<(*num_entries
); i
++) {
1640 centry_put_string(centry
, (*info
)[i
].acct_name
);
1641 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1642 centry_put_uint32(centry
, (*info
)[i
].rid
);
1644 centry_end(centry
, "GL/%s/domain", domain
->name
);
1645 centry_free(centry
);
1651 /* list all domain groups */
1652 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
1653 TALLOC_CTX
*mem_ctx
,
1654 uint32
*num_entries
,
1655 struct acct_info
**info
)
1657 struct winbind_cache
*cache
= get_cache(domain
);
1658 struct cache_entry
*centry
= NULL
;
1663 old_status
= domain
->online
;
1667 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1672 *num_entries
= centry_uint32(centry
);
1674 if (*num_entries
== 0)
1677 (*info
) = TALLOC_ARRAY(mem_ctx
, struct acct_info
, *num_entries
);
1679 smb_panic_fn("enum_dom_groups out of memory");
1681 for (i
=0; i
<(*num_entries
); i
++) {
1682 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1683 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1684 (*info
)[i
].rid
= centry_uint32(centry
);
1689 /* If we are returning cached data and the domain controller
1690 is down then we don't know whether the data is up to date
1691 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1694 if (wcache_server_down(domain
)) {
1695 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1696 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1698 status
= centry
->status
;
1700 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1701 domain
->name
, nt_errstr(status
) ));
1703 centry_free(centry
);
1710 /* Return status value returned by seq number check */
1712 if (!NT_STATUS_IS_OK(domain
->last_status
))
1713 return domain
->last_status
;
1715 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1718 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1720 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1721 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1722 if (!domain
->internal
&& old_status
) {
1723 set_domain_offline(domain
);
1726 !domain
->internal
&&
1729 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1731 goto do_fetch_cache
;
1736 refresh_sequence_number(domain
, false);
1737 if (!NT_STATUS_IS_OK(status
)) {
1740 centry
= centry_start(domain
, status
);
1743 centry_put_uint32(centry
, *num_entries
);
1744 for (i
=0; i
<(*num_entries
); i
++) {
1745 centry_put_string(centry
, (*info
)[i
].acct_name
);
1746 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1747 centry_put_uint32(centry
, (*info
)[i
].rid
);
1749 centry_end(centry
, "GL/%s/local", domain
->name
);
1750 centry_free(centry
);
1756 NTSTATUS
wcache_name_to_sid(struct winbindd_domain
*domain
,
1757 const char *domain_name
,
1759 struct dom_sid
*sid
,
1760 enum lsa_SidType
*type
)
1762 struct winbind_cache
*cache
= get_cache(domain
);
1763 struct cache_entry
*centry
;
1767 if (cache
->tdb
== NULL
) {
1768 return NT_STATUS_NOT_FOUND
;
1771 uname
= talloc_strdup_upper(talloc_tos(), name
);
1772 if (uname
== NULL
) {
1773 return NT_STATUS_NO_MEMORY
;
1776 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1778 if (centry
== NULL
) {
1779 return NT_STATUS_NOT_FOUND
;
1782 status
= centry
->status
;
1783 if (NT_STATUS_IS_OK(status
)) {
1784 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1785 centry_sid(centry
, sid
);
1788 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1789 "%s\n", domain
->name
, nt_errstr(status
) ));
1791 centry_free(centry
);
1795 /* convert a single name to a sid in a domain */
1796 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
1797 TALLOC_CTX
*mem_ctx
,
1798 const char *domain_name
,
1801 struct dom_sid
*sid
,
1802 enum lsa_SidType
*type
)
1807 old_status
= domain
->online
;
1809 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1810 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1816 /* If the seq number check indicated that there is a problem
1817 * with this DC, then return that status... except for
1818 * access_denied. This is special because the dc may be in
1819 * "restrict anonymous = 1" mode, in which case it will deny
1820 * most unauthenticated operations, but *will* allow the LSA
1821 * name-to-sid that we try as a fallback. */
1823 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1824 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1825 return domain
->last_status
;
1827 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1830 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
,
1831 name
, flags
, sid
, type
);
1833 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1834 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1835 if (!domain
->internal
&& old_status
) {
1836 set_domain_offline(domain
);
1838 if (!domain
->internal
&&
1841 NTSTATUS cache_status
;
1842 cache_status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1843 return cache_status
;
1847 refresh_sequence_number(domain
, false);
1849 if (domain
->online
&&
1850 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1851 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1853 /* Only save the reverse mapping if this was not a UPN */
1854 if (!strchr(name
, '@')) {
1855 strupper_m(CONST_DISCARD(char *,domain_name
));
1856 strlower_m(CONST_DISCARD(char *,name
));
1857 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1864 NTSTATUS
wcache_sid_to_name(struct winbindd_domain
*domain
,
1865 const struct dom_sid
*sid
,
1866 TALLOC_CTX
*mem_ctx
,
1869 enum lsa_SidType
*type
)
1871 struct winbind_cache
*cache
= get_cache(domain
);
1872 struct cache_entry
*centry
;
1876 if (cache
->tdb
== NULL
) {
1877 return NT_STATUS_NOT_FOUND
;
1880 sid_string
= sid_string_tos(sid
);
1881 if (sid_string
== NULL
) {
1882 return NT_STATUS_NO_MEMORY
;
1885 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_string
);
1886 TALLOC_FREE(sid_string
);
1887 if (centry
== NULL
) {
1888 return NT_STATUS_NOT_FOUND
;
1891 if (NT_STATUS_IS_OK(centry
->status
)) {
1892 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1893 *domain_name
= centry_string(centry
, mem_ctx
);
1894 *name
= centry_string(centry
, mem_ctx
);
1897 status
= centry
->status
;
1898 centry_free(centry
);
1900 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1901 "%s\n", domain
->name
, nt_errstr(status
) ));
1906 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1908 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1909 TALLOC_CTX
*mem_ctx
,
1910 const struct dom_sid
*sid
,
1913 enum lsa_SidType
*type
)
1918 old_status
= domain
->online
;
1919 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
1921 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1926 *domain_name
= NULL
;
1928 /* If the seq number check indicated that there is a problem
1929 * with this DC, then return that status... except for
1930 * access_denied. This is special because the dc may be in
1931 * "restrict anonymous = 1" mode, in which case it will deny
1932 * most unauthenticated operations, but *will* allow the LSA
1933 * sid-to-name that we try as a fallback. */
1935 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1936 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1937 return domain
->last_status
;
1939 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1942 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1944 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1945 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1946 if (!domain
->internal
&& old_status
) {
1947 set_domain_offline(domain
);
1949 if (!domain
->internal
&&
1952 NTSTATUS cache_status
;
1953 cache_status
= wcache_sid_to_name(domain
, sid
, mem_ctx
,
1954 domain_name
, name
, type
);
1955 return cache_status
;
1959 refresh_sequence_number(domain
, false);
1960 if (!NT_STATUS_IS_OK(status
)) {
1963 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
1965 /* We can't save the name to sid mapping here, as with sid history a
1966 * later name2sid would give the wrong sid. */
1971 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
1972 TALLOC_CTX
*mem_ctx
,
1973 const struct dom_sid
*domain_sid
,
1978 enum lsa_SidType
**types
)
1980 struct winbind_cache
*cache
= get_cache(domain
);
1982 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1987 old_status
= domain
->online
;
1988 *domain_name
= NULL
;
1996 if (num_rids
== 0) {
1997 return NT_STATUS_OK
;
2000 *names
= TALLOC_ARRAY(mem_ctx
, char *, num_rids
);
2001 *types
= TALLOC_ARRAY(mem_ctx
, enum lsa_SidType
, num_rids
);
2003 if ((*names
== NULL
) || (*types
== NULL
)) {
2004 result
= NT_STATUS_NO_MEMORY
;
2008 have_mapped
= have_unmapped
= false;
2010 for (i
=0; i
<num_rids
; i
++) {
2012 struct cache_entry
*centry
;
2015 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2016 result
= NT_STATUS_INTERNAL_ERROR
;
2020 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2021 sid_to_fstring(tmp
, &sid
));
2026 (*types
)[i
] = SID_NAME_UNKNOWN
;
2027 (*names
)[i
] = talloc_strdup(*names
, "");
2029 if (NT_STATUS_IS_OK(centry
->status
)) {
2032 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2034 dom
= centry_string(centry
, mem_ctx
);
2035 if (*domain_name
== NULL
) {
2041 (*names
)[i
] = centry_string(centry
, *names
);
2043 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)) {
2044 have_unmapped
= true;
2047 /* something's definitely wrong */
2048 result
= centry
->status
;
2052 centry_free(centry
);
2056 return NT_STATUS_NONE_MAPPED
;
2058 if (!have_unmapped
) {
2059 return NT_STATUS_OK
;
2061 return STATUS_SOME_UNMAPPED
;
2065 TALLOC_FREE(*names
);
2066 TALLOC_FREE(*types
);
2068 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
2069 rids
, num_rids
, domain_name
,
2072 if (NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
2073 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2074 if (!domain
->internal
&& old_status
) {
2075 set_domain_offline(domain
);
2078 !domain
->internal
&&
2081 have_mapped
= have_unmapped
= false;
2083 for (i
=0; i
<num_rids
; i
++) {
2085 struct cache_entry
*centry
;
2088 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2089 result
= NT_STATUS_INTERNAL_ERROR
;
2093 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2094 sid_to_fstring(tmp
, &sid
));
2096 (*types
)[i
] = SID_NAME_UNKNOWN
;
2097 (*names
)[i
] = talloc_strdup(*names
, "");
2101 (*types
)[i
] = SID_NAME_UNKNOWN
;
2102 (*names
)[i
] = talloc_strdup(*names
, "");
2104 if (NT_STATUS_IS_OK(centry
->status
)) {
2107 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2109 dom
= centry_string(centry
, mem_ctx
);
2110 if (*domain_name
== NULL
) {
2116 (*names
)[i
] = centry_string(centry
, *names
);
2118 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)) {
2119 have_unmapped
= true;
2122 /* something's definitely wrong */
2123 result
= centry
->status
;
2127 centry_free(centry
);
2131 return NT_STATUS_NONE_MAPPED
;
2133 if (!have_unmapped
) {
2134 return NT_STATUS_OK
;
2136 return STATUS_SOME_UNMAPPED
;
2140 None of the queried rids has been found so save all negative entries
2142 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
2143 for (i
= 0; i
< num_rids
; i
++) {
2145 const char *name
= "";
2146 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
2147 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
2149 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2150 return NT_STATUS_INTERNAL_ERROR
;
2153 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2161 Some or all of the queried rids have been found.
2163 if (!NT_STATUS_IS_OK(result
) &&
2164 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
2168 refresh_sequence_number(domain
, false);
2170 for (i
=0; i
<num_rids
; i
++) {
2174 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2175 result
= NT_STATUS_INTERNAL_ERROR
;
2179 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
2180 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
2182 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2183 (*names
)[i
], (*types
)[i
]);
2189 TALLOC_FREE(*names
);
2190 TALLOC_FREE(*types
);
2194 NTSTATUS
wcache_query_user(struct winbindd_domain
*domain
,
2195 TALLOC_CTX
*mem_ctx
,
2196 const struct dom_sid
*user_sid
,
2197 struct wbint_userinfo
*info
)
2199 struct winbind_cache
*cache
= get_cache(domain
);
2200 struct cache_entry
*centry
= NULL
;
2204 if (cache
->tdb
== NULL
) {
2205 return NT_STATUS_NOT_FOUND
;
2208 sid_string
= sid_string_tos(user_sid
);
2209 if (sid_string
== NULL
) {
2210 return NT_STATUS_NO_MEMORY
;
2213 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string
);
2214 TALLOC_FREE(sid_string
);
2215 if (centry
== NULL
) {
2216 return NT_STATUS_NOT_FOUND
;
2220 * If we have an access denied cache entry and a cached info3
2221 * in the samlogon cache then do a query. This will force the
2222 * rpc back end to return the info3 data.
2225 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
) &&
2226 netsamlogon_cache_have(user_sid
)) {
2227 DEBUG(10, ("query_user: cached access denied and have cached "
2229 domain
->last_status
= NT_STATUS_OK
;
2230 centry_free(centry
);
2231 return NT_STATUS_NOT_FOUND
;
2234 /* if status is not ok then this is a negative hit
2235 and the rest of the data doesn't matter */
2236 status
= centry
->status
;
2237 if (NT_STATUS_IS_OK(status
)) {
2238 info
->acct_name
= centry_string(centry
, mem_ctx
);
2239 info
->full_name
= centry_string(centry
, mem_ctx
);
2240 info
->homedir
= centry_string(centry
, mem_ctx
);
2241 info
->shell
= centry_string(centry
, mem_ctx
);
2242 info
->primary_gid
= centry_uint32(centry
);
2243 centry_sid(centry
, &info
->user_sid
);
2244 centry_sid(centry
, &info
->group_sid
);
2247 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2248 "%s\n", domain
->name
, nt_errstr(status
) ));
2250 centry_free(centry
);
2254 /* Lookup user information from a rid */
2255 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
2256 TALLOC_CTX
*mem_ctx
,
2257 const struct dom_sid
*user_sid
,
2258 struct wbint_userinfo
*info
)
2263 old_status
= domain
->online
;
2264 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2265 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2271 /* Return status value returned by seq number check */
2273 if (!NT_STATUS_IS_OK(domain
->last_status
))
2274 return domain
->last_status
;
2276 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2279 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
2281 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2282 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2283 if (!domain
->internal
&& old_status
) {
2284 set_domain_offline(domain
);
2286 if (!domain
->internal
&&
2289 NTSTATUS cache_status
;
2290 cache_status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2291 return cache_status
;
2295 refresh_sequence_number(domain
, false);
2296 if (!NT_STATUS_IS_OK(status
)) {
2299 wcache_save_user(domain
, status
, info
);
2304 NTSTATUS
wcache_lookup_usergroups(struct winbindd_domain
*domain
,
2305 TALLOC_CTX
*mem_ctx
,
2306 const struct dom_sid
*user_sid
,
2307 uint32_t *pnum_sids
,
2308 struct dom_sid
**psids
)
2310 struct winbind_cache
*cache
= get_cache(domain
);
2311 struct cache_entry
*centry
= NULL
;
2313 uint32_t i
, num_sids
;
2314 struct dom_sid
*sids
;
2317 if (cache
->tdb
== NULL
) {
2318 return NT_STATUS_NOT_FOUND
;
2321 centry
= wcache_fetch(cache
, domain
, "UG/%s",
2322 sid_to_fstring(sid_string
, user_sid
));
2323 if (centry
== NULL
) {
2324 return NT_STATUS_NOT_FOUND
;
2327 /* If we have an access denied cache entry and a cached info3 in the
2328 samlogon cache then do a query. This will force the rpc back end
2329 to return the info3 data. */
2331 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)
2332 && netsamlogon_cache_have(user_sid
)) {
2333 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2335 domain
->last_status
= NT_STATUS_OK
;
2336 centry_free(centry
);
2337 return NT_STATUS_NOT_FOUND
;
2340 num_sids
= centry_uint32(centry
);
2341 sids
= talloc_array(mem_ctx
, struct dom_sid
, num_sids
);
2343 centry_free(centry
);
2344 return NT_STATUS_NO_MEMORY
;
2347 for (i
=0; i
<num_sids
; i
++) {
2348 centry_sid(centry
, &sids
[i
]);
2351 status
= centry
->status
;
2353 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2354 "status: %s\n", domain
->name
, nt_errstr(status
)));
2356 centry_free(centry
);
2358 *pnum_sids
= num_sids
;
2363 /* Lookup groups a user is a member of. */
2364 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
2365 TALLOC_CTX
*mem_ctx
,
2366 const struct dom_sid
*user_sid
,
2367 uint32
*num_groups
, struct dom_sid
**user_gids
)
2369 struct cache_entry
*centry
= NULL
;
2375 old_status
= domain
->online
;
2376 status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2377 num_groups
, user_gids
);
2378 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2383 (*user_gids
) = NULL
;
2385 /* Return status value returned by seq number check */
2387 if (!NT_STATUS_IS_OK(domain
->last_status
))
2388 return domain
->last_status
;
2390 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2393 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
2395 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2396 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2397 if (!domain
->internal
&& old_status
) {
2398 set_domain_offline(domain
);
2400 if (!domain
->internal
&&
2403 NTSTATUS cache_status
;
2404 cache_status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2405 num_groups
, user_gids
);
2406 return cache_status
;
2409 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
2413 refresh_sequence_number(domain
, false);
2414 if (!NT_STATUS_IS_OK(status
)) {
2417 centry
= centry_start(domain
, status
);
2421 centry_put_uint32(centry
, *num_groups
);
2422 for (i
=0; i
<(*num_groups
); i
++) {
2423 centry_put_sid(centry
, &(*user_gids
)[i
]);
2426 centry_end(centry
, "UG/%s", sid_to_fstring(sid_string
, user_sid
));
2427 centry_free(centry
);
2433 static char *wcache_make_sidlist(TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2434 const struct dom_sid
*sids
)
2439 sidlist
= talloc_strdup(mem_ctx
, "");
2440 if (sidlist
== NULL
) {
2443 for (i
=0; i
<num_sids
; i
++) {
2445 sidlist
= talloc_asprintf_append_buffer(
2446 sidlist
, "/%s", sid_to_fstring(tmp
, &sids
[i
]));
2447 if (sidlist
== NULL
) {
2454 NTSTATUS
wcache_lookup_useraliases(struct winbindd_domain
*domain
,
2455 TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2456 const struct dom_sid
*sids
,
2457 uint32_t *pnum_aliases
, uint32_t **paliases
)
2459 struct winbind_cache
*cache
= get_cache(domain
);
2460 struct cache_entry
*centry
= NULL
;
2461 uint32_t num_aliases
;
2467 if (cache
->tdb
== NULL
) {
2468 return NT_STATUS_NOT_FOUND
;
2471 if (num_sids
== 0) {
2474 return NT_STATUS_OK
;
2477 /* We need to cache indexed by the whole list of SIDs, the aliases
2478 * resulting might come from any of the SIDs. */
2480 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2481 if (sidlist
== NULL
) {
2482 return NT_STATUS_NO_MEMORY
;
2485 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2486 TALLOC_FREE(sidlist
);
2487 if (centry
== NULL
) {
2488 return NT_STATUS_NOT_FOUND
;
2491 num_aliases
= centry_uint32(centry
);
2492 aliases
= talloc_array(mem_ctx
, uint32_t, num_aliases
);
2493 if (aliases
== NULL
) {
2494 centry_free(centry
);
2495 return NT_STATUS_NO_MEMORY
;
2498 for (i
=0; i
<num_aliases
; i
++) {
2499 aliases
[i
] = centry_uint32(centry
);
2502 status
= centry
->status
;
2504 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2505 "status %s\n", domain
->name
, nt_errstr(status
)));
2507 centry_free(centry
);
2509 *pnum_aliases
= num_aliases
;
2510 *paliases
= aliases
;
2515 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
2516 TALLOC_CTX
*mem_ctx
,
2517 uint32 num_sids
, const struct dom_sid
*sids
,
2518 uint32
*num_aliases
, uint32
**alias_rids
)
2520 struct cache_entry
*centry
= NULL
;
2526 old_status
= domain
->online
;
2527 status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
2528 num_aliases
, alias_rids
);
2529 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2534 (*alias_rids
) = NULL
;
2536 if (!NT_STATUS_IS_OK(domain
->last_status
))
2537 return domain
->last_status
;
2539 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2540 "for domain %s\n", domain
->name
));
2542 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2543 if (sidlist
== NULL
) {
2544 return NT_STATUS_NO_MEMORY
;
2547 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2549 num_aliases
, alias_rids
);
2551 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2552 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2553 if (!domain
->internal
&& old_status
) {
2554 set_domain_offline(domain
);
2556 if (!domain
->internal
&&
2559 NTSTATUS cache_status
;
2560 cache_status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
,
2561 sids
, num_aliases
, alias_rids
);
2562 return cache_status
;
2566 refresh_sequence_number(domain
, false);
2567 if (!NT_STATUS_IS_OK(status
)) {
2570 centry
= centry_start(domain
, status
);
2573 centry_put_uint32(centry
, *num_aliases
);
2574 for (i
=0; i
<(*num_aliases
); i
++)
2575 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2576 centry_end(centry
, "UA%s", sidlist
);
2577 centry_free(centry
);
2583 NTSTATUS
wcache_lookup_groupmem(struct winbindd_domain
*domain
,
2584 TALLOC_CTX
*mem_ctx
,
2585 const struct dom_sid
*group_sid
,
2586 uint32_t *num_names
,
2587 struct dom_sid
**sid_mem
, char ***names
,
2588 uint32_t **name_types
)
2590 struct winbind_cache
*cache
= get_cache(domain
);
2591 struct cache_entry
*centry
= NULL
;
2596 if (cache
->tdb
== NULL
) {
2597 return NT_STATUS_NOT_FOUND
;
2600 sid_string
= sid_string_tos(group_sid
);
2601 if (sid_string
== NULL
) {
2602 return NT_STATUS_NO_MEMORY
;
2605 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_string
);
2606 TALLOC_FREE(sid_string
);
2607 if (centry
== NULL
) {
2608 return NT_STATUS_NOT_FOUND
;
2615 *num_names
= centry_uint32(centry
);
2616 if (*num_names
== 0) {
2617 centry_free(centry
);
2618 return NT_STATUS_OK
;
2621 *sid_mem
= talloc_array(mem_ctx
, struct dom_sid
, *num_names
);
2622 *names
= talloc_array(mem_ctx
, char *, *num_names
);
2623 *name_types
= talloc_array(mem_ctx
, uint32
, *num_names
);
2625 if ((*sid_mem
== NULL
) || (*names
== NULL
) || (*name_types
== NULL
)) {
2626 TALLOC_FREE(*sid_mem
);
2627 TALLOC_FREE(*names
);
2628 TALLOC_FREE(*name_types
);
2629 centry_free(centry
);
2630 return NT_STATUS_NO_MEMORY
;
2633 for (i
=0; i
<(*num_names
); i
++) {
2634 centry_sid(centry
, &(*sid_mem
)[i
]);
2635 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2636 (*name_types
)[i
] = centry_uint32(centry
);
2639 status
= centry
->status
;
2641 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2642 "status: %s\n", domain
->name
, nt_errstr(status
)));
2644 centry_free(centry
);
2648 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
2649 TALLOC_CTX
*mem_ctx
,
2650 const struct dom_sid
*group_sid
,
2651 enum lsa_SidType type
,
2653 struct dom_sid
**sid_mem
, char ***names
,
2654 uint32
**name_types
)
2656 struct cache_entry
*centry
= NULL
;
2662 old_status
= domain
->online
;
2663 status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2664 sid_mem
, names
, name_types
);
2665 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2672 (*name_types
) = NULL
;
2674 /* Return status value returned by seq number check */
2676 if (!NT_STATUS_IS_OK(domain
->last_status
))
2677 return domain
->last_status
;
2679 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2682 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
,
2684 sid_mem
, names
, name_types
);
2686 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2687 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2688 if (!domain
->internal
&& old_status
) {
2689 set_domain_offline(domain
);
2691 if (!domain
->internal
&&
2694 NTSTATUS cache_status
;
2695 cache_status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
,
2696 num_names
, sid_mem
, names
,
2698 return cache_status
;
2702 refresh_sequence_number(domain
, false);
2703 if (!NT_STATUS_IS_OK(status
)) {
2706 centry
= centry_start(domain
, status
);
2709 centry_put_uint32(centry
, *num_names
);
2710 for (i
=0; i
<(*num_names
); i
++) {
2711 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2712 centry_put_string(centry
, (*names
)[i
]);
2713 centry_put_uint32(centry
, (*name_types
)[i
]);
2715 centry_end(centry
, "GM/%s", sid_to_fstring(sid_string
, group_sid
));
2716 centry_free(centry
);
2722 /* find the sequence number for a domain */
2723 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
2725 refresh_sequence_number(domain
, false);
2727 *seq
= domain
->sequence_number
;
2729 return NT_STATUS_OK
;
2732 /* enumerate trusted domains
2733 * (we need to have the list of trustdoms in the cache when we go offline) -
2735 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
2736 TALLOC_CTX
*mem_ctx
,
2737 struct netr_DomainTrustList
*trusts
)
2740 struct winbind_cache
*cache
;
2741 struct winbindd_tdc_domain
*dom_list
= NULL
;
2742 size_t num_domains
= 0;
2743 bool retval
= false;
2747 old_status
= domain
->online
;
2749 trusts
->array
= NULL
;
2751 cache
= get_cache(domain
);
2752 if (!cache
|| !cache
->tdb
) {
2756 if (domain
->online
) {
2760 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2761 if (!retval
|| !num_domains
|| !dom_list
) {
2762 TALLOC_FREE(dom_list
);
2767 trusts
->array
= TALLOC_ZERO_ARRAY(mem_ctx
, struct netr_DomainTrust
, num_domains
);
2768 if (!trusts
->array
) {
2769 TALLOC_FREE(dom_list
);
2770 return NT_STATUS_NO_MEMORY
;
2773 for (i
= 0; i
< num_domains
; i
++) {
2774 struct netr_DomainTrust
*trust
;
2775 struct dom_sid
*sid
;
2776 struct winbindd_domain
*dom
;
2778 dom
= find_domain_from_name_noinit(dom_list
[i
].domain_name
);
2779 if (dom
&& dom
->internal
) {
2783 trust
= &trusts
->array
[trusts
->count
];
2784 trust
->netbios_name
= talloc_strdup(trusts
->array
, dom_list
[i
].domain_name
);
2785 trust
->dns_name
= talloc_strdup(trusts
->array
, dom_list
[i
].dns_name
);
2786 sid
= talloc(trusts
->array
, struct dom_sid
);
2787 if (!trust
->netbios_name
|| !trust
->dns_name
||
2789 TALLOC_FREE(dom_list
);
2790 TALLOC_FREE(trusts
->array
);
2791 return NT_STATUS_NO_MEMORY
;
2794 trust
->trust_flags
= dom_list
[i
].trust_flags
;
2795 trust
->trust_attributes
= dom_list
[i
].trust_attribs
;
2796 trust
->trust_type
= dom_list
[i
].trust_type
;
2797 sid_copy(sid
, &dom_list
[i
].sid
);
2802 TALLOC_FREE(dom_list
);
2803 return NT_STATUS_OK
;
2806 /* Return status value returned by seq number check */
2808 if (!NT_STATUS_IS_OK(domain
->last_status
))
2809 return domain
->last_status
;
2811 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2814 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, trusts
);
2816 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2817 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2818 if (!domain
->internal
&& old_status
) {
2819 set_domain_offline(domain
);
2821 if (!domain
->internal
&&
2824 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2825 if (retval
&& num_domains
&& dom_list
) {
2826 TALLOC_FREE(trusts
->array
);
2828 goto do_fetch_cache
;
2832 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2833 * so that the generic centry handling still applies correctly -
2836 if (!NT_STATUS_IS_ERR(status
)) {
2837 status
= NT_STATUS_OK
;
2842 /* get lockout policy */
2843 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
2844 TALLOC_CTX
*mem_ctx
,
2845 struct samr_DomInfo12
*policy
)
2847 struct winbind_cache
*cache
= get_cache(domain
);
2848 struct cache_entry
*centry
= NULL
;
2852 old_status
= domain
->online
;
2856 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2862 policy
->lockout_duration
= centry_nttime(centry
);
2863 policy
->lockout_window
= centry_nttime(centry
);
2864 policy
->lockout_threshold
= centry_uint16(centry
);
2866 status
= centry
->status
;
2868 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2869 domain
->name
, nt_errstr(status
) ));
2871 centry_free(centry
);
2875 ZERO_STRUCTP(policy
);
2877 /* Return status value returned by seq number check */
2879 if (!NT_STATUS_IS_OK(domain
->last_status
))
2880 return domain
->last_status
;
2882 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2885 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2887 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2888 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2889 if (!domain
->internal
&& old_status
) {
2890 set_domain_offline(domain
);
2893 !domain
->internal
&&
2896 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2898 goto do_fetch_cache
;
2903 refresh_sequence_number(domain
, false);
2904 if (!NT_STATUS_IS_OK(status
)) {
2907 wcache_save_lockout_policy(domain
, status
, policy
);
2912 /* get password policy */
2913 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
2914 TALLOC_CTX
*mem_ctx
,
2915 struct samr_DomInfo1
*policy
)
2917 struct winbind_cache
*cache
= get_cache(domain
);
2918 struct cache_entry
*centry
= NULL
;
2922 old_status
= domain
->online
;
2926 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2932 policy
->min_password_length
= centry_uint16(centry
);
2933 policy
->password_history_length
= centry_uint16(centry
);
2934 policy
->password_properties
= centry_uint32(centry
);
2935 policy
->max_password_age
= centry_nttime(centry
);
2936 policy
->min_password_age
= centry_nttime(centry
);
2938 status
= centry
->status
;
2940 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2941 domain
->name
, nt_errstr(status
) ));
2943 centry_free(centry
);
2947 ZERO_STRUCTP(policy
);
2949 /* Return status value returned by seq number check */
2951 if (!NT_STATUS_IS_OK(domain
->last_status
))
2952 return domain
->last_status
;
2954 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2957 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
2959 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2960 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2961 if (!domain
->internal
&& old_status
) {
2962 set_domain_offline(domain
);
2965 !domain
->internal
&&
2968 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2970 goto do_fetch_cache
;
2975 refresh_sequence_number(domain
, false);
2976 if (!NT_STATUS_IS_OK(status
)) {
2979 wcache_save_password_policy(domain
, status
, policy
);
2985 /* Invalidate cached user and group lists coherently */
2987 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2990 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
2991 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
2992 tdb_delete(the_tdb
, kbuf
);
2997 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2999 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
3000 struct netr_SamInfo3
*info3
)
3003 fstring key_str
, sid_string
;
3004 struct winbind_cache
*cache
;
3006 /* dont clear cached U/SID and UG/SID entries when we want to logon
3009 if (lp_winbind_offline_logon()) {
3016 cache
= get_cache(domain
);
3022 sid_compose(&sid
, info3
->base
.domain_sid
, info3
->base
.rid
);
3024 /* Clear U/SID cache entry */
3025 fstr_sprintf(key_str
, "U/%s", sid_to_fstring(sid_string
, &sid
));
3026 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3027 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3029 /* Clear UG/SID cache entry */
3030 fstr_sprintf(key_str
, "UG/%s", sid_to_fstring(sid_string
, &sid
));
3031 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3032 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3034 /* Samba/winbindd never needs this. */
3035 netsamlogon_clear_cached_user(info3
);
3038 bool wcache_invalidate_cache(void)
3040 struct winbindd_domain
*domain
;
3042 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3043 struct winbind_cache
*cache
= get_cache(domain
);
3045 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3046 "entries for %s\n", domain
->name
));
3049 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3058 bool wcache_invalidate_cache_noinit(void)
3060 struct winbindd_domain
*domain
;
3062 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3063 struct winbind_cache
*cache
;
3065 /* Skip uninitialized domains. */
3066 if (!domain
->initialized
&& !domain
->internal
) {
3070 cache
= get_cache(domain
);
3072 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3073 "entries for %s\n", domain
->name
));
3076 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3078 * Flushing cache has nothing to with domains.
3079 * return here if we successfully flushed once.
3080 * To avoid unnecessary traversing the cache.
3091 bool init_wcache(void)
3093 if (wcache
== NULL
) {
3094 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
3095 ZERO_STRUCTP(wcache
);
3098 if (wcache
->tdb
!= NULL
)
3101 /* when working offline we must not clear the cache on restart */
3102 wcache
->tdb
= tdb_open_log(cache_path("winbindd_cache.tdb"),
3103 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3104 lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
3105 O_RDWR
|O_CREAT
, 0600);
3107 if (wcache
->tdb
== NULL
) {
3108 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3115 /************************************************************************
3116 This is called by the parent to initialize the cache file.
3117 We don't need sophisticated locking here as we know we're the
3119 ************************************************************************/
3121 bool initialize_winbindd_cache(void)
3123 bool cache_bad
= true;
3126 if (!init_wcache()) {
3127 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3131 /* Check version number. */
3132 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
3133 vers
== WINBINDD_CACHE_VERSION
) {
3138 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3139 "and re-creating with version number %d\n",
3140 WINBINDD_CACHE_VERSION
));
3142 tdb_close(wcache
->tdb
);
3145 if (unlink(cache_path("winbindd_cache.tdb")) == -1) {
3146 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3147 cache_path("winbindd_cache.tdb"),
3151 if (!init_wcache()) {
3152 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3153 "init_wcache failed.\n"));
3157 /* Write the version. */
3158 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
3159 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3160 tdb_errorstr(wcache
->tdb
) ));
3165 tdb_close(wcache
->tdb
);
3170 void close_winbindd_cache(void)
3176 tdb_close(wcache
->tdb
);
3181 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*sid
,
3182 char **domain_name
, char **name
,
3183 enum lsa_SidType
*type
)
3185 struct winbindd_domain
*domain
;
3188 domain
= find_lookup_domain_from_sid(sid
);
3189 if (domain
== NULL
) {
3192 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
3194 return NT_STATUS_IS_OK(status
);
3197 bool lookup_cached_name(TALLOC_CTX
*mem_ctx
,
3198 const char *domain_name
,
3200 struct dom_sid
*sid
,
3201 enum lsa_SidType
*type
)
3203 struct winbindd_domain
*domain
;
3205 bool original_online_state
;
3207 domain
= find_lookup_domain_from_name(domain_name
);
3208 if (domain
== NULL
) {
3212 /* If we are doing a cached logon, temporarily set the domain
3213 offline so the cache won't expire the entry */
3215 original_online_state
= domain
->online
;
3216 domain
->online
= false;
3217 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
3218 domain
->online
= original_online_state
;
3220 return NT_STATUS_IS_OK(status
);
3223 void cache_name2sid(struct winbindd_domain
*domain
,
3224 const char *domain_name
, const char *name
,
3225 enum lsa_SidType type
, const struct dom_sid
*sid
)
3227 refresh_sequence_number(domain
, false);
3228 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
3233 * The original idea that this cache only contains centries has
3234 * been blurred - now other stuff gets put in here. Ensure we
3235 * ignore these things on cleanup.
3238 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
3239 TDB_DATA dbuf
, void *state
)
3241 struct cache_entry
*centry
;
3243 if (is_non_centry_key(kbuf
)) {
3247 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
3252 if (!NT_STATUS_IS_OK(centry
->status
)) {
3253 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
3254 tdb_delete(the_tdb
, kbuf
);
3257 centry_free(centry
);
3261 /* flush the cache */
3262 void wcache_flush_cache(void)
3267 tdb_close(wcache
->tdb
);
3270 if (!winbindd_use_cache()) {
3274 /* when working offline we must not clear the cache on restart */
3275 wcache
->tdb
= tdb_open_log(cache_path("winbindd_cache.tdb"),
3276 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3277 lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
3278 O_RDWR
|O_CREAT
, 0600);
3281 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3285 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
3287 DEBUG(10,("wcache_flush_cache success\n"));
3290 /* Count cached creds */
3292 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3295 int *cred_count
= (int*)state
;
3297 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3303 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
3305 struct winbind_cache
*cache
= get_cache(domain
);
3310 return NT_STATUS_INTERNAL_DB_ERROR
;
3313 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
3315 return NT_STATUS_OK
;
3319 struct cred_list
*prev
, *next
;
3324 static struct cred_list
*wcache_cred_list
;
3326 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3329 struct cred_list
*cred
;
3331 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3333 cred
= SMB_MALLOC_P(struct cred_list
);
3335 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3341 /* save a copy of the key */
3343 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
3344 DLIST_ADD(wcache_cred_list
, cred
);
3350 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
3352 struct winbind_cache
*cache
= get_cache(domain
);
3355 struct cred_list
*cred
, *oldest
= NULL
;
3358 return NT_STATUS_INTERNAL_DB_ERROR
;
3361 /* we possibly already have an entry */
3362 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
3364 fstring key_str
, tmp
;
3366 DEBUG(11,("we already have an entry, deleting that\n"));
3368 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
3370 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3372 return NT_STATUS_OK
;
3375 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
3377 return NT_STATUS_OK
;
3378 } else if ((ret
== -1) || (wcache_cred_list
== NULL
)) {
3379 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3382 ZERO_STRUCTP(oldest
);
3384 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
3389 data
= tdb_fetch(cache
->tdb
, string_tdb_data(cred
->name
));
3391 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3393 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3397 t
= IVAL(data
.dptr
, 0);
3398 SAFE_FREE(data
.dptr
);
3401 oldest
= SMB_MALLOC_P(struct cred_list
);
3402 if (oldest
== NULL
) {
3403 status
= NT_STATUS_NO_MEMORY
;
3407 fstrcpy(oldest
->name
, cred
->name
);
3408 oldest
->created
= t
;
3412 if (t
< oldest
->created
) {
3413 fstrcpy(oldest
->name
, cred
->name
);
3414 oldest
->created
= t
;
3418 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3419 status
= NT_STATUS_OK
;
3421 status
= NT_STATUS_UNSUCCESSFUL
;
3424 SAFE_FREE(wcache_cred_list
);
3430 /* Change the global online/offline state. */
3431 bool set_global_winbindd_state_offline(void)
3435 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3437 /* Only go offline if someone has created
3438 the key "WINBINDD_OFFLINE" in the cache tdb. */
3440 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3441 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3445 if (!lp_winbind_offline_logon()) {
3446 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3450 if (global_winbindd_offline_state
) {
3451 /* Already offline. */
3455 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
3457 if (!data
.dptr
|| data
.dsize
!= 4) {
3458 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3459 SAFE_FREE(data
.dptr
);
3462 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3463 global_winbindd_offline_state
= true;
3464 SAFE_FREE(data
.dptr
);
3469 void set_global_winbindd_state_online(void)
3471 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3473 if (!lp_winbind_offline_logon()) {
3474 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3478 if (!global_winbindd_offline_state
) {
3479 /* Already online. */
3482 global_winbindd_offline_state
= false;
3488 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3489 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3492 bool get_global_winbindd_state_offline(void)
3494 return global_winbindd_offline_state
;
3497 /***********************************************************************
3498 Validate functions for all possible cache tdb keys.
3499 ***********************************************************************/
3501 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3502 struct tdb_validation_status
*state
)
3504 struct cache_entry
*centry
;
3506 centry
= SMB_XMALLOC_P(struct cache_entry
);
3507 centry
->data
= (unsigned char *)memdup(data
.dptr
, data
.dsize
);
3508 if (!centry
->data
) {
3512 centry
->len
= data
.dsize
;
3515 if (centry
->len
< 8) {
3516 /* huh? corrupt cache? */
3517 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr
));
3518 centry_free(centry
);
3519 state
->bad_entry
= true;
3520 state
->success
= false;
3524 centry
->status
= NT_STATUS(centry_uint32(centry
));
3525 centry
->sequence_number
= centry_uint32(centry
);
3529 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3530 struct tdb_validation_status
*state
)
3532 if (dbuf
.dsize
!= 8) {
3533 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3534 keystr
, (unsigned int)dbuf
.dsize
));
3535 state
->bad_entry
= true;
3541 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3542 struct tdb_validation_status
*state
)
3544 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3549 (void)centry_uint32(centry
);
3550 if (NT_STATUS_IS_OK(centry
->status
)) {
3552 (void)centry_sid(centry
, &sid
);
3555 centry_free(centry
);
3557 if (!(state
->success
)) {
3560 DEBUG(10,("validate_ns: %s ok\n", keystr
));
3564 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3565 struct tdb_validation_status
*state
)
3567 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3572 if (NT_STATUS_IS_OK(centry
->status
)) {
3573 (void)centry_uint32(centry
);
3574 (void)centry_string(centry
, mem_ctx
);
3575 (void)centry_string(centry
, mem_ctx
);
3578 centry_free(centry
);
3580 if (!(state
->success
)) {
3583 DEBUG(10,("validate_sn: %s ok\n", keystr
));
3587 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3588 struct tdb_validation_status
*state
)
3590 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3597 (void)centry_string(centry
, mem_ctx
);
3598 (void)centry_string(centry
, mem_ctx
);
3599 (void)centry_string(centry
, mem_ctx
);
3600 (void)centry_string(centry
, mem_ctx
);
3601 (void)centry_uint32(centry
);
3602 (void)centry_sid(centry
, &sid
);
3603 (void)centry_sid(centry
, &sid
);
3605 centry_free(centry
);
3607 if (!(state
->success
)) {
3610 DEBUG(10,("validate_u: %s ok\n", keystr
));
3614 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3615 struct tdb_validation_status
*state
)
3617 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3623 (void)centry_nttime(centry
);
3624 (void)centry_nttime(centry
);
3625 (void)centry_uint16(centry
);
3627 centry_free(centry
);
3629 if (!(state
->success
)) {
3632 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3636 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3637 struct tdb_validation_status
*state
)
3639 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3645 (void)centry_uint16(centry
);
3646 (void)centry_uint16(centry
);
3647 (void)centry_uint32(centry
);
3648 (void)centry_nttime(centry
);
3649 (void)centry_nttime(centry
);
3651 centry_free(centry
);
3653 if (!(state
->success
)) {
3656 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3660 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3661 struct tdb_validation_status
*state
)
3663 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3669 (void)centry_time(centry
);
3670 (void)centry_hash16(centry
, mem_ctx
);
3672 /* We only have 17 bytes more data in the salted cred case. */
3673 if (centry
->len
- centry
->ofs
== 17) {
3674 (void)centry_hash16(centry
, mem_ctx
);
3677 centry_free(centry
);
3679 if (!(state
->success
)) {
3682 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3686 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3687 struct tdb_validation_status
*state
)
3689 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3690 int32 num_entries
, i
;
3696 num_entries
= (int32
)centry_uint32(centry
);
3698 for (i
=0; i
< num_entries
; i
++) {
3700 (void)centry_string(centry
, mem_ctx
);
3701 (void)centry_string(centry
, mem_ctx
);
3702 (void)centry_string(centry
, mem_ctx
);
3703 (void)centry_string(centry
, mem_ctx
);
3704 (void)centry_sid(centry
, &sid
);
3705 (void)centry_sid(centry
, &sid
);
3708 centry_free(centry
);
3710 if (!(state
->success
)) {
3713 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3717 static int validate_gl(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
= centry_uint32(centry
);
3729 for (i
=0; i
< num_entries
; i
++) {
3730 (void)centry_string(centry
, mem_ctx
);
3731 (void)centry_string(centry
, mem_ctx
);
3732 (void)centry_uint32(centry
);
3735 centry_free(centry
);
3737 if (!(state
->success
)) {
3740 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3744 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3745 struct tdb_validation_status
*state
)
3747 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3748 int32 num_groups
, i
;
3754 num_groups
= centry_uint32(centry
);
3756 for (i
=0; i
< num_groups
; i
++) {
3758 centry_sid(centry
, &sid
);
3761 centry_free(centry
);
3763 if (!(state
->success
)) {
3766 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3770 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3771 struct tdb_validation_status
*state
)
3773 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3774 int32 num_aliases
, i
;
3780 num_aliases
= centry_uint32(centry
);
3782 for (i
=0; i
< num_aliases
; i
++) {
3783 (void)centry_uint32(centry
);
3786 centry_free(centry
);
3788 if (!(state
->success
)) {
3791 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3795 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3796 struct tdb_validation_status
*state
)
3798 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3805 num_names
= centry_uint32(centry
);
3807 for (i
=0; i
< num_names
; i
++) {
3809 centry_sid(centry
, &sid
);
3810 (void)centry_string(centry
, mem_ctx
);
3811 (void)centry_uint32(centry
);
3814 centry_free(centry
);
3816 if (!(state
->success
)) {
3819 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3823 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3824 struct tdb_validation_status
*state
)
3826 /* Can't say anything about this other than must be nonzero. */
3827 if (dbuf
.dsize
== 0) {
3828 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3830 state
->bad_entry
= true;
3831 state
->success
= false;
3835 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3839 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3840 struct tdb_validation_status
*state
)
3842 /* Can't say anything about this other than must be nonzero. */
3843 if (dbuf
.dsize
== 0) {
3844 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3846 state
->bad_entry
= true;
3847 state
->success
= false;
3851 DEBUG(10,("validate_de: %s ok\n", keystr
));
3855 static int validate_pwinfo(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3856 TDB_DATA dbuf
, struct tdb_validation_status
*state
)
3858 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3864 (void)centry_string(centry
, mem_ctx
);
3865 (void)centry_string(centry
, mem_ctx
);
3866 (void)centry_string(centry
, mem_ctx
);
3867 (void)centry_uint32(centry
);
3869 centry_free(centry
);
3871 if (!(state
->success
)) {
3874 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3878 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3880 struct tdb_validation_status
*state
)
3882 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3888 (void)centry_string( centry
, mem_ctx
);
3890 centry_free(centry
);
3892 if (!(state
->success
)) {
3895 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3899 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3901 struct tdb_validation_status
*state
)
3903 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3909 (void)centry_string( centry
, mem_ctx
);
3911 centry_free(centry
);
3913 if (!(state
->success
)) {
3916 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3920 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3922 struct tdb_validation_status
*state
)
3924 if (dbuf
.dsize
== 0) {
3925 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3926 "key %s (len ==0) ?\n", keystr
));
3927 state
->bad_entry
= true;
3928 state
->success
= false;
3932 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3933 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3937 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3938 struct tdb_validation_status
*state
)
3940 if (dbuf
.dsize
!= 4) {
3941 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3942 keystr
, (unsigned int)dbuf
.dsize
));
3943 state
->bad_entry
= true;
3944 state
->success
= false;
3947 DEBUG(10,("validate_offline: %s ok\n", keystr
));
3951 static int validate_ndr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3952 struct tdb_validation_status
*state
)
3955 * Ignore validation for now. The proper way to do this is with a
3956 * checksum. Just pure parsing does not really catch much.
3961 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3962 struct tdb_validation_status
*state
)
3964 if (dbuf
.dsize
!= 4) {
3965 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3966 "key %s (len %u != 4) ?\n",
3967 keystr
, (unsigned int)dbuf
.dsize
));
3968 state
->bad_entry
= true;
3969 state
->success
= false;
3973 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
3977 /***********************************************************************
3978 A list of all possible cache tdb keys with associated validation
3980 ***********************************************************************/
3982 struct key_val_struct
{
3983 const char *keyname
;
3984 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
3986 {"SEQNUM/", validate_seqnum
},
3987 {"NS/", validate_ns
},
3988 {"SN/", validate_sn
},
3990 {"LOC_POL/", validate_loc_pol
},
3991 {"PWD_POL/", validate_pwd_pol
},
3992 {"CRED/", validate_cred
},
3993 {"UL/", validate_ul
},
3994 {"GL/", validate_gl
},
3995 {"UG/", validate_ug
},
3996 {"UA", validate_ua
},
3997 {"GM/", validate_gm
},
3998 {"DR/", validate_dr
},
3999 {"DE/", validate_de
},
4000 {"NSS/PWINFO/", validate_pwinfo
},
4001 {"TRUSTDOMCACHE/", validate_trustdomcache
},
4002 {"NSS/NA/", validate_nss_na
},
4003 {"NSS/AN/", validate_nss_an
},
4004 {"WINBINDD_OFFLINE", validate_offline
},
4005 {"NDR/", validate_ndr
},
4006 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
4010 /***********************************************************************
4011 Function to look at every entry in the tdb and validate it as far as
4013 ***********************************************************************/
4015 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
4018 unsigned int max_key_len
= 1024;
4019 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
4021 /* Paranoia check. */
4022 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0) {
4023 max_key_len
= 1024 * 1024;
4025 if (kbuf
.dsize
> max_key_len
) {
4026 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4028 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
4032 for (i
= 0; key_val
[i
].keyname
; i
++) {
4033 size_t namelen
= strlen(key_val
[i
].keyname
);
4034 if (kbuf
.dsize
>= namelen
&& (
4035 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
4036 TALLOC_CTX
*mem_ctx
;
4040 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
4044 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
4045 keystr
[kbuf
.dsize
] = '\0';
4047 mem_ctx
= talloc_init("validate_ctx");
4053 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
4057 talloc_destroy(mem_ctx
);
4062 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4063 dump_data(0, (uint8
*)kbuf
.dptr
, kbuf
.dsize
);
4064 DEBUG(0,("data :\n"));
4065 dump_data(0, (uint8
*)dbuf
.dptr
, dbuf
.dsize
);
4066 v_state
->unknown_key
= true;
4067 v_state
->success
= false;
4068 return 1; /* terminate. */
4071 static void validate_panic(const char *const why
)
4073 DEBUG(0,("validating cache: would panic %s\n", why
));
4074 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4078 /***********************************************************************
4079 Try and validate every entry in the winbindd cache. If we fail here,
4080 delete the cache tdb and return non-zero.
4081 ***********************************************************************/
4083 int winbindd_validate_cache(void)
4086 const char *tdb_path
= cache_path("winbindd_cache.tdb");
4087 TDB_CONTEXT
*tdb
= NULL
;
4089 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4090 smb_panic_fn
= validate_panic
;
4093 tdb
= tdb_open_log(tdb_path
,
4094 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
4095 ( lp_winbind_offline_logon()
4097 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
4101 DEBUG(0, ("winbindd_validate_cache: "
4102 "error opening/initializing tdb\n"));
4107 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
4110 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4111 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
4116 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4117 smb_panic_fn
= smb_panic
;
4121 /***********************************************************************
4122 Try and validate every entry in the winbindd cache.
4123 ***********************************************************************/
4125 int winbindd_validate_cache_nobackup(void)
4128 const char *tdb_path
= cache_path("winbindd_cache.tdb");
4130 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4131 smb_panic_fn
= validate_panic
;
4134 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
4135 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
4137 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
4141 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4145 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4147 smb_panic_fn
= smb_panic
;
4151 bool winbindd_cache_validate_and_initialize(void)
4153 close_winbindd_cache();
4155 if (lp_winbind_offline_logon()) {
4156 if (winbindd_validate_cache() < 0) {
4157 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4158 "could be restored.\n"));
4162 return initialize_winbindd_cache();
4165 /*********************************************************************
4166 ********************************************************************/
4168 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
4169 struct winbindd_tdc_domain
**domains
,
4170 size_t *num_domains
)
4172 struct winbindd_tdc_domain
*list
= NULL
;
4175 bool set_only
= false;
4177 /* don't allow duplicates */
4182 for ( i
=0; i
< (*num_domains
); i
++ ) {
4183 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
4184 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4195 list
= TALLOC_ARRAY( NULL
, struct winbindd_tdc_domain
, 1 );
4198 list
= TALLOC_REALLOC_ARRAY( *domains
, *domains
,
4199 struct winbindd_tdc_domain
,
4204 ZERO_STRUCT( list
[idx
] );
4210 list
[idx
].domain_name
= talloc_strdup( list
, new_dom
->name
);
4211 list
[idx
].dns_name
= talloc_strdup( list
, new_dom
->alt_name
);
4213 if ( !is_null_sid( &new_dom
->sid
) ) {
4214 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
4216 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
4219 if ( new_dom
->domain_flags
!= 0x0 )
4220 list
[idx
].trust_flags
= new_dom
->domain_flags
;
4222 if ( new_dom
->domain_type
!= 0x0 )
4223 list
[idx
].trust_type
= new_dom
->domain_type
;
4225 if ( new_dom
->domain_trust_attribs
!= 0x0 )
4226 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
4230 *num_domains
= idx
+ 1;
4236 /*********************************************************************
4237 ********************************************************************/
4239 static TDB_DATA
make_tdc_key( const char *domain_name
)
4241 char *keystr
= NULL
;
4242 TDB_DATA key
= { NULL
, 0 };
4244 if ( !domain_name
) {
4245 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4249 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
4252 key
= string_term_tdb_data(keystr
);
4257 /*********************************************************************
4258 ********************************************************************/
4260 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
4262 unsigned char **buf
)
4264 unsigned char *buffer
= NULL
;
4269 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4277 /* Store the number of array items first */
4278 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
4281 /* now pack each domain trust record */
4282 for ( i
=0; i
<num_domains
; i
++ ) {
4287 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4288 domains
[i
].domain_name
,
4289 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
4292 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
4293 domains
[i
].domain_name
,
4294 domains
[i
].dns_name
,
4295 sid_to_fstring(tmp
, &domains
[i
].sid
),
4296 domains
[i
].trust_flags
,
4297 domains
[i
].trust_attribs
,
4298 domains
[i
].trust_type
);
4301 if ( buflen
< len
) {
4303 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
4304 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4318 /*********************************************************************
4319 ********************************************************************/
4321 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
4322 struct winbindd_tdc_domain
**domains
)
4324 fstring domain_name
, dns_name
, sid_string
;
4325 uint32 type
, attribs
, flags
;
4329 struct winbindd_tdc_domain
*list
= NULL
;
4331 /* get the number of domains */
4332 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
4334 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4338 list
= TALLOC_ARRAY( NULL
, struct winbindd_tdc_domain
, num_domains
);
4340 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4344 for ( i
=0; i
<num_domains
; i
++ ) {
4345 len
+= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
4354 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4355 TALLOC_FREE( list
);
4359 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4360 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4361 domain_name
, dns_name
, sid_string
,
4362 flags
, attribs
, type
));
4364 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
4365 list
[i
].dns_name
= talloc_strdup( list
, dns_name
);
4366 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
4367 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4370 list
[i
].trust_flags
= flags
;
4371 list
[i
].trust_attribs
= attribs
;
4372 list
[i
].trust_type
= type
;
4380 /*********************************************************************
4381 ********************************************************************/
4383 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
4385 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4386 TDB_DATA data
= { NULL
, 0 };
4392 /* See if we were asked to delete the cache entry */
4395 ret
= tdb_delete( wcache
->tdb
, key
);
4399 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4406 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4409 SAFE_FREE( data
.dptr
);
4410 SAFE_FREE( key
.dptr
);
4412 return ( ret
!= -1 );
4415 /*********************************************************************
4416 ********************************************************************/
4418 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4420 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4421 TDB_DATA data
= { NULL
, 0 };
4429 data
= tdb_fetch( wcache
->tdb
, key
);
4431 SAFE_FREE( key
.dptr
);
4436 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4438 SAFE_FREE( data
.dptr
);
4446 /*********************************************************************
4447 ********************************************************************/
4449 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4451 struct winbindd_tdc_domain
*dom_list
= NULL
;
4452 size_t num_domains
= 0;
4455 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4456 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4457 domain
->name
, domain
->alt_name
,
4458 sid_string_dbg(&domain
->sid
),
4459 domain
->domain_flags
,
4460 domain
->domain_trust_attribs
,
4461 domain
->domain_type
));
4463 if ( !init_wcache() ) {
4467 /* fetch the list */
4469 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4471 /* add the new domain */
4473 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4477 /* pack the domain */
4479 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4487 TALLOC_FREE( dom_list
);
4492 /*********************************************************************
4493 ********************************************************************/
4495 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4497 struct winbindd_tdc_domain
*dom_list
= NULL
;
4498 size_t num_domains
= 0;
4500 struct winbindd_tdc_domain
*d
= NULL
;
4502 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4504 if ( !init_wcache() ) {
4508 /* fetch the list */
4510 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4512 for ( i
=0; i
<num_domains
; i
++ ) {
4513 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4514 strequal(name
, dom_list
[i
].dns_name
) )
4516 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4519 d
= TALLOC_P( ctx
, struct winbindd_tdc_domain
);
4523 d
->domain_name
= talloc_strdup( d
, dom_list
[i
].domain_name
);
4524 d
->dns_name
= talloc_strdup( d
, dom_list
[i
].dns_name
);
4525 sid_copy( &d
->sid
, &dom_list
[i
].sid
);
4526 d
->trust_flags
= dom_list
[i
].trust_flags
;
4527 d
->trust_type
= dom_list
[i
].trust_type
;
4528 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
4534 TALLOC_FREE( dom_list
);
4540 /*********************************************************************
4541 ********************************************************************/
4543 void wcache_tdc_clear( void )
4545 if ( !init_wcache() )
4548 wcache_tdc_store_list( NULL
, 0 );
4554 /*********************************************************************
4555 ********************************************************************/
4557 static void wcache_save_user_pwinfo(struct winbindd_domain
*domain
,
4559 const struct dom_sid
*user_sid
,
4560 const char *homedir
,
4565 struct cache_entry
*centry
;
4568 if ( (centry
= centry_start(domain
, status
)) == NULL
)
4571 centry_put_string( centry
, homedir
);
4572 centry_put_string( centry
, shell
);
4573 centry_put_string( centry
, gecos
);
4574 centry_put_uint32( centry
, gid
);
4576 centry_end(centry
, "NSS/PWINFO/%s", sid_to_fstring(tmp
, user_sid
) );
4578 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid
) ));
4580 centry_free(centry
);
4583 NTSTATUS
nss_get_info_cached( struct winbindd_domain
*domain
,
4584 const struct dom_sid
*user_sid
,
4586 ADS_STRUCT
*ads
, LDAPMessage
*msg
,
4587 const char **homedir
, const char **shell
,
4588 const char **gecos
, gid_t
*p_gid
)
4590 struct winbind_cache
*cache
= get_cache(domain
);
4591 struct cache_entry
*centry
= NULL
;
4598 centry
= wcache_fetch(cache
, domain
, "NSS/PWINFO/%s",
4599 sid_to_fstring(tmp
, user_sid
));
4604 *homedir
= centry_string( centry
, ctx
);
4605 *shell
= centry_string( centry
, ctx
);
4606 *gecos
= centry_string( centry
, ctx
);
4607 *p_gid
= centry_uint32( centry
);
4609 centry_free(centry
);
4611 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4612 sid_string_dbg(user_sid
)));
4614 return NT_STATUS_OK
;
4618 nt_status
= nss_get_info( domain
->name
, user_sid
, ctx
, ads
, msg
,
4619 homedir
, shell
, gecos
, p_gid
);
4621 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status
)));
4623 if ( NT_STATUS_IS_OK(nt_status
) ) {
4624 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir
));
4625 DEBUGADD(10, ("\tshell = '%s'\n", *shell
));
4626 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos
));
4627 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid
));
4629 wcache_save_user_pwinfo( domain
, nt_status
, user_sid
,
4630 *homedir
, *shell
, *gecos
, *p_gid
);
4633 if ( NT_STATUS_EQUAL( nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
4634 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4636 set_domain_offline( domain
);
4643 /* the cache backend methods are exposed via this structure */
4644 struct winbindd_methods cache_methods
= {
4662 static bool wcache_ndr_key(TALLOC_CTX
*mem_ctx
, char *domain_name
,
4663 uint32_t opnum
, const DATA_BLOB
*req
,
4669 key
= talloc_asprintf(mem_ctx
, "NDR/%s/%d/", domain_name
, (int)opnum
);
4673 keylen
= talloc_get_size(key
) - 1;
4675 key
= talloc_realloc(mem_ctx
, key
, char, keylen
+ req
->length
);
4679 memcpy(key
+ keylen
, req
->data
, req
->length
);
4681 pkey
->dptr
= (uint8_t *)key
;
4682 pkey
->dsize
= talloc_get_size(key
);
4686 static bool wcache_opnum_cacheable(uint32_t opnum
)
4689 case NDR_WBINT_PING
:
4690 case NDR_WBINT_QUERYSEQUENCENUMBER
:
4691 case NDR_WBINT_ALLOCATEUID
:
4692 case NDR_WBINT_ALLOCATEGID
:
4693 case NDR_WBINT_CHECKMACHINEACCOUNT
:
4694 case NDR_WBINT_CHANGEMACHINEACCOUNT
:
4695 case NDR_WBINT_PINGDC
:
4701 bool wcache_fetch_ndr(TALLOC_CTX
*mem_ctx
, struct winbindd_domain
*domain
,
4702 uint32_t opnum
, const DATA_BLOB
*req
, DATA_BLOB
*resp
)
4707 if (!wcache_opnum_cacheable(opnum
) ||
4708 is_my_own_sam_domain(domain
) ||
4709 is_builtin_domain(domain
)) {
4713 if (wcache
->tdb
== NULL
) {
4717 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4720 data
= tdb_fetch(wcache
->tdb
, key
);
4721 TALLOC_FREE(key
.dptr
);
4723 if (data
.dptr
== NULL
) {
4726 if (data
.dsize
< 4) {
4730 if (!is_domain_offline(domain
)) {
4731 uint32_t entry_seqnum
, dom_seqnum
, last_check
;
4733 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
,
4737 entry_seqnum
= IVAL(data
.dptr
, 0);
4738 if (entry_seqnum
!= dom_seqnum
) {
4739 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4740 (int)entry_seqnum
));
4745 resp
->data
= (uint8_t *)talloc_memdup(mem_ctx
, data
.dptr
+ 4,
4747 if (resp
->data
== NULL
) {
4748 DEBUG(10, ("talloc failed\n"));
4751 resp
->length
= data
.dsize
- 4;
4755 SAFE_FREE(data
.dptr
);
4759 void wcache_store_ndr(struct winbindd_domain
*domain
, uint32_t opnum
,
4760 const DATA_BLOB
*req
, const DATA_BLOB
*resp
)
4763 uint32_t dom_seqnum
, last_check
;
4765 if (!wcache_opnum_cacheable(opnum
) ||
4766 is_my_own_sam_domain(domain
) ||
4767 is_builtin_domain(domain
)) {
4771 if (wcache
->tdb
== NULL
) {
4775 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
, &last_check
)) {
4776 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4781 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4785 data
.dsize
= resp
->length
+ 4;
4786 data
.dptr
= talloc_array(key
.dptr
, uint8_t, data
.dsize
);
4787 if (data
.dptr
== NULL
) {
4791 SIVAL(data
.dptr
, 0, dom_seqnum
);
4792 memcpy(data
.dptr
+4, resp
->data
, resp
->length
);
4794 tdb_store(wcache
->tdb
, key
, data
, 0);
4797 TALLOC_FREE(key
.dptr
);