2 Unix SMB/CIFS implementation.
4 Winbind cache backend functions
6 Copyright (C) Andrew Tridgell 2001
7 Copyright (C) Gerald Carter 2003-2007
8 Copyright (C) Volker Lendecke 2005
9 Copyright (C) Guenther Deschner 2005
10 Copyright (C) Michael Adam 2007
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include "system/filesys.h"
29 #include "tdb_validate.h"
30 #include "../libcli/auth/libcli_auth.h"
31 #include "../librpc/gen_ndr/ndr_winbind.h"
34 #include "../libcli/security/security.h"
35 #include "passdb/machine_sid.h"
39 #define DBGC_CLASS DBGC_WINBIND
41 #define WINBINDD_CACHE_VER1 1 /* initial db version */
42 #define WINBINDD_CACHE_VER2 2 /* second version with timeouts for NDR entries */
44 #define WINBINDD_CACHE_VERSION WINBINDD_CACHE_VER2
45 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
47 extern struct winbindd_methods reconnect_methods
;
49 extern struct winbindd_methods ads_methods
;
51 extern struct winbindd_methods builtin_passdb_methods
;
52 extern struct winbindd_methods sam_passdb_methods
;
55 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
56 * Here are the list of entry types that are *not* stored
57 * as form struct cache_entry in the cache.
60 static const char *non_centry_keys
[] = {
63 WINBINDD_CACHE_VERSION_KEYSTR
,
67 /************************************************************************
68 Is this key a non-centry type ?
69 ************************************************************************/
71 static bool is_non_centry_key(TDB_DATA kbuf
)
75 if (kbuf
.dptr
== NULL
|| kbuf
.dsize
== 0) {
78 for (i
= 0; non_centry_keys
[i
] != NULL
; i
++) {
79 size_t namelen
= strlen(non_centry_keys
[i
]);
80 if (kbuf
.dsize
< namelen
) {
83 if (strncmp(non_centry_keys
[i
], (const char *)kbuf
.dptr
, namelen
) == 0) {
90 /* Global online/offline state - False when online. winbindd starts up online
91 and sets this to true if the first query fails and there's an entry in
92 the cache tdb telling us to stay offline. */
94 static bool global_winbindd_offline_state
;
96 struct winbind_cache
{
102 uint32 sequence_number
;
108 void (*smb_panic_fn
)(const char *const why
) = smb_panic
;
110 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
112 static struct winbind_cache
*wcache
;
114 /* get the winbind_cache structure */
115 static struct winbind_cache
*get_cache(struct winbindd_domain
*domain
)
117 struct winbind_cache
*ret
= wcache
;
119 /* We have to know what type of domain we are dealing with first. */
121 if (domain
->internal
) {
122 domain
->backend
= &builtin_passdb_methods
;
125 if (dom_sid_equal(&domain
->sid
, &global_sid_Builtin
)) {
126 domain
->initialized
= true;
129 if (strequal(domain
->name
, get_global_sam_name()) &&
130 sid_check_is_our_sam(&domain
->sid
)) {
131 domain
->backend
= &sam_passdb_methods
;
134 if ( !domain
->initialized
) {
135 /* We do not need a connection to an RW DC for cache operation */
136 init_dc_connection(domain
, false);
140 OK. listen up becasue I'm only going to say this once.
141 We have the following scenarios to consider
142 (a) trusted AD domains on a Samba DC,
143 (b) trusted AD domains and we are joined to a non-kerberos domain
144 (c) trusted AD domains and we are joined to a kerberos (AD) domain
146 For (a) we can always contact the trusted domain using krb5
147 since we have the domain trust account password
149 For (b) we can only use RPC since we have no way of
150 getting a krb5 ticket in our own domain
152 For (c) we can always use krb5 since we have a kerberos trust
157 if (!domain
->backend
) {
159 struct winbindd_domain
*our_domain
= domain
;
161 /* find our domain first so we can figure out if we
162 are joined to a kerberized domain */
164 if ( !domain
->primary
)
165 our_domain
= find_our_domain();
167 if ((our_domain
->active_directory
|| IS_DC
)
168 && domain
->active_directory
169 && !lp_winbind_rpc_only()) {
170 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain
->name
));
171 domain
->backend
= &ads_methods
;
173 #endif /* HAVE_ADS */
174 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain
->name
));
175 domain
->backend
= &reconnect_methods
;
178 #endif /* HAVE_ADS */
184 ret
= SMB_XMALLOC_P(struct winbind_cache
);
188 wcache_flush_cache();
194 free a centry structure
196 static void centry_free(struct cache_entry
*centry
)
200 SAFE_FREE(centry
->data
);
204 static bool centry_check_bytes(struct cache_entry
*centry
, size_t nbytes
)
206 if (centry
->len
- centry
->ofs
< nbytes
) {
207 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
208 (unsigned int)nbytes
,
209 centry
->len
- centry
->ofs
));
216 pull a uint64_t from a cache entry
218 static uint64_t centry_uint64_t(struct cache_entry
*centry
)
222 if (!centry_check_bytes(centry
, 8)) {
223 smb_panic_fn("centry_uint64_t");
225 ret
= BVAL(centry
->data
, centry
->ofs
);
231 pull a uint32 from a cache entry
233 static uint32
centry_uint32(struct cache_entry
*centry
)
237 if (!centry_check_bytes(centry
, 4)) {
238 smb_panic_fn("centry_uint32");
240 ret
= IVAL(centry
->data
, centry
->ofs
);
246 pull a uint16 from a cache entry
248 static uint16
centry_uint16(struct cache_entry
*centry
)
251 if (!centry_check_bytes(centry
, 2)) {
252 smb_panic_fn("centry_uint16");
254 ret
= SVAL(centry
->data
, centry
->ofs
);
260 pull a uint8 from a cache entry
262 static uint8
centry_uint8(struct cache_entry
*centry
)
265 if (!centry_check_bytes(centry
, 1)) {
266 smb_panic_fn("centry_uint8");
268 ret
= CVAL(centry
->data
, centry
->ofs
);
274 pull a NTTIME from a cache entry
276 static NTTIME
centry_nttime(struct cache_entry
*centry
)
279 if (!centry_check_bytes(centry
, 8)) {
280 smb_panic_fn("centry_nttime");
282 ret
= IVAL(centry
->data
, centry
->ofs
);
284 ret
+= (uint64
)IVAL(centry
->data
, centry
->ofs
) << 32;
290 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
292 static time_t centry_time(struct cache_entry
*centry
)
294 return (time_t)centry_nttime(centry
);
297 /* pull a string from a cache entry, using the supplied
300 static char *centry_string(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
305 len
= centry_uint8(centry
);
308 /* a deliberate NULL string */
312 if (!centry_check_bytes(centry
, (size_t)len
)) {
313 smb_panic_fn("centry_string");
316 ret
= talloc_array(mem_ctx
, char, len
+1);
318 smb_panic_fn("centry_string out of memory\n");
320 memcpy(ret
,centry
->data
+ centry
->ofs
, len
);
326 /* pull a hash16 from a cache entry, using the supplied
329 static char *centry_hash16(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
334 len
= centry_uint8(centry
);
337 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
342 if (!centry_check_bytes(centry
, 16)) {
346 ret
= talloc_array(mem_ctx
, char, 16);
348 smb_panic_fn("centry_hash out of memory\n");
350 memcpy(ret
,centry
->data
+ centry
->ofs
, 16);
355 /* pull a sid from a cache entry, using the supplied
358 static bool centry_sid(struct cache_entry
*centry
, struct dom_sid
*sid
)
363 sid_string
= centry_string(centry
, talloc_tos());
364 if (sid_string
== NULL
) {
367 ret
= string_to_sid(sid
, sid_string
);
368 TALLOC_FREE(sid_string
);
374 pull a NTSTATUS from a cache entry
376 static NTSTATUS
centry_ntstatus(struct cache_entry
*centry
)
380 status
= NT_STATUS(centry_uint32(centry
));
385 /* the server is considered down if it can't give us a sequence number */
386 static bool wcache_server_down(struct winbindd_domain
*domain
)
393 ret
= (domain
->sequence_number
== DOM_SEQUENCE_NONE
);
396 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
401 struct wcache_seqnum_state
{
403 uint32_t *last_seq_check
;
406 static int wcache_seqnum_parser(TDB_DATA key
, TDB_DATA data
,
409 struct wcache_seqnum_state
*state
= private_data
;
411 if (data
.dsize
!= 8) {
412 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
417 *state
->seqnum
= IVAL(data
.dptr
, 0);
418 *state
->last_seq_check
= IVAL(data
.dptr
, 4);
422 static bool wcache_fetch_seqnum(const char *domain_name
, uint32_t *seqnum
,
423 uint32_t *last_seq_check
)
425 struct wcache_seqnum_state state
= {
426 .seqnum
= seqnum
, .last_seq_check
= last_seq_check
432 if (wcache
->tdb
== NULL
) {
433 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
437 keystr
= talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name
);
438 if (keystr
== NULL
) {
439 DEBUG(10, ("talloc failed\n"));
442 key
= string_term_tdb_data(keystr
);
444 ret
= tdb_parse_record(wcache
->tdb
, key
, wcache_seqnum_parser
,
451 static NTSTATUS
fetch_cache_seqnum( struct winbindd_domain
*domain
, time_t now
)
453 uint32 last_check
, time_diff
;
455 if (!wcache_fetch_seqnum(domain
->name
, &domain
->sequence_number
,
457 return NT_STATUS_UNSUCCESSFUL
;
459 domain
->last_seq_check
= last_check
;
461 /* have we expired? */
463 time_diff
= now
- domain
->last_seq_check
;
464 if ( time_diff
> lp_winbind_cache_time() ) {
465 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
466 domain
->name
, domain
->sequence_number
,
467 (uint32
)domain
->last_seq_check
));
468 return NT_STATUS_UNSUCCESSFUL
;
471 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
472 domain
->name
, domain
->sequence_number
,
473 (uint32
)domain
->last_seq_check
));
478 bool wcache_store_seqnum(const char *domain_name
, uint32_t seqnum
,
479 time_t last_seq_check
)
485 if (wcache
->tdb
== NULL
) {
486 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
490 key_str
= talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name
);
491 if (key_str
== NULL
) {
492 DEBUG(10, ("talloc_asprintf failed\n"));
496 SIVAL(buf
, 0, seqnum
);
497 SIVAL(buf
, 4, last_seq_check
);
499 ret
= tdb_store_bystring(wcache
->tdb
, key_str
,
500 make_tdb_data(buf
, sizeof(buf
)), TDB_REPLACE
);
501 TALLOC_FREE(key_str
);
503 DEBUG(10, ("tdb_store_bystring failed: %s\n",
504 tdb_errorstr(wcache
->tdb
)));
505 TALLOC_FREE(key_str
);
509 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
510 domain_name
, seqnum
, (unsigned)last_seq_check
));
515 static bool store_cache_seqnum( struct winbindd_domain
*domain
)
517 return wcache_store_seqnum(domain
->name
, domain
->sequence_number
,
518 domain
->last_seq_check
);
522 refresh the domain sequence number. If force is true
523 then always refresh it, no matter how recently we fetched it
526 static void refresh_sequence_number(struct winbindd_domain
*domain
, bool force
)
530 time_t t
= time(NULL
);
531 unsigned cache_time
= lp_winbind_cache_time();
533 if (is_domain_offline(domain
)) {
539 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
540 /* trying to reconnect is expensive, don't do it too often */
541 if (domain
->sequence_number
== DOM_SEQUENCE_NONE
) {
546 time_diff
= t
- domain
->last_seq_check
;
548 /* see if we have to refetch the domain sequence number */
549 if (!force
&& (time_diff
< cache_time
) &&
550 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
551 NT_STATUS_IS_OK(domain
->last_status
)) {
552 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain
->name
));
556 /* try to get the sequence number from the tdb cache first */
557 /* this will update the timestamp as well */
559 status
= fetch_cache_seqnum( domain
, t
);
560 if (NT_STATUS_IS_OK(status
) &&
561 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
562 NT_STATUS_IS_OK(domain
->last_status
)) {
566 /* important! make sure that we know if this is a native
567 mode domain or not. And that we can contact it. */
569 if ( winbindd_can_contact_domain( domain
) ) {
570 status
= domain
->backend
->sequence_number(domain
,
571 &domain
->sequence_number
);
573 /* just use the current time */
574 status
= NT_STATUS_OK
;
575 domain
->sequence_number
= time(NULL
);
579 /* the above call could have set our domain->backend to NULL when
580 * coming from offline to online mode, make sure to reinitialize the
581 * backend - Guenther */
584 if (!NT_STATUS_IS_OK(status
)) {
585 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status
)));
586 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
589 domain
->last_status
= status
;
590 domain
->last_seq_check
= time(NULL
);
592 /* save the new sequence number in the cache */
593 store_cache_seqnum( domain
);
596 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
597 domain
->name
, domain
->sequence_number
));
603 decide if a cache entry has expired
605 static bool centry_expired(struct winbindd_domain
*domain
, const char *keystr
, struct cache_entry
*centry
)
607 /* If we've been told to be offline - stay in that state... */
608 if (lp_winbind_offline_logon() && global_winbindd_offline_state
) {
609 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
610 keystr
, domain
->name
));
614 /* when the domain is offline return the cached entry.
615 * This deals with transient offline states... */
617 if (!domain
->online
) {
618 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
619 keystr
, domain
->name
));
623 /* if the server is OK and our cache entry came from when it was down then
624 the entry is invalid */
625 if ((domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
626 (centry
->sequence_number
== DOM_SEQUENCE_NONE
)) {
627 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
628 keystr
, domain
->name
));
632 /* if the server is down or the cache entry is not older than the
633 current sequence number or it did not timeout then it is OK */
634 if (wcache_server_down(domain
)
635 || ((centry
->sequence_number
== domain
->sequence_number
)
636 && (centry
->timeout
> time(NULL
)))) {
637 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
638 keystr
, domain
->name
));
642 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
643 keystr
, domain
->name
));
649 static struct cache_entry
*wcache_fetch_raw(char *kstr
)
652 struct cache_entry
*centry
;
655 key
= string_tdb_data(kstr
);
656 data
= tdb_fetch(wcache
->tdb
, key
);
662 centry
= SMB_XMALLOC_P(struct cache_entry
);
663 centry
->data
= (unsigned char *)data
.dptr
;
664 centry
->len
= data
.dsize
;
667 if (centry
->len
< 16) {
668 /* huh? corrupt cache? */
669 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s "
670 "(len < 16)?\n", kstr
));
675 centry
->status
= centry_ntstatus(centry
);
676 centry
->sequence_number
= centry_uint32(centry
);
677 centry
->timeout
= centry_uint64_t(centry
);
682 static bool is_my_own_sam_domain(struct winbindd_domain
*domain
)
684 if (strequal(domain
->name
, get_global_sam_name()) &&
685 sid_check_is_our_sam(&domain
->sid
)) {
692 static bool is_builtin_domain(struct winbindd_domain
*domain
)
694 if (strequal(domain
->name
, "BUILTIN") &&
695 sid_check_is_builtin(&domain
->sid
)) {
703 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
704 number and return status
706 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
707 struct winbindd_domain
*domain
,
708 const char *format
, ...) PRINTF_ATTRIBUTE(3,4);
709 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
710 struct winbindd_domain
*domain
,
711 const char *format
, ...)
715 struct cache_entry
*centry
;
717 if (!winbindd_use_cache() ||
718 is_my_own_sam_domain(domain
) ||
719 is_builtin_domain(domain
)) {
723 refresh_sequence_number(domain
, false);
725 va_start(ap
, format
);
726 smb_xvasprintf(&kstr
, format
, ap
);
729 centry
= wcache_fetch_raw(kstr
);
730 if (centry
== NULL
) {
735 if (centry_expired(domain
, kstr
, centry
)) {
737 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
738 kstr
, domain
->name
));
745 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
746 kstr
, domain
->name
));
752 static void wcache_delete(const char *format
, ...) PRINTF_ATTRIBUTE(1,2);
753 static void wcache_delete(const char *format
, ...)
759 va_start(ap
, format
);
760 smb_xvasprintf(&kstr
, format
, ap
);
763 key
= string_tdb_data(kstr
);
765 tdb_delete(wcache
->tdb
, key
);
770 make sure we have at least len bytes available in a centry
772 static void centry_expand(struct cache_entry
*centry
, uint32 len
)
774 if (centry
->len
- centry
->ofs
>= len
)
777 centry
->data
= SMB_REALLOC_ARRAY(centry
->data
, unsigned char,
780 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry
->len
));
781 smb_panic_fn("out of memory in centry_expand");
786 push a uint64_t into a centry
788 static void centry_put_uint64_t(struct cache_entry
*centry
, uint64_t v
)
790 centry_expand(centry
, 8);
791 SBVAL(centry
->data
, centry
->ofs
, v
);
796 push a uint32 into a centry
798 static void centry_put_uint32(struct cache_entry
*centry
, uint32 v
)
800 centry_expand(centry
, 4);
801 SIVAL(centry
->data
, centry
->ofs
, v
);
806 push a uint16 into a centry
808 static void centry_put_uint16(struct cache_entry
*centry
, uint16 v
)
810 centry_expand(centry
, 2);
811 SSVAL(centry
->data
, centry
->ofs
, v
);
816 push a uint8 into a centry
818 static void centry_put_uint8(struct cache_entry
*centry
, uint8 v
)
820 centry_expand(centry
, 1);
821 SCVAL(centry
->data
, centry
->ofs
, v
);
826 push a string into a centry
828 static void centry_put_string(struct cache_entry
*centry
, const char *s
)
833 /* null strings are marked as len 0xFFFF */
834 centry_put_uint8(centry
, 0xFF);
839 /* can't handle more than 254 char strings. Truncating is probably best */
841 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len
));
844 centry_put_uint8(centry
, len
);
845 centry_expand(centry
, len
);
846 memcpy(centry
->data
+ centry
->ofs
, s
, len
);
851 push a 16 byte hash into a centry - treat as 16 byte string.
853 static void centry_put_hash16(struct cache_entry
*centry
, const uint8 val
[16])
855 centry_put_uint8(centry
, 16);
856 centry_expand(centry
, 16);
857 memcpy(centry
->data
+ centry
->ofs
, val
, 16);
861 static void centry_put_sid(struct cache_entry
*centry
, const struct dom_sid
*sid
)
864 centry_put_string(centry
, sid_to_fstring(sid_string
, sid
));
869 put NTSTATUS into a centry
871 static void centry_put_ntstatus(struct cache_entry
*centry
, NTSTATUS status
)
873 uint32 status_value
= NT_STATUS_V(status
);
874 centry_put_uint32(centry
, status_value
);
879 push a NTTIME into a centry
881 static void centry_put_nttime(struct cache_entry
*centry
, NTTIME nt
)
883 centry_expand(centry
, 8);
884 SIVAL(centry
->data
, centry
->ofs
, nt
& 0xFFFFFFFF);
886 SIVAL(centry
->data
, centry
->ofs
, nt
>> 32);
891 push a time_t into a centry - use a 64 bit size.
892 NTTIME here is being used as a convenient 64-bit size.
894 static void centry_put_time(struct cache_entry
*centry
, time_t t
)
896 NTTIME nt
= (NTTIME
)t
;
897 centry_put_nttime(centry
, nt
);
901 start a centry for output. When finished, call centry_end()
903 static struct cache_entry
*centry_start(struct winbindd_domain
*domain
,
906 struct cache_entry
*centry
;
911 centry
= SMB_XMALLOC_P(struct cache_entry
);
913 centry
->len
= 8192; /* reasonable default */
914 centry
->data
= SMB_XMALLOC_ARRAY(uint8
, centry
->len
);
916 centry
->sequence_number
= domain
->sequence_number
;
917 centry
->timeout
= lp_winbind_cache_time() + time(NULL
);
918 centry_put_ntstatus(centry
, status
);
919 centry_put_uint32(centry
, centry
->sequence_number
);
920 centry_put_uint64_t(centry
, centry
->timeout
);
925 finish a centry and write it to the tdb
927 static void centry_end(struct cache_entry
*centry
, const char *format
, ...) PRINTF_ATTRIBUTE(2,3);
928 static void centry_end(struct cache_entry
*centry
, const char *format
, ...)
934 if (!winbindd_use_cache()) {
938 va_start(ap
, format
);
939 smb_xvasprintf(&kstr
, format
, ap
);
942 key
= string_tdb_data(kstr
);
943 data
.dptr
= centry
->data
;
944 data
.dsize
= centry
->ofs
;
946 tdb_store(wcache
->tdb
, key
, data
, TDB_REPLACE
);
950 static void wcache_save_name_to_sid(struct winbindd_domain
*domain
,
951 NTSTATUS status
, const char *domain_name
,
952 const char *name
, const struct dom_sid
*sid
,
953 enum lsa_SidType type
)
955 struct cache_entry
*centry
;
958 centry
= centry_start(domain
, status
);
962 if ((domain_name
== NULL
) || (domain_name
[0] == '\0')) {
963 struct winbindd_domain
*mydomain
=
964 find_domain_from_sid_noinit(sid
);
965 if (mydomain
!= NULL
) {
966 domain_name
= mydomain
->name
;
970 centry_put_uint32(centry
, type
);
971 centry_put_sid(centry
, sid
);
972 fstrcpy(uname
, name
);
973 (void)strupper_m(uname
);
974 centry_end(centry
, "NS/%s/%s", domain_name
, uname
);
975 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name
,
976 uname
, sid_string_dbg(sid
), nt_errstr(status
)));
980 static void wcache_save_sid_to_name(struct winbindd_domain
*domain
, NTSTATUS status
,
981 const struct dom_sid
*sid
, const char *domain_name
, const char *name
, enum lsa_SidType type
)
983 struct cache_entry
*centry
;
986 centry
= centry_start(domain
, status
);
990 if ((domain_name
== NULL
) || (domain_name
[0] == '\0')) {
991 struct winbindd_domain
*mydomain
=
992 find_domain_from_sid_noinit(sid
);
993 if (mydomain
!= NULL
) {
994 domain_name
= mydomain
->name
;
998 if (NT_STATUS_IS_OK(status
)) {
999 centry_put_uint32(centry
, type
);
1000 centry_put_string(centry
, domain_name
);
1001 centry_put_string(centry
, name
);
1004 centry_end(centry
, "SN/%s", sid_to_fstring(sid_string
, sid
));
1005 DEBUG(10,("wcache_save_sid_to_name: %s -> %s\\%s (%s)\n", sid_string
,
1006 domain_name
, name
, nt_errstr(status
)));
1007 centry_free(centry
);
1011 static void wcache_save_user(struct winbindd_domain
*domain
, NTSTATUS status
,
1012 struct wbint_userinfo
*info
)
1014 struct cache_entry
*centry
;
1017 if (is_null_sid(&info
->user_sid
)) {
1021 centry
= centry_start(domain
, status
);
1024 centry_put_string(centry
, info
->acct_name
);
1025 centry_put_string(centry
, info
->full_name
);
1026 centry_put_string(centry
, info
->homedir
);
1027 centry_put_string(centry
, info
->shell
);
1028 centry_put_uint32(centry
, info
->primary_gid
);
1029 centry_put_sid(centry
, &info
->user_sid
);
1030 centry_put_sid(centry
, &info
->group_sid
);
1031 centry_end(centry
, "U/%s", sid_to_fstring(sid_string
,
1033 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string
, info
->acct_name
));
1034 centry_free(centry
);
1037 static void wcache_save_lockout_policy(struct winbindd_domain
*domain
,
1039 struct samr_DomInfo12
*lockout_policy
)
1041 struct cache_entry
*centry
;
1043 centry
= centry_start(domain
, status
);
1047 centry_put_nttime(centry
, lockout_policy
->lockout_duration
);
1048 centry_put_nttime(centry
, lockout_policy
->lockout_window
);
1049 centry_put_uint16(centry
, lockout_policy
->lockout_threshold
);
1051 centry_end(centry
, "LOC_POL/%s", domain
->name
);
1053 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain
->name
));
1055 centry_free(centry
);
1060 static void wcache_save_password_policy(struct winbindd_domain
*domain
,
1062 struct samr_DomInfo1
*policy
)
1064 struct cache_entry
*centry
;
1066 centry
= centry_start(domain
, status
);
1070 centry_put_uint16(centry
, policy
->min_password_length
);
1071 centry_put_uint16(centry
, policy
->password_history_length
);
1072 centry_put_uint32(centry
, policy
->password_properties
);
1073 centry_put_nttime(centry
, policy
->max_password_age
);
1074 centry_put_nttime(centry
, policy
->min_password_age
);
1076 centry_end(centry
, "PWD_POL/%s", domain
->name
);
1078 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
1080 centry_free(centry
);
1083 /***************************************************************************
1084 ***************************************************************************/
1086 static void wcache_save_username_alias(struct winbindd_domain
*domain
,
1088 const char *name
, const char *alias
)
1090 struct cache_entry
*centry
;
1093 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1096 centry_put_string( centry
, alias
);
1098 fstrcpy(uname
, name
);
1099 (void)strupper_m(uname
);
1100 centry_end(centry
, "NSS/NA/%s", uname
);
1102 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name
, alias
));
1104 centry_free(centry
);
1107 static void wcache_save_alias_username(struct winbindd_domain
*domain
,
1109 const char *alias
, const char *name
)
1111 struct cache_entry
*centry
;
1114 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1117 centry_put_string( centry
, name
);
1119 fstrcpy(uname
, alias
);
1120 (void)strupper_m(uname
);
1121 centry_end(centry
, "NSS/AN/%s", uname
);
1123 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias
, name
));
1125 centry_free(centry
);
1128 /***************************************************************************
1129 ***************************************************************************/
1131 NTSTATUS
resolve_username_to_alias( TALLOC_CTX
*mem_ctx
,
1132 struct winbindd_domain
*domain
,
1133 const char *name
, char **alias
)
1135 struct winbind_cache
*cache
= get_cache(domain
);
1136 struct cache_entry
*centry
= NULL
;
1140 if ( domain
->internal
)
1141 return NT_STATUS_NOT_SUPPORTED
;
1146 upper_name
= talloc_strdup(mem_ctx
, name
);
1147 if (upper_name
== NULL
) {
1148 return NT_STATUS_NO_MEMORY
;
1150 if (!strupper_m(upper_name
)) {
1151 talloc_free(upper_name
);
1152 return NT_STATUS_INVALID_PARAMETER
;
1155 centry
= wcache_fetch(cache
, domain
, "NSS/NA/%s", upper_name
);
1157 talloc_free(upper_name
);
1162 status
= centry
->status
;
1164 if (!NT_STATUS_IS_OK(status
)) {
1165 centry_free(centry
);
1169 *alias
= centry_string( centry
, mem_ctx
);
1171 centry_free(centry
);
1173 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1174 name
, *alias
? *alias
: "(none)"));
1176 return (*alias
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1180 /* If its not in cache and we are offline, then fail */
1182 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1183 DEBUG(8,("resolve_username_to_alias: rejecting query "
1184 "in offline mode\n"));
1185 return NT_STATUS_NOT_FOUND
;
1188 status
= nss_map_to_alias( mem_ctx
, domain
->name
, name
, alias
);
1190 if ( NT_STATUS_IS_OK( status
) ) {
1191 wcache_save_username_alias(domain
, status
, name
, *alias
);
1194 if ( NT_STATUS_EQUAL( status
, NT_STATUS_NONE_MAPPED
) ) {
1195 wcache_save_username_alias(domain
, status
, name
, "(NULL)");
1198 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1199 nt_errstr(status
)));
1201 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1202 set_domain_offline( domain
);
1208 /***************************************************************************
1209 ***************************************************************************/
1211 NTSTATUS
resolve_alias_to_username( TALLOC_CTX
*mem_ctx
,
1212 struct winbindd_domain
*domain
,
1213 const char *alias
, char **name
)
1215 struct winbind_cache
*cache
= get_cache(domain
);
1216 struct cache_entry
*centry
= NULL
;
1220 if ( domain
->internal
)
1221 return NT_STATUS_NOT_SUPPORTED
;
1226 upper_name
= talloc_strdup(mem_ctx
, alias
);
1227 if (upper_name
== NULL
) {
1228 return NT_STATUS_NO_MEMORY
;
1230 if (!strupper_m(upper_name
)) {
1231 talloc_free(upper_name
);
1232 return NT_STATUS_INVALID_PARAMETER
;
1235 centry
= wcache_fetch(cache
, domain
, "NSS/AN/%s", upper_name
);
1237 talloc_free(upper_name
);
1242 status
= centry
->status
;
1244 if (!NT_STATUS_IS_OK(status
)) {
1245 centry_free(centry
);
1249 *name
= centry_string( centry
, mem_ctx
);
1251 centry_free(centry
);
1253 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1254 alias
, *name
? *name
: "(none)"));
1256 return (*name
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1260 /* If its not in cache and we are offline, then fail */
1262 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1263 DEBUG(8,("resolve_alias_to_username: rejecting query "
1264 "in offline mode\n"));
1265 return NT_STATUS_NOT_FOUND
;
1268 /* an alias cannot contain a domain prefix or '@' */
1270 if (strchr(alias
, '\\') || strchr(alias
, '@')) {
1271 DEBUG(10,("resolve_alias_to_username: skipping fully "
1272 "qualified name %s\n", alias
));
1273 return NT_STATUS_OBJECT_NAME_INVALID
;
1276 status
= nss_map_from_alias( mem_ctx
, domain
->name
, alias
, name
);
1278 if ( NT_STATUS_IS_OK( status
) ) {
1279 wcache_save_alias_username( domain
, status
, alias
, *name
);
1282 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1283 wcache_save_alias_username(domain
, status
, alias
, "(NULL)");
1286 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1287 nt_errstr(status
)));
1289 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1290 set_domain_offline( domain
);
1296 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
1298 struct winbind_cache
*cache
= get_cache(domain
);
1300 fstring key_str
, tmp
;
1304 return NT_STATUS_INTERNAL_DB_ERROR
;
1307 if (is_null_sid(sid
)) {
1308 return NT_STATUS_INVALID_SID
;
1311 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1312 return NT_STATUS_INVALID_SID
;
1315 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
1317 data
= tdb_fetch(cache
->tdb
, string_tdb_data(key_str
));
1319 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1322 SAFE_FREE(data
.dptr
);
1323 return NT_STATUS_OK
;
1326 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1327 as new salted ones. */
1329 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
1330 TALLOC_CTX
*mem_ctx
,
1331 const struct dom_sid
*sid
,
1332 const uint8
**cached_nt_pass
,
1333 const uint8
**cached_salt
)
1335 struct winbind_cache
*cache
= get_cache(domain
);
1336 struct cache_entry
*centry
= NULL
;
1342 return NT_STATUS_INTERNAL_DB_ERROR
;
1345 if (is_null_sid(sid
)) {
1346 return NT_STATUS_INVALID_SID
;
1349 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1350 return NT_STATUS_INVALID_SID
;
1353 /* Try and get a salted cred first. If we can't
1354 fall back to an unsalted cred. */
1356 centry
= wcache_fetch(cache
, domain
, "CRED/%s",
1357 sid_to_fstring(tmp
, sid
));
1359 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1360 sid_string_dbg(sid
)));
1361 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1365 * We don't use the time element at this moment,
1366 * but we have to consume it, so that we don't
1367 * neet to change the disk format of the cache.
1369 (void)centry_time(centry
);
1371 /* In the salted case this isn't actually the nt_hash itself,
1372 but the MD5 of the salt + nt_hash. Let the caller
1373 sort this out. It can tell as we only return the cached_salt
1374 if we are returning a salted cred. */
1376 *cached_nt_pass
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1377 if (*cached_nt_pass
== NULL
) {
1380 sid_to_fstring(sidstr
, sid
);
1382 /* Bad (old) cred cache. Delete and pretend we
1384 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1386 wcache_delete("CRED/%s", sidstr
);
1387 centry_free(centry
);
1388 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1391 /* We only have 17 bytes more data in the salted cred case. */
1392 if (centry
->len
- centry
->ofs
== 17) {
1393 *cached_salt
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1395 *cached_salt
= NULL
;
1398 dump_data_pw("cached_nt_pass", *cached_nt_pass
, NT_HASH_LEN
);
1400 dump_data_pw("cached_salt", *cached_salt
, NT_HASH_LEN
);
1403 status
= centry
->status
;
1405 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1406 sid_string_dbg(sid
), nt_errstr(status
) ));
1408 centry_free(centry
);
1412 /* Store creds for a SID - only writes out new salted ones. */
1414 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1415 const struct dom_sid
*sid
,
1416 const uint8 nt_pass
[NT_HASH_LEN
])
1418 struct cache_entry
*centry
;
1421 uint8 cred_salt
[NT_HASH_LEN
];
1422 uint8 salted_hash
[NT_HASH_LEN
];
1424 if (is_null_sid(sid
)) {
1425 return NT_STATUS_INVALID_SID
;
1428 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1429 return NT_STATUS_INVALID_SID
;
1432 centry
= centry_start(domain
, NT_STATUS_OK
);
1434 return NT_STATUS_INTERNAL_DB_ERROR
;
1437 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1439 centry_put_time(centry
, time(NULL
));
1441 /* Create a salt and then salt the hash. */
1442 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1443 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1445 centry_put_hash16(centry
, salted_hash
);
1446 centry_put_hash16(centry
, cred_salt
);
1447 centry_end(centry
, "CRED/%s", sid_to_fstring(sid_string
, sid
));
1449 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1451 centry_free(centry
);
1453 return NT_STATUS_OK
;
1457 /* Query display info. This is the basic user list fn */
1458 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
1459 TALLOC_CTX
*mem_ctx
,
1460 uint32
*num_entries
,
1461 struct wbint_userinfo
**info
)
1463 struct winbind_cache
*cache
= get_cache(domain
);
1464 struct cache_entry
*centry
= NULL
;
1466 unsigned int i
, retry
;
1467 bool old_status
= domain
->online
;
1472 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1477 *num_entries
= centry_uint32(centry
);
1479 if (*num_entries
== 0)
1482 (*info
) = talloc_array(mem_ctx
, struct wbint_userinfo
, *num_entries
);
1484 smb_panic_fn("query_user_list out of memory");
1486 for (i
=0; i
<(*num_entries
); i
++) {
1487 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
1488 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
1489 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
1490 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
1491 centry_sid(centry
, &(*info
)[i
].user_sid
);
1492 centry_sid(centry
, &(*info
)[i
].group_sid
);
1496 status
= centry
->status
;
1498 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1499 domain
->name
, nt_errstr(status
) ));
1501 centry_free(centry
);
1508 /* Return status value returned by seq number check */
1510 if (!NT_STATUS_IS_OK(domain
->last_status
))
1511 return domain
->last_status
;
1513 /* Put the query_user_list() in a retry loop. There appears to be
1514 * some bug either with Windows 2000 or Samba's handling of large
1515 * rpc replies. This manifests itself as sudden disconnection
1516 * at a random point in the enumeration of a large (60k) user list.
1517 * The retry loop simply tries the operation again. )-: It's not
1518 * pretty but an acceptable workaround until we work out what the
1519 * real problem is. */
1524 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1527 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
1528 if (!NT_STATUS_IS_OK(status
)) {
1529 DEBUG(3, ("query_user_list: returned 0x%08x, "
1530 "retrying\n", NT_STATUS_V(status
)));
1532 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1533 DEBUG(3, ("query_user_list: flushing "
1534 "connection cache\n"));
1535 invalidate_cm_connection(domain
);
1537 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1538 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1539 if (!domain
->internal
&& old_status
) {
1540 set_domain_offline(domain
);
1542 /* store partial response. */
1543 if (*num_entries
> 0) {
1545 * humm, what about the status used for cache?
1546 * Should it be NT_STATUS_OK?
1551 * domain is offline now, and there is no user entries,
1552 * try to fetch from cache again.
1554 if (cache
->tdb
&& !domain
->online
&& !domain
->internal
&& old_status
) {
1555 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1556 /* partial response... */
1560 goto do_fetch_cache
;
1567 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1571 refresh_sequence_number(domain
, false);
1572 if (!NT_STATUS_IS_OK(status
)) {
1575 centry
= centry_start(domain
, status
);
1578 centry_put_uint32(centry
, *num_entries
);
1579 for (i
=0; i
<(*num_entries
); i
++) {
1580 centry_put_string(centry
, (*info
)[i
].acct_name
);
1581 centry_put_string(centry
, (*info
)[i
].full_name
);
1582 centry_put_string(centry
, (*info
)[i
].homedir
);
1583 centry_put_string(centry
, (*info
)[i
].shell
);
1584 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1585 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1586 if (domain
->backend
&& domain
->backend
->consistent
) {
1587 /* when the backend is consistent we can pre-prime some mappings */
1588 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1590 (*info
)[i
].acct_name
,
1591 &(*info
)[i
].user_sid
,
1593 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1594 &(*info
)[i
].user_sid
,
1596 (*info
)[i
].acct_name
,
1598 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1601 centry_end(centry
, "UL/%s", domain
->name
);
1602 centry_free(centry
);
1608 /* list all domain groups */
1609 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
1610 TALLOC_CTX
*mem_ctx
,
1611 uint32
*num_entries
,
1612 struct wb_acct_info
**info
)
1614 struct winbind_cache
*cache
= get_cache(domain
);
1615 struct cache_entry
*centry
= NULL
;
1620 old_status
= domain
->online
;
1624 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1629 *num_entries
= centry_uint32(centry
);
1631 if (*num_entries
== 0)
1634 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1636 smb_panic_fn("enum_dom_groups out of memory");
1638 for (i
=0; i
<(*num_entries
); i
++) {
1639 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1640 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1641 (*info
)[i
].rid
= centry_uint32(centry
);
1645 status
= centry
->status
;
1647 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1648 domain
->name
, nt_errstr(status
) ));
1650 centry_free(centry
);
1657 /* Return status value returned by seq number check */
1659 if (!NT_STATUS_IS_OK(domain
->last_status
))
1660 return domain
->last_status
;
1662 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1665 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1667 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1668 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1669 if (!domain
->internal
&& old_status
) {
1670 set_domain_offline(domain
);
1674 !domain
->internal
&&
1676 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1678 goto do_fetch_cache
;
1683 refresh_sequence_number(domain
, false);
1684 if (!NT_STATUS_IS_OK(status
)) {
1687 centry
= centry_start(domain
, status
);
1690 centry_put_uint32(centry
, *num_entries
);
1691 for (i
=0; i
<(*num_entries
); i
++) {
1692 centry_put_string(centry
, (*info
)[i
].acct_name
);
1693 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1694 centry_put_uint32(centry
, (*info
)[i
].rid
);
1696 centry_end(centry
, "GL/%s/domain", domain
->name
);
1697 centry_free(centry
);
1703 /* list all domain groups */
1704 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
1705 TALLOC_CTX
*mem_ctx
,
1706 uint32
*num_entries
,
1707 struct wb_acct_info
**info
)
1709 struct winbind_cache
*cache
= get_cache(domain
);
1710 struct cache_entry
*centry
= NULL
;
1715 old_status
= domain
->online
;
1719 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1724 *num_entries
= centry_uint32(centry
);
1726 if (*num_entries
== 0)
1729 (*info
) = talloc_array(mem_ctx
, struct wb_acct_info
, *num_entries
);
1731 smb_panic_fn("enum_dom_groups out of memory");
1733 for (i
=0; i
<(*num_entries
); i
++) {
1734 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1735 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1736 (*info
)[i
].rid
= centry_uint32(centry
);
1741 /* If we are returning cached data and the domain controller
1742 is down then we don't know whether the data is up to date
1743 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1746 if (wcache_server_down(domain
)) {
1747 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1748 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1750 status
= centry
->status
;
1752 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1753 domain
->name
, nt_errstr(status
) ));
1755 centry_free(centry
);
1762 /* Return status value returned by seq number check */
1764 if (!NT_STATUS_IS_OK(domain
->last_status
))
1765 return domain
->last_status
;
1767 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1770 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1772 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1773 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1774 if (!domain
->internal
&& old_status
) {
1775 set_domain_offline(domain
);
1778 !domain
->internal
&&
1781 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1783 goto do_fetch_cache
;
1788 refresh_sequence_number(domain
, false);
1789 if (!NT_STATUS_IS_OK(status
)) {
1792 centry
= centry_start(domain
, status
);
1795 centry_put_uint32(centry
, *num_entries
);
1796 for (i
=0; i
<(*num_entries
); i
++) {
1797 centry_put_string(centry
, (*info
)[i
].acct_name
);
1798 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1799 centry_put_uint32(centry
, (*info
)[i
].rid
);
1801 centry_end(centry
, "GL/%s/local", domain
->name
);
1802 centry_free(centry
);
1808 NTSTATUS
wcache_name_to_sid(struct winbindd_domain
*domain
,
1809 const char *domain_name
,
1811 struct dom_sid
*sid
,
1812 enum lsa_SidType
*type
)
1814 struct winbind_cache
*cache
= get_cache(domain
);
1815 struct cache_entry
*centry
;
1819 if (cache
->tdb
== NULL
) {
1820 return NT_STATUS_NOT_FOUND
;
1823 uname
= talloc_strdup_upper(talloc_tos(), name
);
1824 if (uname
== NULL
) {
1825 return NT_STATUS_NO_MEMORY
;
1828 if ((domain_name
== NULL
) || (domain_name
[0] == '\0')) {
1829 domain_name
= domain
->name
;
1832 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1834 if (centry
== NULL
) {
1835 return NT_STATUS_NOT_FOUND
;
1838 status
= centry
->status
;
1839 if (NT_STATUS_IS_OK(status
)) {
1840 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1841 centry_sid(centry
, sid
);
1844 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1845 "%s\n", domain
->name
, nt_errstr(status
) ));
1847 centry_free(centry
);
1851 /* convert a single name to a sid in a domain */
1852 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
1853 TALLOC_CTX
*mem_ctx
,
1854 const char *domain_name
,
1857 struct dom_sid
*sid
,
1858 enum lsa_SidType
*type
)
1863 old_status
= domain
->online
;
1865 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1866 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1872 /* If the seq number check indicated that there is a problem
1873 * with this DC, then return that status... except for
1874 * access_denied. This is special because the dc may be in
1875 * "restrict anonymous = 1" mode, in which case it will deny
1876 * most unauthenticated operations, but *will* allow the LSA
1877 * name-to-sid that we try as a fallback. */
1879 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1880 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1881 return domain
->last_status
;
1883 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1886 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
,
1887 name
, flags
, sid
, type
);
1889 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1890 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1891 if (!domain
->internal
&& old_status
) {
1892 set_domain_offline(domain
);
1894 if (!domain
->internal
&&
1897 NTSTATUS cache_status
;
1898 cache_status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1899 return cache_status
;
1903 refresh_sequence_number(domain
, false);
1905 if (domain
->online
&&
1906 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1907 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1909 /* Only save the reverse mapping if this was not a UPN */
1910 if (!strchr(name
, '@')) {
1911 if (!strupper_m(discard_const_p(char, domain_name
))) {
1912 return NT_STATUS_INVALID_PARAMETER
;
1914 (void)strlower_m(discard_const_p(char, name
));
1915 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1922 static NTSTATUS
wcache_sid_to_name(struct winbindd_domain
*domain
,
1923 const struct dom_sid
*sid
,
1924 TALLOC_CTX
*mem_ctx
,
1927 enum lsa_SidType
*type
)
1929 struct winbind_cache
*cache
= get_cache(domain
);
1930 struct cache_entry
*centry
;
1934 if (cache
->tdb
== NULL
) {
1935 return NT_STATUS_NOT_FOUND
;
1938 sid_string
= sid_string_tos(sid
);
1939 if (sid_string
== NULL
) {
1940 return NT_STATUS_NO_MEMORY
;
1943 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_string
);
1944 TALLOC_FREE(sid_string
);
1945 if (centry
== NULL
) {
1946 return NT_STATUS_NOT_FOUND
;
1949 if (NT_STATUS_IS_OK(centry
->status
)) {
1950 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1951 *domain_name
= centry_string(centry
, mem_ctx
);
1952 *name
= centry_string(centry
, mem_ctx
);
1955 status
= centry
->status
;
1956 centry_free(centry
);
1958 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1959 "%s\n", domain
->name
, nt_errstr(status
) ));
1964 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1966 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1967 TALLOC_CTX
*mem_ctx
,
1968 const struct dom_sid
*sid
,
1971 enum lsa_SidType
*type
)
1976 old_status
= domain
->online
;
1977 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
1979 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1984 *domain_name
= NULL
;
1986 /* If the seq number check indicated that there is a problem
1987 * with this DC, then return that status... except for
1988 * access_denied. This is special because the dc may be in
1989 * "restrict anonymous = 1" mode, in which case it will deny
1990 * most unauthenticated operations, but *will* allow the LSA
1991 * sid-to-name that we try as a fallback. */
1993 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1994 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1995 return domain
->last_status
;
1997 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
2000 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
2002 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2003 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2004 if (!domain
->internal
&& old_status
) {
2005 set_domain_offline(domain
);
2007 if (!domain
->internal
&&
2010 NTSTATUS cache_status
;
2011 cache_status
= wcache_sid_to_name(domain
, sid
, mem_ctx
,
2012 domain_name
, name
, type
);
2013 return cache_status
;
2017 refresh_sequence_number(domain
, false);
2018 if (!NT_STATUS_IS_OK(status
)) {
2021 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
2023 /* We can't save the name to sid mapping here, as with sid history a
2024 * later name2sid would give the wrong sid. */
2029 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
2030 TALLOC_CTX
*mem_ctx
,
2031 const struct dom_sid
*domain_sid
,
2036 enum lsa_SidType
**types
)
2038 struct winbind_cache
*cache
= get_cache(domain
);
2040 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
2045 old_status
= domain
->online
;
2046 *domain_name
= NULL
;
2054 if (num_rids
== 0) {
2055 return NT_STATUS_OK
;
2058 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2059 *types
= talloc_array(mem_ctx
, enum lsa_SidType
, num_rids
);
2061 if ((*names
== NULL
) || (*types
== NULL
)) {
2062 result
= NT_STATUS_NO_MEMORY
;
2066 have_mapped
= have_unmapped
= false;
2068 for (i
=0; i
<num_rids
; i
++) {
2070 struct cache_entry
*centry
;
2073 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2074 result
= NT_STATUS_INTERNAL_ERROR
;
2078 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2079 sid_to_fstring(tmp
, &sid
));
2084 (*types
)[i
] = SID_NAME_UNKNOWN
;
2085 (*names
)[i
] = talloc_strdup(*names
, "");
2087 if (NT_STATUS_IS_OK(centry
->status
)) {
2090 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2092 dom
= centry_string(centry
, mem_ctx
);
2093 if (*domain_name
== NULL
) {
2099 (*names
)[i
] = centry_string(centry
, *names
);
2101 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)
2102 || NT_STATUS_EQUAL(centry
->status
, STATUS_SOME_UNMAPPED
)) {
2103 have_unmapped
= true;
2106 /* something's definitely wrong */
2107 result
= centry
->status
;
2108 centry_free(centry
);
2112 centry_free(centry
);
2116 return NT_STATUS_NONE_MAPPED
;
2118 if (!have_unmapped
) {
2119 return NT_STATUS_OK
;
2121 return STATUS_SOME_UNMAPPED
;
2125 TALLOC_FREE(*names
);
2126 TALLOC_FREE(*types
);
2128 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
2129 rids
, num_rids
, domain_name
,
2132 if (NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
2133 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2134 if (!domain
->internal
&& old_status
) {
2135 set_domain_offline(domain
);
2138 !domain
->internal
&&
2141 have_mapped
= have_unmapped
= false;
2143 *names
= talloc_array(mem_ctx
, char *, num_rids
);
2144 if (*names
== NULL
) {
2145 result
= NT_STATUS_NO_MEMORY
;
2149 *types
= talloc_array(mem_ctx
, enum lsa_SidType
,
2151 if (*types
== NULL
) {
2152 result
= NT_STATUS_NO_MEMORY
;
2156 for (i
=0; i
<num_rids
; i
++) {
2158 struct cache_entry
*centry
;
2161 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2162 result
= NT_STATUS_INTERNAL_ERROR
;
2166 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2167 sid_to_fstring(tmp
, &sid
));
2169 (*types
)[i
] = SID_NAME_UNKNOWN
;
2170 (*names
)[i
] = talloc_strdup(*names
, "");
2174 (*types
)[i
] = SID_NAME_UNKNOWN
;
2175 (*names
)[i
] = talloc_strdup(*names
, "");
2177 if (NT_STATUS_IS_OK(centry
->status
)) {
2180 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2182 dom
= centry_string(centry
, mem_ctx
);
2183 if (*domain_name
== NULL
) {
2189 (*names
)[i
] = centry_string(centry
, *names
);
2191 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)) {
2192 have_unmapped
= true;
2195 /* something's definitely wrong */
2196 result
= centry
->status
;
2197 centry_free(centry
);
2201 centry_free(centry
);
2205 return NT_STATUS_NONE_MAPPED
;
2207 if (!have_unmapped
) {
2208 return NT_STATUS_OK
;
2210 return STATUS_SOME_UNMAPPED
;
2214 None of the queried rids has been found so save all negative entries
2216 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
2217 for (i
= 0; i
< num_rids
; i
++) {
2219 const char *name
= "";
2220 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
2221 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
2223 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2224 return NT_STATUS_INTERNAL_ERROR
;
2227 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2235 Some or all of the queried rids have been found.
2237 if (!NT_STATUS_IS_OK(result
) &&
2238 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
2242 refresh_sequence_number(domain
, false);
2244 for (i
=0; i
<num_rids
; i
++) {
2248 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2249 result
= NT_STATUS_INTERNAL_ERROR
;
2253 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
2254 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
2256 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2257 (*names
)[i
], (*types
)[i
]);
2263 TALLOC_FREE(*names
);
2264 TALLOC_FREE(*types
);
2268 NTSTATUS
wcache_query_user(struct winbindd_domain
*domain
,
2269 TALLOC_CTX
*mem_ctx
,
2270 const struct dom_sid
*user_sid
,
2271 struct wbint_userinfo
*info
)
2273 struct winbind_cache
*cache
= get_cache(domain
);
2274 struct cache_entry
*centry
= NULL
;
2278 if (cache
->tdb
== NULL
) {
2279 return NT_STATUS_NOT_FOUND
;
2282 sid_string
= sid_string_tos(user_sid
);
2283 if (sid_string
== NULL
) {
2284 return NT_STATUS_NO_MEMORY
;
2287 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string
);
2288 TALLOC_FREE(sid_string
);
2289 if (centry
== NULL
) {
2290 return NT_STATUS_NOT_FOUND
;
2294 * If we have an access denied cache entry and a cached info3
2295 * in the samlogon cache then do a query. This will force the
2296 * rpc back end to return the info3 data.
2299 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
) &&
2300 netsamlogon_cache_have(user_sid
)) {
2301 DEBUG(10, ("query_user: cached access denied and have cached "
2303 domain
->last_status
= NT_STATUS_OK
;
2304 centry_free(centry
);
2305 return NT_STATUS_NOT_FOUND
;
2308 /* if status is not ok then this is a negative hit
2309 and the rest of the data doesn't matter */
2310 status
= centry
->status
;
2311 if (NT_STATUS_IS_OK(status
)) {
2312 info
->acct_name
= centry_string(centry
, mem_ctx
);
2313 info
->full_name
= centry_string(centry
, mem_ctx
);
2314 info
->homedir
= centry_string(centry
, mem_ctx
);
2315 info
->shell
= centry_string(centry
, mem_ctx
);
2316 info
->primary_gid
= centry_uint32(centry
);
2317 centry_sid(centry
, &info
->user_sid
);
2318 centry_sid(centry
, &info
->group_sid
);
2321 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2322 "%s\n", domain
->name
, nt_errstr(status
) ));
2324 centry_free(centry
);
2330 * @brief Query a fullname from the username cache (for further gecos processing)
2332 * @param domain A pointer to the winbindd_domain struct.
2333 * @param mem_ctx The talloc context.
2334 * @param user_sid The user sid.
2335 * @param full_name A pointer to the full_name string.
2337 * @return NTSTATUS code
2339 NTSTATUS
wcache_query_user_fullname(struct winbindd_domain
*domain
,
2340 TALLOC_CTX
*mem_ctx
,
2341 const struct dom_sid
*user_sid
,
2342 const char **full_name
)
2345 struct wbint_userinfo info
;
2347 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, &info
);
2348 if (!NT_STATUS_IS_OK(status
)) {
2352 if (info
.full_name
!= NULL
) {
2353 *full_name
= talloc_strdup(mem_ctx
, info
.full_name
);
2354 if (*full_name
== NULL
) {
2355 return NT_STATUS_NO_MEMORY
;
2359 return NT_STATUS_OK
;
2362 /* Lookup user information from a rid */
2363 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
2364 TALLOC_CTX
*mem_ctx
,
2365 const struct dom_sid
*user_sid
,
2366 struct wbint_userinfo
*info
)
2371 old_status
= domain
->online
;
2372 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2373 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2379 /* Return status value returned by seq number check */
2381 if (!NT_STATUS_IS_OK(domain
->last_status
))
2382 return domain
->last_status
;
2384 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2387 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
2389 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2390 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2391 if (!domain
->internal
&& old_status
) {
2392 set_domain_offline(domain
);
2394 if (!domain
->internal
&&
2397 NTSTATUS cache_status
;
2398 cache_status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2399 return cache_status
;
2403 refresh_sequence_number(domain
, false);
2404 if (!NT_STATUS_IS_OK(status
)) {
2407 wcache_save_user(domain
, status
, info
);
2412 NTSTATUS
wcache_lookup_usergroups(struct winbindd_domain
*domain
,
2413 TALLOC_CTX
*mem_ctx
,
2414 const struct dom_sid
*user_sid
,
2415 uint32_t *pnum_sids
,
2416 struct dom_sid
**psids
)
2418 struct winbind_cache
*cache
= get_cache(domain
);
2419 struct cache_entry
*centry
= NULL
;
2421 uint32_t i
, num_sids
;
2422 struct dom_sid
*sids
;
2425 if (cache
->tdb
== NULL
) {
2426 return NT_STATUS_NOT_FOUND
;
2429 centry
= wcache_fetch(cache
, domain
, "UG/%s",
2430 sid_to_fstring(sid_string
, user_sid
));
2431 if (centry
== NULL
) {
2432 return NT_STATUS_NOT_FOUND
;
2435 /* If we have an access denied cache entry and a cached info3 in the
2436 samlogon cache then do a query. This will force the rpc back end
2437 to return the info3 data. */
2439 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)
2440 && netsamlogon_cache_have(user_sid
)) {
2441 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2443 domain
->last_status
= NT_STATUS_OK
;
2444 centry_free(centry
);
2445 return NT_STATUS_NOT_FOUND
;
2448 num_sids
= centry_uint32(centry
);
2449 sids
= talloc_array(mem_ctx
, struct dom_sid
, num_sids
);
2451 centry_free(centry
);
2452 return NT_STATUS_NO_MEMORY
;
2455 for (i
=0; i
<num_sids
; i
++) {
2456 centry_sid(centry
, &sids
[i
]);
2459 status
= centry
->status
;
2461 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2462 "status: %s\n", domain
->name
, nt_errstr(status
)));
2464 centry_free(centry
);
2466 *pnum_sids
= num_sids
;
2471 /* Lookup groups a user is a member of. */
2472 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
2473 TALLOC_CTX
*mem_ctx
,
2474 const struct dom_sid
*user_sid
,
2475 uint32
*num_groups
, struct dom_sid
**user_gids
)
2477 struct cache_entry
*centry
= NULL
;
2483 old_status
= domain
->online
;
2484 status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2485 num_groups
, user_gids
);
2486 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2491 (*user_gids
) = NULL
;
2493 /* Return status value returned by seq number check */
2495 if (!NT_STATUS_IS_OK(domain
->last_status
))
2496 return domain
->last_status
;
2498 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2501 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
2503 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2504 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2505 if (!domain
->internal
&& old_status
) {
2506 set_domain_offline(domain
);
2508 if (!domain
->internal
&&
2511 NTSTATUS cache_status
;
2512 cache_status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2513 num_groups
, user_gids
);
2514 return cache_status
;
2517 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
2521 refresh_sequence_number(domain
, false);
2522 if (!NT_STATUS_IS_OK(status
)) {
2525 centry
= centry_start(domain
, status
);
2529 centry_put_uint32(centry
, *num_groups
);
2530 for (i
=0; i
<(*num_groups
); i
++) {
2531 centry_put_sid(centry
, &(*user_gids
)[i
]);
2534 centry_end(centry
, "UG/%s", sid_to_fstring(sid_string
, user_sid
));
2535 centry_free(centry
);
2541 static char *wcache_make_sidlist(TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2542 const struct dom_sid
*sids
)
2547 sidlist
= talloc_strdup(mem_ctx
, "");
2548 if (sidlist
== NULL
) {
2551 for (i
=0; i
<num_sids
; i
++) {
2553 sidlist
= talloc_asprintf_append_buffer(
2554 sidlist
, "/%s", sid_to_fstring(tmp
, &sids
[i
]));
2555 if (sidlist
== NULL
) {
2562 NTSTATUS
wcache_lookup_useraliases(struct winbindd_domain
*domain
,
2563 TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2564 const struct dom_sid
*sids
,
2565 uint32_t *pnum_aliases
, uint32_t **paliases
)
2567 struct winbind_cache
*cache
= get_cache(domain
);
2568 struct cache_entry
*centry
= NULL
;
2569 uint32_t num_aliases
;
2575 if (cache
->tdb
== NULL
) {
2576 return NT_STATUS_NOT_FOUND
;
2579 if (num_sids
== 0) {
2582 return NT_STATUS_OK
;
2585 /* We need to cache indexed by the whole list of SIDs, the aliases
2586 * resulting might come from any of the SIDs. */
2588 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2589 if (sidlist
== NULL
) {
2590 return NT_STATUS_NO_MEMORY
;
2593 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2594 TALLOC_FREE(sidlist
);
2595 if (centry
== NULL
) {
2596 return NT_STATUS_NOT_FOUND
;
2599 num_aliases
= centry_uint32(centry
);
2600 aliases
= talloc_array(mem_ctx
, uint32_t, num_aliases
);
2601 if (aliases
== NULL
) {
2602 centry_free(centry
);
2603 return NT_STATUS_NO_MEMORY
;
2606 for (i
=0; i
<num_aliases
; i
++) {
2607 aliases
[i
] = centry_uint32(centry
);
2610 status
= centry
->status
;
2612 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2613 "status %s\n", domain
->name
, nt_errstr(status
)));
2615 centry_free(centry
);
2617 *pnum_aliases
= num_aliases
;
2618 *paliases
= aliases
;
2623 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
2624 TALLOC_CTX
*mem_ctx
,
2625 uint32 num_sids
, const struct dom_sid
*sids
,
2626 uint32
*num_aliases
, uint32
**alias_rids
)
2628 struct cache_entry
*centry
= NULL
;
2634 old_status
= domain
->online
;
2635 status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
2636 num_aliases
, alias_rids
);
2637 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2642 (*alias_rids
) = NULL
;
2644 if (!NT_STATUS_IS_OK(domain
->last_status
))
2645 return domain
->last_status
;
2647 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2648 "for domain %s\n", domain
->name
));
2650 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2651 if (sidlist
== NULL
) {
2652 return NT_STATUS_NO_MEMORY
;
2655 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2657 num_aliases
, alias_rids
);
2659 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2660 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2661 if (!domain
->internal
&& old_status
) {
2662 set_domain_offline(domain
);
2664 if (!domain
->internal
&&
2667 NTSTATUS cache_status
;
2668 cache_status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
,
2669 sids
, num_aliases
, alias_rids
);
2670 return cache_status
;
2674 refresh_sequence_number(domain
, false);
2675 if (!NT_STATUS_IS_OK(status
)) {
2678 centry
= centry_start(domain
, status
);
2681 centry_put_uint32(centry
, *num_aliases
);
2682 for (i
=0; i
<(*num_aliases
); i
++)
2683 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2684 centry_end(centry
, "UA%s", sidlist
);
2685 centry_free(centry
);
2691 NTSTATUS
wcache_lookup_groupmem(struct winbindd_domain
*domain
,
2692 TALLOC_CTX
*mem_ctx
,
2693 const struct dom_sid
*group_sid
,
2694 uint32_t *num_names
,
2695 struct dom_sid
**sid_mem
, char ***names
,
2696 uint32_t **name_types
)
2698 struct winbind_cache
*cache
= get_cache(domain
);
2699 struct cache_entry
*centry
= NULL
;
2704 if (cache
->tdb
== NULL
) {
2705 return NT_STATUS_NOT_FOUND
;
2708 sid_string
= sid_string_tos(group_sid
);
2709 if (sid_string
== NULL
) {
2710 return NT_STATUS_NO_MEMORY
;
2713 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_string
);
2714 TALLOC_FREE(sid_string
);
2715 if (centry
== NULL
) {
2716 return NT_STATUS_NOT_FOUND
;
2723 *num_names
= centry_uint32(centry
);
2724 if (*num_names
== 0) {
2725 centry_free(centry
);
2726 return NT_STATUS_OK
;
2729 *sid_mem
= talloc_array(mem_ctx
, struct dom_sid
, *num_names
);
2730 *names
= talloc_array(mem_ctx
, char *, *num_names
);
2731 *name_types
= talloc_array(mem_ctx
, uint32
, *num_names
);
2733 if ((*sid_mem
== NULL
) || (*names
== NULL
) || (*name_types
== NULL
)) {
2734 TALLOC_FREE(*sid_mem
);
2735 TALLOC_FREE(*names
);
2736 TALLOC_FREE(*name_types
);
2737 centry_free(centry
);
2738 return NT_STATUS_NO_MEMORY
;
2741 for (i
=0; i
<(*num_names
); i
++) {
2742 centry_sid(centry
, &(*sid_mem
)[i
]);
2743 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2744 (*name_types
)[i
] = centry_uint32(centry
);
2747 status
= centry
->status
;
2749 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2750 "status: %s\n", domain
->name
, nt_errstr(status
)));
2752 centry_free(centry
);
2756 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
2757 TALLOC_CTX
*mem_ctx
,
2758 const struct dom_sid
*group_sid
,
2759 enum lsa_SidType type
,
2761 struct dom_sid
**sid_mem
, char ***names
,
2762 uint32
**name_types
)
2764 struct cache_entry
*centry
= NULL
;
2770 old_status
= domain
->online
;
2771 status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2772 sid_mem
, names
, name_types
);
2773 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2780 (*name_types
) = NULL
;
2782 /* Return status value returned by seq number check */
2784 if (!NT_STATUS_IS_OK(domain
->last_status
))
2785 return domain
->last_status
;
2787 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2790 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
,
2792 sid_mem
, names
, name_types
);
2794 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2795 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2796 if (!domain
->internal
&& old_status
) {
2797 set_domain_offline(domain
);
2799 if (!domain
->internal
&&
2802 NTSTATUS cache_status
;
2803 cache_status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
,
2804 num_names
, sid_mem
, names
,
2806 return cache_status
;
2810 refresh_sequence_number(domain
, false);
2811 if (!NT_STATUS_IS_OK(status
)) {
2814 centry
= centry_start(domain
, status
);
2817 centry_put_uint32(centry
, *num_names
);
2818 for (i
=0; i
<(*num_names
); i
++) {
2819 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2820 centry_put_string(centry
, (*names
)[i
]);
2821 centry_put_uint32(centry
, (*name_types
)[i
]);
2823 centry_end(centry
, "GM/%s", sid_to_fstring(sid_string
, group_sid
));
2824 centry_free(centry
);
2830 /* find the sequence number for a domain */
2831 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
2833 refresh_sequence_number(domain
, false);
2835 *seq
= domain
->sequence_number
;
2837 return NT_STATUS_OK
;
2840 /* enumerate trusted domains
2841 * (we need to have the list of trustdoms in the cache when we go offline) -
2843 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
2844 TALLOC_CTX
*mem_ctx
,
2845 struct netr_DomainTrustList
*trusts
)
2848 struct winbind_cache
*cache
;
2849 struct winbindd_tdc_domain
*dom_list
= NULL
;
2850 size_t num_domains
= 0;
2851 bool retval
= false;
2855 old_status
= domain
->online
;
2857 trusts
->array
= NULL
;
2859 cache
= get_cache(domain
);
2860 if (!cache
|| !cache
->tdb
) {
2864 if (domain
->online
) {
2868 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2869 if (!retval
|| !num_domains
|| !dom_list
) {
2870 TALLOC_FREE(dom_list
);
2875 trusts
->array
= talloc_zero_array(mem_ctx
, struct netr_DomainTrust
, num_domains
);
2876 if (!trusts
->array
) {
2877 TALLOC_FREE(dom_list
);
2878 return NT_STATUS_NO_MEMORY
;
2881 for (i
= 0; i
< num_domains
; i
++) {
2882 struct netr_DomainTrust
*trust
;
2883 struct dom_sid
*sid
;
2884 struct winbindd_domain
*dom
;
2886 dom
= find_domain_from_name_noinit(dom_list
[i
].domain_name
);
2887 if (dom
&& dom
->internal
) {
2891 trust
= &trusts
->array
[trusts
->count
];
2892 trust
->netbios_name
= talloc_strdup(trusts
->array
, dom_list
[i
].domain_name
);
2893 trust
->dns_name
= talloc_strdup(trusts
->array
, dom_list
[i
].dns_name
);
2894 sid
= talloc(trusts
->array
, struct dom_sid
);
2895 if (!trust
->netbios_name
|| !trust
->dns_name
||
2897 TALLOC_FREE(dom_list
);
2898 TALLOC_FREE(trusts
->array
);
2899 return NT_STATUS_NO_MEMORY
;
2902 trust
->trust_flags
= dom_list
[i
].trust_flags
;
2903 trust
->trust_attributes
= dom_list
[i
].trust_attribs
;
2904 trust
->trust_type
= dom_list
[i
].trust_type
;
2905 sid_copy(sid
, &dom_list
[i
].sid
);
2910 TALLOC_FREE(dom_list
);
2911 return NT_STATUS_OK
;
2914 /* Return status value returned by seq number check */
2916 if (!NT_STATUS_IS_OK(domain
->last_status
))
2917 return domain
->last_status
;
2919 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2922 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, trusts
);
2924 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2925 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2926 if (!domain
->internal
&& old_status
) {
2927 set_domain_offline(domain
);
2929 if (!domain
->internal
&&
2932 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2933 if (retval
&& num_domains
&& dom_list
) {
2934 TALLOC_FREE(trusts
->array
);
2936 goto do_fetch_cache
;
2940 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2941 * so that the generic centry handling still applies correctly -
2944 if (!NT_STATUS_IS_ERR(status
)) {
2945 status
= NT_STATUS_OK
;
2950 /* get lockout policy */
2951 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
2952 TALLOC_CTX
*mem_ctx
,
2953 struct samr_DomInfo12
*policy
)
2955 struct winbind_cache
*cache
= get_cache(domain
);
2956 struct cache_entry
*centry
= NULL
;
2960 old_status
= domain
->online
;
2964 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2970 policy
->lockout_duration
= centry_nttime(centry
);
2971 policy
->lockout_window
= centry_nttime(centry
);
2972 policy
->lockout_threshold
= centry_uint16(centry
);
2974 status
= centry
->status
;
2976 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2977 domain
->name
, nt_errstr(status
) ));
2979 centry_free(centry
);
2983 ZERO_STRUCTP(policy
);
2985 /* Return status value returned by seq number check */
2987 if (!NT_STATUS_IS_OK(domain
->last_status
))
2988 return domain
->last_status
;
2990 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2993 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2995 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2996 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2997 if (!domain
->internal
&& old_status
) {
2998 set_domain_offline(domain
);
3001 !domain
->internal
&&
3004 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
3006 goto do_fetch_cache
;
3011 refresh_sequence_number(domain
, false);
3012 if (!NT_STATUS_IS_OK(status
)) {
3015 wcache_save_lockout_policy(domain
, status
, policy
);
3020 /* get password policy */
3021 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
3022 TALLOC_CTX
*mem_ctx
,
3023 struct samr_DomInfo1
*policy
)
3025 struct winbind_cache
*cache
= get_cache(domain
);
3026 struct cache_entry
*centry
= NULL
;
3030 old_status
= domain
->online
;
3034 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
3040 policy
->min_password_length
= centry_uint16(centry
);
3041 policy
->password_history_length
= centry_uint16(centry
);
3042 policy
->password_properties
= centry_uint32(centry
);
3043 policy
->max_password_age
= centry_nttime(centry
);
3044 policy
->min_password_age
= centry_nttime(centry
);
3046 status
= centry
->status
;
3048 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
3049 domain
->name
, nt_errstr(status
) ));
3051 centry_free(centry
);
3055 ZERO_STRUCTP(policy
);
3057 /* Return status value returned by seq number check */
3059 if (!NT_STATUS_IS_OK(domain
->last_status
))
3060 return domain
->last_status
;
3062 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
3065 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
3067 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
3068 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
3069 if (!domain
->internal
&& old_status
) {
3070 set_domain_offline(domain
);
3073 !domain
->internal
&&
3076 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
3078 goto do_fetch_cache
;
3083 refresh_sequence_number(domain
, false);
3084 if (!NT_STATUS_IS_OK(status
)) {
3087 wcache_save_password_policy(domain
, status
, policy
);
3093 /* Invalidate cached user and group lists coherently */
3095 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3098 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
3099 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
3100 tdb_delete(the_tdb
, kbuf
);
3105 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3107 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
3108 const struct dom_sid
*sid
)
3110 fstring key_str
, sid_string
;
3111 struct winbind_cache
*cache
;
3113 /* dont clear cached U/SID and UG/SID entries when we want to logon
3116 if (lp_winbind_offline_logon()) {
3123 cache
= get_cache(domain
);
3129 /* Clear U/SID cache entry */
3130 fstr_sprintf(key_str
, "U/%s", sid_to_fstring(sid_string
, sid
));
3131 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3132 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3134 /* Clear UG/SID cache entry */
3135 fstr_sprintf(key_str
, "UG/%s", sid_to_fstring(sid_string
, sid
));
3136 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3137 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3139 /* Samba/winbindd never needs this. */
3140 netsamlogon_clear_cached_user(sid
);
3143 bool wcache_invalidate_cache(void)
3145 struct winbindd_domain
*domain
;
3147 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3148 struct winbind_cache
*cache
= get_cache(domain
);
3150 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3151 "entries for %s\n", domain
->name
));
3154 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3163 bool wcache_invalidate_cache_noinit(void)
3165 struct winbindd_domain
*domain
;
3167 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3168 struct winbind_cache
*cache
;
3170 /* Skip uninitialized domains. */
3171 if (!domain
->initialized
&& !domain
->internal
) {
3175 cache
= get_cache(domain
);
3177 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3178 "entries for %s\n", domain
->name
));
3181 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3183 * Flushing cache has nothing to with domains.
3184 * return here if we successfully flushed once.
3185 * To avoid unnecessary traversing the cache.
3196 bool init_wcache(void)
3200 if (wcache
== NULL
) {
3201 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
3202 ZERO_STRUCTP(wcache
);
3205 if (wcache
->tdb
!= NULL
)
3208 db_path
= state_path("winbindd_cache.tdb");
3209 if (db_path
== NULL
) {
3213 /* when working offline we must not clear the cache on restart */
3214 wcache
->tdb
= tdb_open_log(db_path
,
3215 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3216 TDB_INCOMPATIBLE_HASH
|
3217 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3218 O_RDWR
|O_CREAT
, 0600);
3219 TALLOC_FREE(db_path
);
3220 if (wcache
->tdb
== NULL
) {
3221 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3228 /************************************************************************
3229 This is called by the parent to initialize the cache file.
3230 We don't need sophisticated locking here as we know we're the
3232 ************************************************************************/
3234 bool initialize_winbindd_cache(void)
3236 bool cache_bad
= true;
3239 if (!init_wcache()) {
3240 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3244 /* Check version number. */
3245 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
3246 vers
== WINBINDD_CACHE_VERSION
) {
3253 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3254 "and re-creating with version number %d\n",
3255 WINBINDD_CACHE_VERSION
));
3257 tdb_close(wcache
->tdb
);
3260 db_path
= state_path("winbindd_cache.tdb");
3261 if (db_path
== NULL
) {
3265 if (unlink(db_path
) == -1) {
3266 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3269 TALLOC_FREE(db_path
);
3272 TALLOC_FREE(db_path
);
3273 if (!init_wcache()) {
3274 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3275 "init_wcache failed.\n"));
3279 /* Write the version. */
3280 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
3281 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3282 tdb_errorstr(wcache
->tdb
) ));
3287 tdb_close(wcache
->tdb
);
3292 void close_winbindd_cache(void)
3298 tdb_close(wcache
->tdb
);
3303 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*sid
,
3304 char **domain_name
, char **name
,
3305 enum lsa_SidType
*type
)
3307 struct winbindd_domain
*domain
;
3310 domain
= find_lookup_domain_from_sid(sid
);
3311 if (domain
== NULL
) {
3314 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
3316 return NT_STATUS_IS_OK(status
);
3319 bool lookup_cached_name(const char *domain_name
,
3321 struct dom_sid
*sid
,
3322 enum lsa_SidType
*type
)
3324 struct winbindd_domain
*domain
;
3326 bool original_online_state
;
3328 domain
= find_lookup_domain_from_name(domain_name
);
3329 if (domain
== NULL
) {
3333 /* If we are doing a cached logon, temporarily set the domain
3334 offline so the cache won't expire the entry */
3336 original_online_state
= domain
->online
;
3337 domain
->online
= false;
3338 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
3339 domain
->online
= original_online_state
;
3341 return NT_STATUS_IS_OK(status
);
3344 void cache_name2sid(struct winbindd_domain
*domain
,
3345 const char *domain_name
, const char *name
,
3346 enum lsa_SidType type
, const struct dom_sid
*sid
)
3348 refresh_sequence_number(domain
, false);
3349 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
3354 * The original idea that this cache only contains centries has
3355 * been blurred - now other stuff gets put in here. Ensure we
3356 * ignore these things on cleanup.
3359 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
3360 TDB_DATA dbuf
, void *state
)
3362 struct cache_entry
*centry
;
3364 if (is_non_centry_key(kbuf
)) {
3368 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
3373 if (!NT_STATUS_IS_OK(centry
->status
)) {
3374 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
3375 tdb_delete(the_tdb
, kbuf
);
3378 centry_free(centry
);
3382 /* flush the cache */
3383 void wcache_flush_cache(void)
3390 tdb_close(wcache
->tdb
);
3393 if (!winbindd_use_cache()) {
3397 db_path
= state_path("winbindd_cache.tdb");
3398 if (db_path
== NULL
) {
3402 /* when working offline we must not clear the cache on restart */
3403 wcache
->tdb
= tdb_open_log(db_path
,
3404 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3405 TDB_INCOMPATIBLE_HASH
|
3406 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3407 O_RDWR
|O_CREAT
, 0600);
3408 TALLOC_FREE(db_path
);
3410 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3414 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
3416 DEBUG(10,("wcache_flush_cache success\n"));
3419 /* Count cached creds */
3421 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3424 int *cred_count
= (int*)state
;
3426 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3432 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
3434 struct winbind_cache
*cache
= get_cache(domain
);
3439 return NT_STATUS_INTERNAL_DB_ERROR
;
3442 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
3444 return NT_STATUS_OK
;
3448 struct cred_list
*prev
, *next
;
3453 static struct cred_list
*wcache_cred_list
;
3455 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3458 struct cred_list
*cred
;
3460 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3462 cred
= SMB_MALLOC_P(struct cred_list
);
3464 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3470 /* save a copy of the key */
3472 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
3473 DLIST_ADD(wcache_cred_list
, cred
);
3479 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
3481 struct winbind_cache
*cache
= get_cache(domain
);
3484 struct cred_list
*cred
, *oldest
= NULL
;
3487 return NT_STATUS_INTERNAL_DB_ERROR
;
3490 /* we possibly already have an entry */
3491 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
3493 fstring key_str
, tmp
;
3495 DEBUG(11,("we already have an entry, deleting that\n"));
3497 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
3499 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3501 return NT_STATUS_OK
;
3504 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
3506 return NT_STATUS_OK
;
3507 } else if ((ret
< 0) || (wcache_cred_list
== NULL
)) {
3508 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3511 ZERO_STRUCTP(oldest
);
3513 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
3518 data
= tdb_fetch(cache
->tdb
, string_tdb_data(cred
->name
));
3520 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3522 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3526 t
= IVAL(data
.dptr
, 0);
3527 SAFE_FREE(data
.dptr
);
3530 oldest
= SMB_MALLOC_P(struct cred_list
);
3531 if (oldest
== NULL
) {
3532 status
= NT_STATUS_NO_MEMORY
;
3536 fstrcpy(oldest
->name
, cred
->name
);
3537 oldest
->created
= t
;
3541 if (t
< oldest
->created
) {
3542 fstrcpy(oldest
->name
, cred
->name
);
3543 oldest
->created
= t
;
3547 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3548 status
= NT_STATUS_OK
;
3550 status
= NT_STATUS_UNSUCCESSFUL
;
3553 SAFE_FREE(wcache_cred_list
);
3559 /* Change the global online/offline state. */
3560 bool set_global_winbindd_state_offline(void)
3564 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3566 /* Only go offline if someone has created
3567 the key "WINBINDD_OFFLINE" in the cache tdb. */
3569 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3570 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3574 if (!lp_winbind_offline_logon()) {
3575 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3579 if (global_winbindd_offline_state
) {
3580 /* Already offline. */
3584 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
3586 if (!data
.dptr
|| data
.dsize
!= 4) {
3587 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3588 SAFE_FREE(data
.dptr
);
3591 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3592 global_winbindd_offline_state
= true;
3593 SAFE_FREE(data
.dptr
);
3598 void set_global_winbindd_state_online(void)
3600 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3602 if (!lp_winbind_offline_logon()) {
3603 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3607 if (!global_winbindd_offline_state
) {
3608 /* Already online. */
3611 global_winbindd_offline_state
= false;
3617 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3618 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3621 bool get_global_winbindd_state_offline(void)
3623 return global_winbindd_offline_state
;
3626 /***********************************************************************
3627 Validate functions for all possible cache tdb keys.
3628 ***********************************************************************/
3630 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3631 struct tdb_validation_status
*state
)
3633 struct cache_entry
*centry
;
3635 centry
= SMB_XMALLOC_P(struct cache_entry
);
3636 centry
->data
= (unsigned char *)smb_memdup(data
.dptr
, data
.dsize
);
3637 if (!centry
->data
) {
3641 centry
->len
= data
.dsize
;
3644 if (centry
->len
< 16) {
3645 /* huh? corrupt cache? */
3646 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3647 "(len < 16) ?\n", kstr
));
3648 centry_free(centry
);
3649 state
->bad_entry
= true;
3650 state
->success
= false;
3654 centry
->status
= NT_STATUS(centry_uint32(centry
));
3655 centry
->sequence_number
= centry_uint32(centry
);
3656 centry
->timeout
= centry_uint64_t(centry
);
3660 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3661 struct tdb_validation_status
*state
)
3663 if (dbuf
.dsize
!= 8) {
3664 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3665 keystr
, (unsigned int)dbuf
.dsize
));
3666 state
->bad_entry
= true;
3672 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3673 struct tdb_validation_status
*state
)
3675 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3680 (void)centry_uint32(centry
);
3681 if (NT_STATUS_IS_OK(centry
->status
)) {
3683 (void)centry_sid(centry
, &sid
);
3686 centry_free(centry
);
3688 if (!(state
->success
)) {
3691 DEBUG(10,("validate_ns: %s ok\n", keystr
));
3695 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3696 struct tdb_validation_status
*state
)
3698 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3703 if (NT_STATUS_IS_OK(centry
->status
)) {
3704 (void)centry_uint32(centry
);
3705 (void)centry_string(centry
, mem_ctx
);
3706 (void)centry_string(centry
, mem_ctx
);
3709 centry_free(centry
);
3711 if (!(state
->success
)) {
3714 DEBUG(10,("validate_sn: %s ok\n", keystr
));
3718 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3719 struct tdb_validation_status
*state
)
3721 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3728 (void)centry_string(centry
, mem_ctx
);
3729 (void)centry_string(centry
, mem_ctx
);
3730 (void)centry_string(centry
, mem_ctx
);
3731 (void)centry_string(centry
, mem_ctx
);
3732 (void)centry_uint32(centry
);
3733 (void)centry_sid(centry
, &sid
);
3734 (void)centry_sid(centry
, &sid
);
3736 centry_free(centry
);
3738 if (!(state
->success
)) {
3741 DEBUG(10,("validate_u: %s ok\n", keystr
));
3745 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3746 struct tdb_validation_status
*state
)
3748 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3754 (void)centry_nttime(centry
);
3755 (void)centry_nttime(centry
);
3756 (void)centry_uint16(centry
);
3758 centry_free(centry
);
3760 if (!(state
->success
)) {
3763 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3767 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3768 struct tdb_validation_status
*state
)
3770 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3776 (void)centry_uint16(centry
);
3777 (void)centry_uint16(centry
);
3778 (void)centry_uint32(centry
);
3779 (void)centry_nttime(centry
);
3780 (void)centry_nttime(centry
);
3782 centry_free(centry
);
3784 if (!(state
->success
)) {
3787 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3791 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3792 struct tdb_validation_status
*state
)
3794 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3800 (void)centry_time(centry
);
3801 (void)centry_hash16(centry
, mem_ctx
);
3803 /* We only have 17 bytes more data in the salted cred case. */
3804 if (centry
->len
- centry
->ofs
== 17) {
3805 (void)centry_hash16(centry
, mem_ctx
);
3808 centry_free(centry
);
3810 if (!(state
->success
)) {
3813 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3817 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3818 struct tdb_validation_status
*state
)
3820 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3821 int32 num_entries
, i
;
3827 num_entries
= (int32
)centry_uint32(centry
);
3829 for (i
=0; i
< num_entries
; i
++) {
3831 (void)centry_string(centry
, mem_ctx
);
3832 (void)centry_string(centry
, mem_ctx
);
3833 (void)centry_string(centry
, mem_ctx
);
3834 (void)centry_string(centry
, mem_ctx
);
3835 (void)centry_sid(centry
, &sid
);
3836 (void)centry_sid(centry
, &sid
);
3839 centry_free(centry
);
3841 if (!(state
->success
)) {
3844 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3848 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3849 struct tdb_validation_status
*state
)
3851 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3852 int32 num_entries
, i
;
3858 num_entries
= centry_uint32(centry
);
3860 for (i
=0; i
< num_entries
; i
++) {
3861 (void)centry_string(centry
, mem_ctx
);
3862 (void)centry_string(centry
, mem_ctx
);
3863 (void)centry_uint32(centry
);
3866 centry_free(centry
);
3868 if (!(state
->success
)) {
3871 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3875 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3876 struct tdb_validation_status
*state
)
3878 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3879 int32 num_groups
, i
;
3885 num_groups
= centry_uint32(centry
);
3887 for (i
=0; i
< num_groups
; i
++) {
3889 centry_sid(centry
, &sid
);
3892 centry_free(centry
);
3894 if (!(state
->success
)) {
3897 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3901 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3902 struct tdb_validation_status
*state
)
3904 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3905 int32 num_aliases
, i
;
3911 num_aliases
= centry_uint32(centry
);
3913 for (i
=0; i
< num_aliases
; i
++) {
3914 (void)centry_uint32(centry
);
3917 centry_free(centry
);
3919 if (!(state
->success
)) {
3922 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3926 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3927 struct tdb_validation_status
*state
)
3929 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3936 num_names
= centry_uint32(centry
);
3938 for (i
=0; i
< num_names
; i
++) {
3940 centry_sid(centry
, &sid
);
3941 (void)centry_string(centry
, mem_ctx
);
3942 (void)centry_uint32(centry
);
3945 centry_free(centry
);
3947 if (!(state
->success
)) {
3950 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3954 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3955 struct tdb_validation_status
*state
)
3957 /* Can't say anything about this other than must be nonzero. */
3958 if (dbuf
.dsize
== 0) {
3959 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3961 state
->bad_entry
= true;
3962 state
->success
= false;
3966 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3970 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3971 struct tdb_validation_status
*state
)
3973 /* Can't say anything about this other than must be nonzero. */
3974 if (dbuf
.dsize
== 0) {
3975 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3977 state
->bad_entry
= true;
3978 state
->success
= false;
3982 DEBUG(10,("validate_de: %s ok\n", keystr
));
3986 static int validate_pwinfo(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3987 TDB_DATA dbuf
, struct tdb_validation_status
*state
)
3989 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3995 (void)centry_string(centry
, mem_ctx
);
3996 (void)centry_string(centry
, mem_ctx
);
3997 (void)centry_string(centry
, mem_ctx
);
3998 (void)centry_uint32(centry
);
4000 centry_free(centry
);
4002 if (!(state
->success
)) {
4005 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
4009 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
4011 struct tdb_validation_status
*state
)
4013 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
4019 (void)centry_string( centry
, mem_ctx
);
4021 centry_free(centry
);
4023 if (!(state
->success
)) {
4026 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
4030 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
4032 struct tdb_validation_status
*state
)
4034 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
4040 (void)centry_string( centry
, mem_ctx
);
4042 centry_free(centry
);
4044 if (!(state
->success
)) {
4047 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
4051 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
4053 struct tdb_validation_status
*state
)
4055 if (dbuf
.dsize
== 0) {
4056 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
4057 "key %s (len ==0) ?\n", keystr
));
4058 state
->bad_entry
= true;
4059 state
->success
= false;
4063 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
4064 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
4068 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
4069 struct tdb_validation_status
*state
)
4071 if (dbuf
.dsize
!= 4) {
4072 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
4073 keystr
, (unsigned int)dbuf
.dsize
));
4074 state
->bad_entry
= true;
4075 state
->success
= false;
4078 DEBUG(10,("validate_offline: %s ok\n", keystr
));
4082 static int validate_ndr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
4083 struct tdb_validation_status
*state
)
4086 * Ignore validation for now. The proper way to do this is with a
4087 * checksum. Just pure parsing does not really catch much.
4092 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
4093 struct tdb_validation_status
*state
)
4095 if (dbuf
.dsize
!= 4) {
4096 DEBUG(0, ("validate_cache_version: Corrupt cache for "
4097 "key %s (len %u != 4) ?\n",
4098 keystr
, (unsigned int)dbuf
.dsize
));
4099 state
->bad_entry
= true;
4100 state
->success
= false;
4104 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
4108 /***********************************************************************
4109 A list of all possible cache tdb keys with associated validation
4111 ***********************************************************************/
4113 struct key_val_struct
{
4114 const char *keyname
;
4115 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
4117 {"SEQNUM/", validate_seqnum
},
4118 {"NS/", validate_ns
},
4119 {"SN/", validate_sn
},
4121 {"LOC_POL/", validate_loc_pol
},
4122 {"PWD_POL/", validate_pwd_pol
},
4123 {"CRED/", validate_cred
},
4124 {"UL/", validate_ul
},
4125 {"GL/", validate_gl
},
4126 {"UG/", validate_ug
},
4127 {"UA", validate_ua
},
4128 {"GM/", validate_gm
},
4129 {"DR/", validate_dr
},
4130 {"DE/", validate_de
},
4131 {"NSS/PWINFO/", validate_pwinfo
},
4132 {"TRUSTDOMCACHE/", validate_trustdomcache
},
4133 {"NSS/NA/", validate_nss_na
},
4134 {"NSS/AN/", validate_nss_an
},
4135 {"WINBINDD_OFFLINE", validate_offline
},
4136 {"NDR/", validate_ndr
},
4137 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
4141 /***********************************************************************
4142 Function to look at every entry in the tdb and validate it as far as
4144 ***********************************************************************/
4146 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
4149 unsigned int max_key_len
= 1024;
4150 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
4152 /* Paranoia check. */
4153 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0 ||
4154 strncmp("NDR/", (const char *)kbuf
.dptr
, 4) == 0) {
4155 max_key_len
= 1024 * 1024;
4157 if (kbuf
.dsize
> max_key_len
) {
4158 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4160 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
4164 for (i
= 0; key_val
[i
].keyname
; i
++) {
4165 size_t namelen
= strlen(key_val
[i
].keyname
);
4166 if (kbuf
.dsize
>= namelen
&& (
4167 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
4168 TALLOC_CTX
*mem_ctx
;
4172 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
4176 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
4177 keystr
[kbuf
.dsize
] = '\0';
4179 mem_ctx
= talloc_init("validate_ctx");
4185 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
4189 talloc_destroy(mem_ctx
);
4194 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4195 dump_data(0, (uint8
*)kbuf
.dptr
, kbuf
.dsize
);
4196 DEBUG(0,("data :\n"));
4197 dump_data(0, (uint8
*)dbuf
.dptr
, dbuf
.dsize
);
4198 v_state
->unknown_key
= true;
4199 v_state
->success
= false;
4200 return 1; /* terminate. */
4203 static void validate_panic(const char *const why
)
4205 DEBUG(0,("validating cache: would panic %s\n", why
));
4206 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4210 static int wbcache_update_centry_fn(TDB_CONTEXT
*tdb
,
4218 if (is_non_centry_key(key
)) {
4222 if (data
.dptr
== NULL
|| data
.dsize
== 0) {
4223 if (tdb_delete(tdb
, key
) < 0) {
4224 DEBUG(0, ("tdb_delete for [%s] failed!\n",
4230 /* add timeout to blob (uint64_t) */
4231 blob
.dsize
= data
.dsize
+ 8;
4233 blob
.dptr
= SMB_XMALLOC_ARRAY(uint8_t, blob
.dsize
);
4234 if (blob
.dptr
== NULL
) {
4237 memset(blob
.dptr
, 0, blob
.dsize
);
4239 /* copy status and seqnum */
4240 memcpy(blob
.dptr
, data
.dptr
, 8);
4243 ctimeout
= lp_winbind_cache_time() + time(NULL
);
4244 SBVAL(blob
.dptr
, 8, ctimeout
);
4247 memcpy(blob
.dptr
+ 16, data
.dptr
+ 8, data
.dsize
- 8);
4249 if (tdb_store(tdb
, key
, blob
, TDB_REPLACE
) < 0) {
4250 DEBUG(0, ("tdb_store to update [%s] failed!\n",
4252 SAFE_FREE(blob
.dptr
);
4256 SAFE_FREE(blob
.dptr
);
4260 static bool wbcache_upgrade_v1_to_v2(TDB_CONTEXT
*tdb
)
4264 DEBUG(1, ("Upgrade to version 2 of the winbindd_cache.tdb\n"));
4266 rc
= tdb_traverse(tdb
, wbcache_update_centry_fn
, NULL
);
4274 /***********************************************************************
4275 Try and validate every entry in the winbindd cache. If we fail here,
4276 delete the cache tdb and return non-zero.
4277 ***********************************************************************/
4279 int winbindd_validate_cache(void)
4282 char *tdb_path
= NULL
;
4283 TDB_CONTEXT
*tdb
= NULL
;
4287 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4288 smb_panic_fn
= validate_panic
;
4290 tdb_path
= state_path("winbindd_cache.tdb");
4291 if (tdb_path
== NULL
) {
4295 tdb
= tdb_open_log(tdb_path
,
4296 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
4297 TDB_INCOMPATIBLE_HASH
|
4298 ( lp_winbind_offline_logon()
4300 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
4304 DEBUG(0, ("winbindd_validate_cache: "
4305 "error opening/initializing tdb\n"));
4309 /* Version check and upgrade code. */
4310 if (!tdb_fetch_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers_id
)) {
4311 DEBUG(10, ("Fresh database\n"));
4312 tdb_store_uint32(tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
);
4313 vers_id
= WINBINDD_CACHE_VERSION
;
4316 if (vers_id
!= WINBINDD_CACHE_VERSION
) {
4317 if (vers_id
== WINBINDD_CACHE_VER1
) {
4318 ok
= wbcache_upgrade_v1_to_v2(tdb
);
4320 DEBUG(10, ("winbindd_validate_cache: upgrade to version 2 failed.\n"));
4325 tdb_store_uint32(tdb
,
4326 WINBINDD_CACHE_VERSION_KEYSTR
,
4327 WINBINDD_CACHE_VERSION
);
4328 vers_id
= WINBINDD_CACHE_VER2
;
4334 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
4337 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4338 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
4343 TALLOC_FREE(tdb_path
);
4344 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4345 smb_panic_fn
= smb_panic
;
4349 /***********************************************************************
4350 Try and validate every entry in the winbindd cache.
4351 ***********************************************************************/
4353 int winbindd_validate_cache_nobackup(void)
4358 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4359 smb_panic_fn
= validate_panic
;
4361 tdb_path
= state_path("winbindd_cache.tdb");
4362 if (tdb_path
== NULL
) {
4363 goto err_panic_restore
;
4366 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
4367 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
4369 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
4373 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4377 TALLOC_FREE(tdb_path
);
4379 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4381 smb_panic_fn
= smb_panic
;
4385 bool winbindd_cache_validate_and_initialize(void)
4387 close_winbindd_cache();
4389 if (lp_winbind_offline_logon()) {
4390 if (winbindd_validate_cache() < 0) {
4391 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4392 "could be restored.\n"));
4396 return initialize_winbindd_cache();
4399 /*********************************************************************
4400 ********************************************************************/
4402 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
4403 struct winbindd_tdc_domain
**domains
,
4404 size_t *num_domains
)
4406 struct winbindd_tdc_domain
*list
= NULL
;
4409 bool set_only
= false;
4411 /* don't allow duplicates */
4416 for ( i
=0; i
< (*num_domains
); i
++ ) {
4417 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
4418 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4429 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, 1 );
4432 list
= talloc_realloc( *domains
, *domains
,
4433 struct winbindd_tdc_domain
,
4438 ZERO_STRUCT( list
[idx
] );
4444 list
[idx
].domain_name
= talloc_strdup(list
, new_dom
->name
);
4445 if (list
[idx
].domain_name
== NULL
) {
4448 if (new_dom
->alt_name
!= NULL
) {
4449 list
[idx
].dns_name
= talloc_strdup(list
, new_dom
->alt_name
);
4450 if (list
[idx
].dns_name
== NULL
) {
4455 if ( !is_null_sid( &new_dom
->sid
) ) {
4456 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
4458 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
4461 if ( new_dom
->domain_flags
!= 0x0 )
4462 list
[idx
].trust_flags
= new_dom
->domain_flags
;
4464 if ( new_dom
->domain_type
!= 0x0 )
4465 list
[idx
].trust_type
= new_dom
->domain_type
;
4467 if ( new_dom
->domain_trust_attribs
!= 0x0 )
4468 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
4472 *num_domains
= idx
+ 1;
4478 /*********************************************************************
4479 ********************************************************************/
4481 static TDB_DATA
make_tdc_key( const char *domain_name
)
4483 char *keystr
= NULL
;
4484 TDB_DATA key
= { NULL
, 0 };
4486 if ( !domain_name
) {
4487 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4491 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
4494 key
= string_term_tdb_data(keystr
);
4499 /*********************************************************************
4500 ********************************************************************/
4502 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
4504 unsigned char **buf
)
4506 unsigned char *buffer
= NULL
;
4511 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4519 /* Store the number of array items first */
4520 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
4523 /* now pack each domain trust record */
4524 for ( i
=0; i
<num_domains
; i
++ ) {
4529 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4530 domains
[i
].domain_name
,
4531 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
4534 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
4535 domains
[i
].domain_name
,
4536 domains
[i
].dns_name
? domains
[i
].dns_name
: "",
4537 sid_to_fstring(tmp
, &domains
[i
].sid
),
4538 domains
[i
].trust_flags
,
4539 domains
[i
].trust_attribs
,
4540 domains
[i
].trust_type
);
4543 if ( buflen
< len
) {
4545 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
4546 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4560 /*********************************************************************
4561 ********************************************************************/
4563 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
4564 struct winbindd_tdc_domain
**domains
)
4566 fstring domain_name
, dns_name
, sid_string
;
4567 uint32 type
, attribs
, flags
;
4571 struct winbindd_tdc_domain
*list
= NULL
;
4573 /* get the number of domains */
4574 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
4576 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4580 list
= talloc_array( NULL
, struct winbindd_tdc_domain
, num_domains
);
4582 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4586 for ( i
=0; i
<num_domains
; i
++ ) {
4589 this_len
= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
4597 if ( this_len
== -1 ) {
4598 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4599 TALLOC_FREE( list
);
4604 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4605 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4606 domain_name
, dns_name
, sid_string
,
4607 flags
, attribs
, type
));
4609 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
4610 list
[i
].dns_name
= NULL
;
4611 if (dns_name
[0] != '\0') {
4612 list
[i
].dns_name
= talloc_strdup(list
, dns_name
);
4614 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
4615 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4618 list
[i
].trust_flags
= flags
;
4619 list
[i
].trust_attribs
= attribs
;
4620 list
[i
].trust_type
= type
;
4628 /*********************************************************************
4629 ********************************************************************/
4631 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
4633 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4634 TDB_DATA data
= { NULL
, 0 };
4640 /* See if we were asked to delete the cache entry */
4643 ret
= tdb_delete( wcache
->tdb
, key
);
4647 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4654 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4657 SAFE_FREE( data
.dptr
);
4658 SAFE_FREE( key
.dptr
);
4660 return ( ret
== 0 );
4663 /*********************************************************************
4664 ********************************************************************/
4666 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4668 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4669 TDB_DATA data
= { NULL
, 0 };
4677 data
= tdb_fetch( wcache
->tdb
, key
);
4679 SAFE_FREE( key
.dptr
);
4684 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4686 SAFE_FREE( data
.dptr
);
4694 /*********************************************************************
4695 ********************************************************************/
4697 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4699 struct winbindd_tdc_domain
*dom_list
= NULL
;
4700 size_t num_domains
= 0;
4703 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4704 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4705 domain
->name
, domain
->alt_name
,
4706 sid_string_dbg(&domain
->sid
),
4707 domain
->domain_flags
,
4708 domain
->domain_trust_attribs
,
4709 domain
->domain_type
));
4711 if ( !init_wcache() ) {
4715 /* fetch the list */
4717 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4719 /* add the new domain */
4721 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4725 /* pack the domain */
4727 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4735 TALLOC_FREE( dom_list
);
4740 static struct winbindd_tdc_domain
*wcache_tdc_dup_domain(
4741 TALLOC_CTX
*mem_ctx
, const struct winbindd_tdc_domain
*src
)
4743 struct winbindd_tdc_domain
*dst
;
4745 dst
= talloc(mem_ctx
, struct winbindd_tdc_domain
);
4749 dst
->domain_name
= talloc_strdup(dst
, src
->domain_name
);
4750 if (dst
->domain_name
== NULL
) {
4754 dst
->dns_name
= NULL
;
4755 if (src
->dns_name
!= NULL
) {
4756 dst
->dns_name
= talloc_strdup(dst
, src
->dns_name
);
4757 if (dst
->dns_name
== NULL
) {
4762 sid_copy(&dst
->sid
, &src
->sid
);
4763 dst
->trust_flags
= src
->trust_flags
;
4764 dst
->trust_type
= src
->trust_type
;
4765 dst
->trust_attribs
= src
->trust_attribs
;
4772 /*********************************************************************
4773 ********************************************************************/
4775 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4777 struct winbindd_tdc_domain
*dom_list
= NULL
;
4778 size_t num_domains
= 0;
4780 struct winbindd_tdc_domain
*d
= NULL
;
4782 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4784 if ( !init_wcache() ) {
4788 /* fetch the list */
4790 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4792 for ( i
=0; i
<num_domains
; i
++ ) {
4793 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4794 strequal(name
, dom_list
[i
].dns_name
) )
4796 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4799 d
= wcache_tdc_dup_domain(ctx
, &dom_list
[i
]);
4804 TALLOC_FREE( dom_list
);
4809 /*********************************************************************
4810 ********************************************************************/
4812 struct winbindd_tdc_domain
*
4813 wcache_tdc_fetch_domainbysid(TALLOC_CTX
*ctx
,
4814 const struct dom_sid
*sid
)
4816 struct winbindd_tdc_domain
*dom_list
= NULL
;
4817 size_t num_domains
= 0;
4819 struct winbindd_tdc_domain
*d
= NULL
;
4821 DEBUG(10,("wcache_tdc_fetch_domainbysid: Searching for domain %s\n",
4822 sid_string_dbg(sid
)));
4824 if (!init_wcache()) {
4828 /* fetch the list */
4830 wcache_tdc_fetch_list(&dom_list
, &num_domains
);
4832 for (i
= 0; i
<num_domains
; i
++) {
4833 if (dom_sid_equal(sid
, &(dom_list
[i
].sid
))) {
4834 DEBUG(10, ("wcache_tdc_fetch_domainbysid: "
4835 "Found domain %s for SID %s\n",
4836 dom_list
[i
].domain_name
,
4837 sid_string_dbg(sid
)));
4839 d
= wcache_tdc_dup_domain(ctx
, &dom_list
[i
]);
4844 TALLOC_FREE(dom_list
);
4850 /*********************************************************************
4851 ********************************************************************/
4853 void wcache_tdc_clear( void )
4855 if ( !init_wcache() )
4858 wcache_tdc_store_list( NULL
, 0 );
4864 /*********************************************************************
4865 ********************************************************************/
4867 static void wcache_save_user_pwinfo(struct winbindd_domain
*domain
,
4869 const struct dom_sid
*user_sid
,
4870 const char *homedir
,
4875 struct cache_entry
*centry
;
4878 if ( (centry
= centry_start(domain
, status
)) == NULL
)
4881 centry_put_string( centry
, homedir
);
4882 centry_put_string( centry
, shell
);
4883 centry_put_string( centry
, gecos
);
4884 centry_put_uint32( centry
, gid
);
4886 centry_end(centry
, "NSS/PWINFO/%s", sid_to_fstring(tmp
, user_sid
) );
4888 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid
) ));
4890 centry_free(centry
);
4895 NTSTATUS
nss_get_info_cached( struct winbindd_domain
*domain
,
4896 const struct dom_sid
*user_sid
,
4898 const char **homedir
, const char **shell
,
4899 const char **gecos
, gid_t
*p_gid
)
4901 struct winbind_cache
*cache
= get_cache(domain
);
4902 struct cache_entry
*centry
= NULL
;
4909 centry
= wcache_fetch(cache
, domain
, "NSS/PWINFO/%s",
4910 sid_to_fstring(tmp
, user_sid
));
4915 *homedir
= centry_string( centry
, ctx
);
4916 *shell
= centry_string( centry
, ctx
);
4917 *gecos
= centry_string( centry
, ctx
);
4918 *p_gid
= centry_uint32( centry
);
4920 centry_free(centry
);
4922 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4923 sid_string_dbg(user_sid
)));
4925 return NT_STATUS_OK
;
4929 nt_status
= nss_get_info( domain
->name
, user_sid
, ctx
,
4930 homedir
, shell
, gecos
, p_gid
);
4932 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status
)));
4934 if ( NT_STATUS_IS_OK(nt_status
) ) {
4935 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir
));
4936 DEBUGADD(10, ("\tshell = '%s'\n", *shell
));
4937 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos
));
4938 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid
));
4940 wcache_save_user_pwinfo( domain
, nt_status
, user_sid
,
4941 *homedir
, *shell
, *gecos
, *p_gid
);
4944 if ( NT_STATUS_EQUAL( nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
4945 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4947 set_domain_offline( domain
);
4955 /* the cache backend methods are exposed via this structure */
4956 struct winbindd_methods cache_methods
= {
4974 static bool wcache_ndr_key(TALLOC_CTX
*mem_ctx
, const char *domain_name
,
4975 uint32_t opnum
, const DATA_BLOB
*req
,
4981 key
= talloc_asprintf(mem_ctx
, "NDR/%s/%d/", domain_name
, (int)opnum
);
4985 keylen
= talloc_get_size(key
) - 1;
4987 key
= talloc_realloc(mem_ctx
, key
, char, keylen
+ req
->length
);
4991 memcpy(key
+ keylen
, req
->data
, req
->length
);
4993 pkey
->dptr
= (uint8_t *)key
;
4994 pkey
->dsize
= talloc_get_size(key
);
4998 static bool wcache_opnum_cacheable(uint32_t opnum
)
5001 case NDR_WBINT_PING
:
5002 case NDR_WBINT_QUERYSEQUENCENUMBER
:
5003 case NDR_WBINT_ALLOCATEUID
:
5004 case NDR_WBINT_ALLOCATEGID
:
5005 case NDR_WBINT_CHECKMACHINEACCOUNT
:
5006 case NDR_WBINT_CHANGEMACHINEACCOUNT
:
5007 case NDR_WBINT_PINGDC
:
5013 bool wcache_fetch_ndr(TALLOC_CTX
*mem_ctx
, struct winbindd_domain
*domain
,
5014 uint32_t opnum
, const DATA_BLOB
*req
, DATA_BLOB
*resp
)
5019 if (!wcache_opnum_cacheable(opnum
) ||
5020 is_my_own_sam_domain(domain
) ||
5021 is_builtin_domain(domain
)) {
5025 if (wcache
->tdb
== NULL
) {
5029 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
5032 data
= tdb_fetch(wcache
->tdb
, key
);
5033 TALLOC_FREE(key
.dptr
);
5035 if (data
.dptr
== NULL
) {
5038 if (data
.dsize
< 12) {
5042 if (!is_domain_offline(domain
)) {
5043 uint32_t entry_seqnum
, dom_seqnum
, last_check
;
5044 uint64_t entry_timeout
;
5046 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
,
5050 entry_seqnum
= IVAL(data
.dptr
, 0);
5051 if (entry_seqnum
!= dom_seqnum
) {
5052 DEBUG(10, ("Entry has wrong sequence number: %d\n",
5053 (int)entry_seqnum
));
5056 entry_timeout
= BVAL(data
.dptr
, 4);
5057 if (time(NULL
) > entry_timeout
) {
5058 DEBUG(10, ("Entry has timed out\n"));
5063 resp
->data
= (uint8_t *)talloc_memdup(mem_ctx
, data
.dptr
+ 12,
5065 if (resp
->data
== NULL
) {
5066 DEBUG(10, ("talloc failed\n"));
5069 resp
->length
= data
.dsize
- 12;
5073 SAFE_FREE(data
.dptr
);
5077 void wcache_store_ndr(struct winbindd_domain
*domain
, uint32_t opnum
,
5078 const DATA_BLOB
*req
, const DATA_BLOB
*resp
)
5081 uint32_t dom_seqnum
, last_check
;
5084 if (!wcache_opnum_cacheable(opnum
) ||
5085 is_my_own_sam_domain(domain
) ||
5086 is_builtin_domain(domain
)) {
5090 if (wcache
->tdb
== NULL
) {
5094 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
, &last_check
)) {
5095 DEBUG(10, ("could not fetch seqnum for domain %s\n",
5100 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
5104 timeout
= time(NULL
) + lp_winbind_cache_time();
5106 data
.dsize
= resp
->length
+ 12;
5107 data
.dptr
= talloc_array(key
.dptr
, uint8_t, data
.dsize
);
5108 if (data
.dptr
== NULL
) {
5112 SIVAL(data
.dptr
, 0, dom_seqnum
);
5113 SBVAL(data
.dptr
, 4, timeout
);
5114 memcpy(data
.dptr
+ 12, resp
->data
, resp
->length
);
5116 tdb_store(wcache
->tdb
, key
, data
, 0);
5119 TALLOC_FREE(key
.dptr
);