2 Unix SMB/CIFS implementation.
4 Winbind cache backend functions
6 Copyright (C) Andrew Tridgell 2001
7 Copyright (C) Gerald Carter 2003-2007
8 Copyright (C) Volker Lendecke 2005
9 Copyright (C) Guenther Deschner 2005
10 Copyright (C) Michael Adam 2007
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include "system/filesys.h"
29 #include "tdb_validate.h"
30 #include "../libcli/auth/libcli_auth.h"
31 #include "../librpc/gen_ndr/ndr_wbint.h"
34 #include "../libcli/security/security.h"
35 #include "passdb/machine_sid.h"
39 #define DBGC_CLASS DBGC_WINBIND
41 #define WINBINDD_CACHE_VERSION 2
42 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
44 extern struct winbindd_methods reconnect_methods
;
46 extern struct winbindd_methods ads_methods
;
48 extern struct winbindd_methods builtin_passdb_methods
;
49 extern struct winbindd_methods sam_passdb_methods
;
52 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
53 * Here are the list of entry types that are *not* stored
54 * as form struct cache_entry in the cache.
57 static const char *non_centry_keys
[] = {
62 WINBINDD_CACHE_VERSION_KEYSTR
,
66 /************************************************************************
67 Is this key a non-centry type ?
68 ************************************************************************/
70 static bool is_non_centry_key(TDB_DATA kbuf
)
74 if (kbuf
.dptr
== NULL
|| kbuf
.dsize
== 0) {
77 for (i
= 0; non_centry_keys
[i
] != NULL
; i
++) {
78 size_t namelen
= strlen(non_centry_keys
[i
]);
79 if (kbuf
.dsize
< namelen
) {
82 if (strncmp(non_centry_keys
[i
], (const char *)kbuf
.dptr
, namelen
) == 0) {
89 /* Global online/offline state - False when online. winbindd starts up online
90 and sets this to true if the first query fails and there's an entry in
91 the cache tdb telling us to stay offline. */
93 static bool global_winbindd_offline_state
;
95 struct winbind_cache
{
101 uint32 sequence_number
;
107 void (*smb_panic_fn
)(const char *const why
) = smb_panic
;
109 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
111 static struct winbind_cache
*wcache
;
113 /* get the winbind_cache structure */
114 static struct winbind_cache
*get_cache(struct winbindd_domain
*domain
)
116 struct winbind_cache
*ret
= wcache
;
118 /* We have to know what type of domain we are dealing with first. */
120 if (domain
->internal
) {
121 domain
->backend
= &builtin_passdb_methods
;
122 domain
->initialized
= True
;
125 if (strequal(domain
->name
, get_global_sam_name()) &&
126 sid_check_is_domain(&domain
->sid
)) {
127 domain
->backend
= &sam_passdb_methods
;
128 domain
->initialized
= True
;
131 if ( !domain
->initialized
) {
132 init_dc_connection( domain
);
136 OK. listen up becasue I'm only going to say this once.
137 We have the following scenarios to consider
138 (a) trusted AD domains on a Samba DC,
139 (b) trusted AD domains and we are joined to a non-kerberos domain
140 (c) trusted AD domains and we are joined to a kerberos (AD) domain
142 For (a) we can always contact the trusted domain using krb5
143 since we have the domain trust account password
145 For (b) we can only use RPC since we have no way of
146 getting a krb5 ticket in our own domain
148 For (c) we can always use krb5 since we have a kerberos trust
153 if (!domain
->backend
) {
155 struct winbindd_domain
*our_domain
= domain
;
157 /* find our domain first so we can figure out if we
158 are joined to a kerberized domain */
160 if ( !domain
->primary
)
161 our_domain
= find_our_domain();
163 if ((our_domain
->active_directory
|| IS_DC
)
164 && domain
->active_directory
165 && !lp_winbind_rpc_only()) {
166 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain
->name
));
167 domain
->backend
= &ads_methods
;
169 #endif /* HAVE_ADS */
170 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain
->name
));
171 domain
->backend
= &reconnect_methods
;
174 #endif /* HAVE_ADS */
180 ret
= SMB_XMALLOC_P(struct winbind_cache
);
184 wcache_flush_cache();
190 free a centry structure
192 static void centry_free(struct cache_entry
*centry
)
196 SAFE_FREE(centry
->data
);
200 static bool centry_check_bytes(struct cache_entry
*centry
, size_t nbytes
)
202 if (centry
->len
- centry
->ofs
< nbytes
) {
203 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
204 (unsigned int)nbytes
,
205 centry
->len
- centry
->ofs
));
212 pull a uint64_t from a cache entry
214 static uint64_t centry_uint64_t(struct cache_entry
*centry
)
218 if (!centry_check_bytes(centry
, 8)) {
219 smb_panic_fn("centry_uint64_t");
221 ret
= BVAL(centry
->data
, centry
->ofs
);
227 pull a uint32 from a cache entry
229 static uint32
centry_uint32(struct cache_entry
*centry
)
233 if (!centry_check_bytes(centry
, 4)) {
234 smb_panic_fn("centry_uint32");
236 ret
= IVAL(centry
->data
, centry
->ofs
);
242 pull a uint16 from a cache entry
244 static uint16
centry_uint16(struct cache_entry
*centry
)
247 if (!centry_check_bytes(centry
, 2)) {
248 smb_panic_fn("centry_uint16");
250 ret
= SVAL(centry
->data
, centry
->ofs
);
256 pull a uint8 from a cache entry
258 static uint8
centry_uint8(struct cache_entry
*centry
)
261 if (!centry_check_bytes(centry
, 1)) {
262 smb_panic_fn("centry_uint8");
264 ret
= CVAL(centry
->data
, centry
->ofs
);
270 pull a NTTIME from a cache entry
272 static NTTIME
centry_nttime(struct cache_entry
*centry
)
275 if (!centry_check_bytes(centry
, 8)) {
276 smb_panic_fn("centry_nttime");
278 ret
= IVAL(centry
->data
, centry
->ofs
);
280 ret
+= (uint64
)IVAL(centry
->data
, centry
->ofs
) << 32;
286 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
288 static time_t centry_time(struct cache_entry
*centry
)
290 return (time_t)centry_nttime(centry
);
293 /* pull a string from a cache entry, using the supplied
296 static char *centry_string(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
301 len
= centry_uint8(centry
);
304 /* a deliberate NULL string */
308 if (!centry_check_bytes(centry
, (size_t)len
)) {
309 smb_panic_fn("centry_string");
312 ret
= TALLOC_ARRAY(mem_ctx
, char, len
+1);
314 smb_panic_fn("centry_string out of memory\n");
316 memcpy(ret
,centry
->data
+ centry
->ofs
, len
);
322 /* pull a hash16 from a cache entry, using the supplied
325 static char *centry_hash16(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
330 len
= centry_uint8(centry
);
333 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
338 if (!centry_check_bytes(centry
, 16)) {
342 ret
= TALLOC_ARRAY(mem_ctx
, char, 16);
344 smb_panic_fn("centry_hash out of memory\n");
346 memcpy(ret
,centry
->data
+ centry
->ofs
, 16);
351 /* pull a sid from a cache entry, using the supplied
354 static bool centry_sid(struct cache_entry
*centry
, struct dom_sid
*sid
)
359 sid_string
= centry_string(centry
, talloc_tos());
360 if (sid_string
== NULL
) {
363 ret
= string_to_sid(sid
, sid_string
);
364 TALLOC_FREE(sid_string
);
370 pull a NTSTATUS from a cache entry
372 static NTSTATUS
centry_ntstatus(struct cache_entry
*centry
)
376 status
= NT_STATUS(centry_uint32(centry
));
381 /* the server is considered down if it can't give us a sequence number */
382 static bool wcache_server_down(struct winbindd_domain
*domain
)
389 ret
= (domain
->sequence_number
== DOM_SEQUENCE_NONE
);
392 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
397 static bool wcache_fetch_seqnum(const char *domain_name
, uint32_t *seqnum
,
398 uint32_t *last_seq_check
)
403 if (wcache
->tdb
== NULL
) {
404 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
408 key
= talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name
);
410 DEBUG(10, ("talloc failed\n"));
414 data
= tdb_fetch_bystring(wcache
->tdb
, key
);
417 if (data
.dptr
== NULL
) {
418 DEBUG(10, ("wcache_fetch_seqnum: %s not found\n",
422 if (data
.dsize
!= 8) {
423 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
425 SAFE_FREE(data
.dptr
);
429 *seqnum
= IVAL(data
.dptr
, 0);
430 *last_seq_check
= IVAL(data
.dptr
, 4);
431 SAFE_FREE(data
.dptr
);
436 static NTSTATUS
fetch_cache_seqnum( struct winbindd_domain
*domain
, time_t now
)
438 uint32 last_check
, time_diff
;
440 if (!wcache_fetch_seqnum(domain
->name
, &domain
->sequence_number
,
442 return NT_STATUS_UNSUCCESSFUL
;
444 domain
->last_seq_check
= last_check
;
446 /* have we expired? */
448 time_diff
= now
- domain
->last_seq_check
;
449 if ( time_diff
> lp_winbind_cache_time() ) {
450 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
451 domain
->name
, domain
->sequence_number
,
452 (uint32
)domain
->last_seq_check
));
453 return NT_STATUS_UNSUCCESSFUL
;
456 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
457 domain
->name
, domain
->sequence_number
,
458 (uint32
)domain
->last_seq_check
));
463 bool wcache_store_seqnum(const char *domain_name
, uint32_t seqnum
,
464 time_t last_seq_check
)
470 if (wcache
->tdb
== NULL
) {
471 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
475 key_str
= talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name
);
476 if (key_str
== NULL
) {
477 DEBUG(10, ("talloc_asprintf failed\n"));
481 SIVAL(buf
, 0, seqnum
);
482 SIVAL(buf
, 4, last_seq_check
);
484 ret
= tdb_store_bystring(wcache
->tdb
, key_str
,
485 make_tdb_data(buf
, sizeof(buf
)), TDB_REPLACE
);
486 TALLOC_FREE(key_str
);
488 DEBUG(10, ("tdb_store_bystring failed: %s\n",
489 tdb_errorstr(wcache
->tdb
)));
490 TALLOC_FREE(key_str
);
494 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
495 domain_name
, seqnum
, (unsigned)last_seq_check
));
500 static bool store_cache_seqnum( struct winbindd_domain
*domain
)
502 return wcache_store_seqnum(domain
->name
, domain
->sequence_number
,
503 domain
->last_seq_check
);
507 refresh the domain sequence number. If force is true
508 then always refresh it, no matter how recently we fetched it
511 static void refresh_sequence_number(struct winbindd_domain
*domain
, bool force
)
515 time_t t
= time(NULL
);
516 unsigned cache_time
= lp_winbind_cache_time();
518 if (is_domain_offline(domain
)) {
524 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
525 /* trying to reconnect is expensive, don't do it too often */
526 if (domain
->sequence_number
== DOM_SEQUENCE_NONE
) {
531 time_diff
= t
- domain
->last_seq_check
;
533 /* see if we have to refetch the domain sequence number */
534 if (!force
&& (time_diff
< cache_time
) &&
535 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
536 NT_STATUS_IS_OK(domain
->last_status
)) {
537 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain
->name
));
541 /* try to get the sequence number from the tdb cache first */
542 /* this will update the timestamp as well */
544 status
= fetch_cache_seqnum( domain
, t
);
545 if (NT_STATUS_IS_OK(status
) &&
546 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
547 NT_STATUS_IS_OK(domain
->last_status
)) {
551 /* important! make sure that we know if this is a native
552 mode domain or not. And that we can contact it. */
554 if ( winbindd_can_contact_domain( domain
) ) {
555 status
= domain
->backend
->sequence_number(domain
,
556 &domain
->sequence_number
);
558 /* just use the current time */
559 status
= NT_STATUS_OK
;
560 domain
->sequence_number
= time(NULL
);
564 /* the above call could have set our domain->backend to NULL when
565 * coming from offline to online mode, make sure to reinitialize the
566 * backend - Guenther */
569 if (!NT_STATUS_IS_OK(status
)) {
570 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status
)));
571 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
574 domain
->last_status
= status
;
575 domain
->last_seq_check
= time(NULL
);
577 /* save the new sequence number in the cache */
578 store_cache_seqnum( domain
);
581 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
582 domain
->name
, domain
->sequence_number
));
588 decide if a cache entry has expired
590 static bool centry_expired(struct winbindd_domain
*domain
, const char *keystr
, struct cache_entry
*centry
)
592 /* If we've been told to be offline - stay in that state... */
593 if (lp_winbind_offline_logon() && global_winbindd_offline_state
) {
594 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
595 keystr
, domain
->name
));
599 /* when the domain is offline return the cached entry.
600 * This deals with transient offline states... */
602 if (!domain
->online
) {
603 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
604 keystr
, domain
->name
));
608 /* if the server is OK and our cache entry came from when it was down then
609 the entry is invalid */
610 if ((domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
611 (centry
->sequence_number
== DOM_SEQUENCE_NONE
)) {
612 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
613 keystr
, domain
->name
));
617 /* if the server is down or the cache entry is not older than the
618 current sequence number or it did not timeout then it is OK */
619 if (wcache_server_down(domain
)
620 || ((centry
->sequence_number
== domain
->sequence_number
)
621 && (centry
->timeout
> time(NULL
)))) {
622 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
623 keystr
, domain
->name
));
627 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
628 keystr
, domain
->name
));
634 static struct cache_entry
*wcache_fetch_raw(char *kstr
)
637 struct cache_entry
*centry
;
640 key
= string_tdb_data(kstr
);
641 data
= tdb_fetch(wcache
->tdb
, key
);
647 centry
= SMB_XMALLOC_P(struct cache_entry
);
648 centry
->data
= (unsigned char *)data
.dptr
;
649 centry
->len
= data
.dsize
;
652 if (centry
->len
< 16) {
653 /* huh? corrupt cache? */
654 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s "
655 "(len < 16)?\n", kstr
));
660 centry
->status
= centry_ntstatus(centry
);
661 centry
->sequence_number
= centry_uint32(centry
);
662 centry
->timeout
= centry_uint64_t(centry
);
667 static bool is_my_own_sam_domain(struct winbindd_domain
*domain
)
669 if (strequal(domain
->name
, get_global_sam_name()) &&
670 sid_check_is_domain(&domain
->sid
)) {
677 static bool is_builtin_domain(struct winbindd_domain
*domain
)
679 if (strequal(domain
->name
, "BUILTIN") &&
680 sid_check_is_builtin(&domain
->sid
)) {
688 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
689 number and return status
691 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
692 struct winbindd_domain
*domain
,
693 const char *format
, ...) PRINTF_ATTRIBUTE(3,4);
694 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
695 struct winbindd_domain
*domain
,
696 const char *format
, ...)
700 struct cache_entry
*centry
;
702 if (!winbindd_use_cache() ||
703 is_my_own_sam_domain(domain
) ||
704 is_builtin_domain(domain
)) {
708 refresh_sequence_number(domain
, false);
710 va_start(ap
, format
);
711 smb_xvasprintf(&kstr
, format
, ap
);
714 centry
= wcache_fetch_raw(kstr
);
715 if (centry
== NULL
) {
720 if (centry_expired(domain
, kstr
, centry
)) {
722 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
723 kstr
, domain
->name
));
730 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
731 kstr
, domain
->name
));
737 static void wcache_delete(const char *format
, ...) PRINTF_ATTRIBUTE(1,2);
738 static void wcache_delete(const char *format
, ...)
744 va_start(ap
, format
);
745 smb_xvasprintf(&kstr
, format
, ap
);
748 key
= string_tdb_data(kstr
);
750 tdb_delete(wcache
->tdb
, key
);
755 make sure we have at least len bytes available in a centry
757 static void centry_expand(struct cache_entry
*centry
, uint32 len
)
759 if (centry
->len
- centry
->ofs
>= len
)
762 centry
->data
= SMB_REALLOC_ARRAY(centry
->data
, unsigned char,
765 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry
->len
));
766 smb_panic_fn("out of memory in centry_expand");
771 push a uint64_t into a centry
773 static void centry_put_uint64_t(struct cache_entry
*centry
, uint64_t v
)
775 centry_expand(centry
, 8);
776 SBVAL(centry
->data
, centry
->ofs
, v
);
781 push a uint32 into a centry
783 static void centry_put_uint32(struct cache_entry
*centry
, uint32 v
)
785 centry_expand(centry
, 4);
786 SIVAL(centry
->data
, centry
->ofs
, v
);
791 push a uint16 into a centry
793 static void centry_put_uint16(struct cache_entry
*centry
, uint16 v
)
795 centry_expand(centry
, 2);
796 SSVAL(centry
->data
, centry
->ofs
, v
);
801 push a uint8 into a centry
803 static void centry_put_uint8(struct cache_entry
*centry
, uint8 v
)
805 centry_expand(centry
, 1);
806 SCVAL(centry
->data
, centry
->ofs
, v
);
811 push a string into a centry
813 static void centry_put_string(struct cache_entry
*centry
, const char *s
)
818 /* null strings are marked as len 0xFFFF */
819 centry_put_uint8(centry
, 0xFF);
824 /* can't handle more than 254 char strings. Truncating is probably best */
826 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len
));
829 centry_put_uint8(centry
, len
);
830 centry_expand(centry
, len
);
831 memcpy(centry
->data
+ centry
->ofs
, s
, len
);
836 push a 16 byte hash into a centry - treat as 16 byte string.
838 static void centry_put_hash16(struct cache_entry
*centry
, const uint8 val
[16])
840 centry_put_uint8(centry
, 16);
841 centry_expand(centry
, 16);
842 memcpy(centry
->data
+ centry
->ofs
, val
, 16);
846 static void centry_put_sid(struct cache_entry
*centry
, const struct dom_sid
*sid
)
849 centry_put_string(centry
, sid_to_fstring(sid_string
, sid
));
854 put NTSTATUS into a centry
856 static void centry_put_ntstatus(struct cache_entry
*centry
, NTSTATUS status
)
858 uint32 status_value
= NT_STATUS_V(status
);
859 centry_put_uint32(centry
, status_value
);
864 push a NTTIME into a centry
866 static void centry_put_nttime(struct cache_entry
*centry
, NTTIME nt
)
868 centry_expand(centry
, 8);
869 SIVAL(centry
->data
, centry
->ofs
, nt
& 0xFFFFFFFF);
871 SIVAL(centry
->data
, centry
->ofs
, nt
>> 32);
876 push a time_t into a centry - use a 64 bit size.
877 NTTIME here is being used as a convenient 64-bit size.
879 static void centry_put_time(struct cache_entry
*centry
, time_t t
)
881 NTTIME nt
= (NTTIME
)t
;
882 centry_put_nttime(centry
, nt
);
886 start a centry for output. When finished, call centry_end()
888 struct cache_entry
*centry_start(struct winbindd_domain
*domain
, NTSTATUS status
)
890 struct cache_entry
*centry
;
895 centry
= SMB_XMALLOC_P(struct cache_entry
);
897 centry
->len
= 8192; /* reasonable default */
898 centry
->data
= SMB_XMALLOC_ARRAY(uint8
, centry
->len
);
900 centry
->sequence_number
= domain
->sequence_number
;
901 centry
->timeout
= lp_winbind_cache_time() + time(NULL
);
902 centry_put_ntstatus(centry
, status
);
903 centry_put_uint32(centry
, centry
->sequence_number
);
904 centry_put_uint64_t(centry
, centry
->timeout
);
909 finish a centry and write it to the tdb
911 static void centry_end(struct cache_entry
*centry
, const char *format
, ...) PRINTF_ATTRIBUTE(2,3);
912 static void centry_end(struct cache_entry
*centry
, const char *format
, ...)
918 if (!winbindd_use_cache()) {
922 va_start(ap
, format
);
923 smb_xvasprintf(&kstr
, format
, ap
);
926 key
= string_tdb_data(kstr
);
927 data
.dptr
= centry
->data
;
928 data
.dsize
= centry
->ofs
;
930 tdb_store(wcache
->tdb
, key
, data
, TDB_REPLACE
);
934 static void wcache_save_name_to_sid(struct winbindd_domain
*domain
,
935 NTSTATUS status
, const char *domain_name
,
936 const char *name
, const struct dom_sid
*sid
,
937 enum lsa_SidType type
)
939 struct cache_entry
*centry
;
942 centry
= centry_start(domain
, status
);
945 centry_put_uint32(centry
, type
);
946 centry_put_sid(centry
, sid
);
947 fstrcpy(uname
, name
);
949 centry_end(centry
, "NS/%s/%s", domain_name
, uname
);
950 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name
,
951 uname
, sid_string_dbg(sid
), nt_errstr(status
)));
955 static void wcache_save_sid_to_name(struct winbindd_domain
*domain
, NTSTATUS status
,
956 const struct dom_sid
*sid
, const char *domain_name
, const char *name
, enum lsa_SidType type
)
958 struct cache_entry
*centry
;
961 centry
= centry_start(domain
, status
);
965 if (NT_STATUS_IS_OK(status
)) {
966 centry_put_uint32(centry
, type
);
967 centry_put_string(centry
, domain_name
);
968 centry_put_string(centry
, name
);
971 centry_end(centry
, "SN/%s", sid_to_fstring(sid_string
, sid
));
972 DEBUG(10,("wcache_save_sid_to_name: %s -> %s (%s)\n", sid_string
,
973 name
, nt_errstr(status
)));
978 static void wcache_save_user(struct winbindd_domain
*domain
, NTSTATUS status
,
979 struct wbint_userinfo
*info
)
981 struct cache_entry
*centry
;
984 if (is_null_sid(&info
->user_sid
)) {
988 centry
= centry_start(domain
, status
);
991 centry_put_string(centry
, info
->acct_name
);
992 centry_put_string(centry
, info
->full_name
);
993 centry_put_string(centry
, info
->homedir
);
994 centry_put_string(centry
, info
->shell
);
995 centry_put_uint32(centry
, info
->primary_gid
);
996 centry_put_sid(centry
, &info
->user_sid
);
997 centry_put_sid(centry
, &info
->group_sid
);
998 centry_end(centry
, "U/%s", sid_to_fstring(sid_string
,
1000 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string
, info
->acct_name
));
1001 centry_free(centry
);
1004 static void wcache_save_lockout_policy(struct winbindd_domain
*domain
,
1006 struct samr_DomInfo12
*lockout_policy
)
1008 struct cache_entry
*centry
;
1010 centry
= centry_start(domain
, status
);
1014 centry_put_nttime(centry
, lockout_policy
->lockout_duration
);
1015 centry_put_nttime(centry
, lockout_policy
->lockout_window
);
1016 centry_put_uint16(centry
, lockout_policy
->lockout_threshold
);
1018 centry_end(centry
, "LOC_POL/%s", domain
->name
);
1020 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain
->name
));
1022 centry_free(centry
);
1027 static void wcache_save_password_policy(struct winbindd_domain
*domain
,
1029 struct samr_DomInfo1
*policy
)
1031 struct cache_entry
*centry
;
1033 centry
= centry_start(domain
, status
);
1037 centry_put_uint16(centry
, policy
->min_password_length
);
1038 centry_put_uint16(centry
, policy
->password_history_length
);
1039 centry_put_uint32(centry
, policy
->password_properties
);
1040 centry_put_nttime(centry
, policy
->max_password_age
);
1041 centry_put_nttime(centry
, policy
->min_password_age
);
1043 centry_end(centry
, "PWD_POL/%s", domain
->name
);
1045 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
1047 centry_free(centry
);
1050 /***************************************************************************
1051 ***************************************************************************/
1053 static void wcache_save_username_alias(struct winbindd_domain
*domain
,
1055 const char *name
, const char *alias
)
1057 struct cache_entry
*centry
;
1060 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1063 centry_put_string( centry
, alias
);
1065 fstrcpy(uname
, name
);
1067 centry_end(centry
, "NSS/NA/%s", uname
);
1069 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name
, alias
));
1071 centry_free(centry
);
1074 static void wcache_save_alias_username(struct winbindd_domain
*domain
,
1076 const char *alias
, const char *name
)
1078 struct cache_entry
*centry
;
1081 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1084 centry_put_string( centry
, name
);
1086 fstrcpy(uname
, alias
);
1088 centry_end(centry
, "NSS/AN/%s", uname
);
1090 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias
, name
));
1092 centry_free(centry
);
1095 /***************************************************************************
1096 ***************************************************************************/
1098 NTSTATUS
resolve_username_to_alias( TALLOC_CTX
*mem_ctx
,
1099 struct winbindd_domain
*domain
,
1100 const char *name
, char **alias
)
1102 struct winbind_cache
*cache
= get_cache(domain
);
1103 struct cache_entry
*centry
= NULL
;
1107 if ( domain
->internal
)
1108 return NT_STATUS_NOT_SUPPORTED
;
1113 if ( (upper_name
= SMB_STRDUP(name
)) == NULL
)
1114 return NT_STATUS_NO_MEMORY
;
1115 strupper_m(upper_name
);
1117 centry
= wcache_fetch(cache
, domain
, "NSS/NA/%s", upper_name
);
1119 SAFE_FREE( upper_name
);
1124 status
= centry
->status
;
1126 if (!NT_STATUS_IS_OK(status
)) {
1127 centry_free(centry
);
1131 *alias
= centry_string( centry
, mem_ctx
);
1133 centry_free(centry
);
1135 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1136 name
, *alias
? *alias
: "(none)"));
1138 return (*alias
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1142 /* If its not in cache and we are offline, then fail */
1144 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1145 DEBUG(8,("resolve_username_to_alias: rejecting query "
1146 "in offline mode\n"));
1147 return NT_STATUS_NOT_FOUND
;
1150 status
= nss_map_to_alias( mem_ctx
, domain
->name
, name
, alias
);
1152 if ( NT_STATUS_IS_OK( status
) ) {
1153 wcache_save_username_alias(domain
, status
, name
, *alias
);
1156 if ( NT_STATUS_EQUAL( status
, NT_STATUS_NONE_MAPPED
) ) {
1157 wcache_save_username_alias(domain
, status
, name
, "(NULL)");
1160 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1161 nt_errstr(status
)));
1163 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1164 set_domain_offline( domain
);
1170 /***************************************************************************
1171 ***************************************************************************/
1173 NTSTATUS
resolve_alias_to_username( TALLOC_CTX
*mem_ctx
,
1174 struct winbindd_domain
*domain
,
1175 const char *alias
, char **name
)
1177 struct winbind_cache
*cache
= get_cache(domain
);
1178 struct cache_entry
*centry
= NULL
;
1182 if ( domain
->internal
)
1183 return NT_STATUS_NOT_SUPPORTED
;
1188 if ( (upper_name
= SMB_STRDUP(alias
)) == NULL
)
1189 return NT_STATUS_NO_MEMORY
;
1190 strupper_m(upper_name
);
1192 centry
= wcache_fetch(cache
, domain
, "NSS/AN/%s", upper_name
);
1194 SAFE_FREE( upper_name
);
1199 status
= centry
->status
;
1201 if (!NT_STATUS_IS_OK(status
)) {
1202 centry_free(centry
);
1206 *name
= centry_string( centry
, mem_ctx
);
1208 centry_free(centry
);
1210 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1211 alias
, *name
? *name
: "(none)"));
1213 return (*name
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1217 /* If its not in cache and we are offline, then fail */
1219 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1220 DEBUG(8,("resolve_alias_to_username: rejecting query "
1221 "in offline mode\n"));
1222 return NT_STATUS_NOT_FOUND
;
1225 /* an alias cannot contain a domain prefix or '@' */
1227 if (strchr(alias
, '\\') || strchr(alias
, '@')) {
1228 DEBUG(10,("resolve_alias_to_username: skipping fully "
1229 "qualified name %s\n", alias
));
1230 return NT_STATUS_OBJECT_NAME_INVALID
;
1233 status
= nss_map_from_alias( mem_ctx
, domain
->name
, alias
, name
);
1235 if ( NT_STATUS_IS_OK( status
) ) {
1236 wcache_save_alias_username( domain
, status
, alias
, *name
);
1239 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1240 wcache_save_alias_username(domain
, status
, alias
, "(NULL)");
1243 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1244 nt_errstr(status
)));
1246 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1247 set_domain_offline( domain
);
1253 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
1255 struct winbind_cache
*cache
= get_cache(domain
);
1257 fstring key_str
, tmp
;
1261 return NT_STATUS_INTERNAL_DB_ERROR
;
1264 if (is_null_sid(sid
)) {
1265 return NT_STATUS_INVALID_SID
;
1268 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1269 return NT_STATUS_INVALID_SID
;
1272 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
1274 data
= tdb_fetch(cache
->tdb
, string_tdb_data(key_str
));
1276 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1279 SAFE_FREE(data
.dptr
);
1280 return NT_STATUS_OK
;
1283 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1284 as new salted ones. */
1286 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
1287 TALLOC_CTX
*mem_ctx
,
1288 const struct dom_sid
*sid
,
1289 const uint8
**cached_nt_pass
,
1290 const uint8
**cached_salt
)
1292 struct winbind_cache
*cache
= get_cache(domain
);
1293 struct cache_entry
*centry
= NULL
;
1300 return NT_STATUS_INTERNAL_DB_ERROR
;
1303 if (is_null_sid(sid
)) {
1304 return NT_STATUS_INVALID_SID
;
1307 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1308 return NT_STATUS_INVALID_SID
;
1311 /* Try and get a salted cred first. If we can't
1312 fall back to an unsalted cred. */
1314 centry
= wcache_fetch(cache
, domain
, "CRED/%s",
1315 sid_to_fstring(tmp
, sid
));
1317 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1318 sid_string_dbg(sid
)));
1319 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1322 t
= centry_time(centry
);
1324 /* In the salted case this isn't actually the nt_hash itself,
1325 but the MD5 of the salt + nt_hash. Let the caller
1326 sort this out. It can tell as we only return the cached_salt
1327 if we are returning a salted cred. */
1329 *cached_nt_pass
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1330 if (*cached_nt_pass
== NULL
) {
1333 sid_to_fstring(sidstr
, sid
);
1335 /* Bad (old) cred cache. Delete and pretend we
1337 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1339 wcache_delete("CRED/%s", sidstr
);
1340 centry_free(centry
);
1341 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1344 /* We only have 17 bytes more data in the salted cred case. */
1345 if (centry
->len
- centry
->ofs
== 17) {
1346 *cached_salt
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1348 *cached_salt
= NULL
;
1351 dump_data_pw("cached_nt_pass", *cached_nt_pass
, NT_HASH_LEN
);
1353 dump_data_pw("cached_salt", *cached_salt
, NT_HASH_LEN
);
1356 status
= centry
->status
;
1358 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1359 sid_string_dbg(sid
), nt_errstr(status
) ));
1361 centry_free(centry
);
1365 /* Store creds for a SID - only writes out new salted ones. */
1367 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1368 const struct dom_sid
*sid
,
1369 const uint8 nt_pass
[NT_HASH_LEN
])
1371 struct cache_entry
*centry
;
1374 uint8 cred_salt
[NT_HASH_LEN
];
1375 uint8 salted_hash
[NT_HASH_LEN
];
1377 if (is_null_sid(sid
)) {
1378 return NT_STATUS_INVALID_SID
;
1381 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1382 return NT_STATUS_INVALID_SID
;
1385 centry
= centry_start(domain
, NT_STATUS_OK
);
1387 return NT_STATUS_INTERNAL_DB_ERROR
;
1390 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1392 centry_put_time(centry
, time(NULL
));
1394 /* Create a salt and then salt the hash. */
1395 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1396 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1398 centry_put_hash16(centry
, salted_hash
);
1399 centry_put_hash16(centry
, cred_salt
);
1400 centry_end(centry
, "CRED/%s", sid_to_fstring(sid_string
, sid
));
1402 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1404 centry_free(centry
);
1406 return NT_STATUS_OK
;
1410 /* Query display info. This is the basic user list fn */
1411 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
1412 TALLOC_CTX
*mem_ctx
,
1413 uint32
*num_entries
,
1414 struct wbint_userinfo
**info
)
1416 struct winbind_cache
*cache
= get_cache(domain
);
1417 struct cache_entry
*centry
= NULL
;
1419 unsigned int i
, retry
;
1420 bool old_status
= domain
->online
;
1425 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1430 *num_entries
= centry_uint32(centry
);
1432 if (*num_entries
== 0)
1435 (*info
) = TALLOC_ARRAY(mem_ctx
, struct wbint_userinfo
, *num_entries
);
1437 smb_panic_fn("query_user_list out of memory");
1439 for (i
=0; i
<(*num_entries
); i
++) {
1440 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
1441 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
1442 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
1443 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
1444 centry_sid(centry
, &(*info
)[i
].user_sid
);
1445 centry_sid(centry
, &(*info
)[i
].group_sid
);
1449 status
= centry
->status
;
1451 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1452 domain
->name
, nt_errstr(status
) ));
1454 centry_free(centry
);
1461 /* Return status value returned by seq number check */
1463 if (!NT_STATUS_IS_OK(domain
->last_status
))
1464 return domain
->last_status
;
1466 /* Put the query_user_list() in a retry loop. There appears to be
1467 * some bug either with Windows 2000 or Samba's handling of large
1468 * rpc replies. This manifests itself as sudden disconnection
1469 * at a random point in the enumeration of a large (60k) user list.
1470 * The retry loop simply tries the operation again. )-: It's not
1471 * pretty but an acceptable workaround until we work out what the
1472 * real problem is. */
1477 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1480 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
1481 if (!NT_STATUS_IS_OK(status
)) {
1482 DEBUG(3, ("query_user_list: returned 0x%08x, "
1483 "retrying\n", NT_STATUS_V(status
)));
1485 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1486 DEBUG(3, ("query_user_list: flushing "
1487 "connection cache\n"));
1488 invalidate_cm_connection(&domain
->conn
);
1490 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1491 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1492 if (!domain
->internal
&& old_status
) {
1493 set_domain_offline(domain
);
1495 /* store partial response. */
1496 if (*num_entries
> 0) {
1498 * humm, what about the status used for cache?
1499 * Should it be NT_STATUS_OK?
1504 * domain is offline now, and there is no user entries,
1505 * try to fetch from cache again.
1507 if (cache
->tdb
&& !domain
->online
&& !domain
->internal
&& old_status
) {
1508 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1509 /* partial response... */
1513 goto do_fetch_cache
;
1520 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1524 refresh_sequence_number(domain
, false);
1525 if (!NT_STATUS_IS_OK(status
)) {
1528 centry
= centry_start(domain
, status
);
1531 centry_put_uint32(centry
, *num_entries
);
1532 for (i
=0; i
<(*num_entries
); i
++) {
1533 centry_put_string(centry
, (*info
)[i
].acct_name
);
1534 centry_put_string(centry
, (*info
)[i
].full_name
);
1535 centry_put_string(centry
, (*info
)[i
].homedir
);
1536 centry_put_string(centry
, (*info
)[i
].shell
);
1537 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1538 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1539 if (domain
->backend
&& domain
->backend
->consistent
) {
1540 /* when the backend is consistent we can pre-prime some mappings */
1541 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1543 (*info
)[i
].acct_name
,
1544 &(*info
)[i
].user_sid
,
1546 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1547 &(*info
)[i
].user_sid
,
1549 (*info
)[i
].acct_name
,
1551 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1554 centry_end(centry
, "UL/%s", domain
->name
);
1555 centry_free(centry
);
1561 /* list all domain groups */
1562 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
1563 TALLOC_CTX
*mem_ctx
,
1564 uint32
*num_entries
,
1565 struct wb_acct_info
**info
)
1567 struct winbind_cache
*cache
= get_cache(domain
);
1568 struct cache_entry
*centry
= NULL
;
1573 old_status
= domain
->online
;
1577 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1582 *num_entries
= centry_uint32(centry
);
1584 if (*num_entries
== 0)
1587 (*info
) = TALLOC_ARRAY(mem_ctx
, struct wb_acct_info
, *num_entries
);
1589 smb_panic_fn("enum_dom_groups out of memory");
1591 for (i
=0; i
<(*num_entries
); i
++) {
1592 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1593 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1594 (*info
)[i
].rid
= centry_uint32(centry
);
1598 status
= centry
->status
;
1600 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1601 domain
->name
, nt_errstr(status
) ));
1603 centry_free(centry
);
1610 /* Return status value returned by seq number check */
1612 if (!NT_STATUS_IS_OK(domain
->last_status
))
1613 return domain
->last_status
;
1615 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1618 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1620 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1621 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1622 if (!domain
->internal
&& old_status
) {
1623 set_domain_offline(domain
);
1627 !domain
->internal
&&
1629 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1631 goto do_fetch_cache
;
1636 refresh_sequence_number(domain
, false);
1637 if (!NT_STATUS_IS_OK(status
)) {
1640 centry
= centry_start(domain
, status
);
1643 centry_put_uint32(centry
, *num_entries
);
1644 for (i
=0; i
<(*num_entries
); i
++) {
1645 centry_put_string(centry
, (*info
)[i
].acct_name
);
1646 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1647 centry_put_uint32(centry
, (*info
)[i
].rid
);
1649 centry_end(centry
, "GL/%s/domain", domain
->name
);
1650 centry_free(centry
);
1656 /* list all domain groups */
1657 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
1658 TALLOC_CTX
*mem_ctx
,
1659 uint32
*num_entries
,
1660 struct wb_acct_info
**info
)
1662 struct winbind_cache
*cache
= get_cache(domain
);
1663 struct cache_entry
*centry
= NULL
;
1668 old_status
= domain
->online
;
1672 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1677 *num_entries
= centry_uint32(centry
);
1679 if (*num_entries
== 0)
1682 (*info
) = TALLOC_ARRAY(mem_ctx
, struct wb_acct_info
, *num_entries
);
1684 smb_panic_fn("enum_dom_groups out of memory");
1686 for (i
=0; i
<(*num_entries
); i
++) {
1687 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1688 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1689 (*info
)[i
].rid
= centry_uint32(centry
);
1694 /* If we are returning cached data and the domain controller
1695 is down then we don't know whether the data is up to date
1696 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1699 if (wcache_server_down(domain
)) {
1700 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1701 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1703 status
= centry
->status
;
1705 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1706 domain
->name
, nt_errstr(status
) ));
1708 centry_free(centry
);
1715 /* Return status value returned by seq number check */
1717 if (!NT_STATUS_IS_OK(domain
->last_status
))
1718 return domain
->last_status
;
1720 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1723 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1725 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1726 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1727 if (!domain
->internal
&& old_status
) {
1728 set_domain_offline(domain
);
1731 !domain
->internal
&&
1734 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1736 goto do_fetch_cache
;
1741 refresh_sequence_number(domain
, false);
1742 if (!NT_STATUS_IS_OK(status
)) {
1745 centry
= centry_start(domain
, status
);
1748 centry_put_uint32(centry
, *num_entries
);
1749 for (i
=0; i
<(*num_entries
); i
++) {
1750 centry_put_string(centry
, (*info
)[i
].acct_name
);
1751 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1752 centry_put_uint32(centry
, (*info
)[i
].rid
);
1754 centry_end(centry
, "GL/%s/local", domain
->name
);
1755 centry_free(centry
);
1761 NTSTATUS
wcache_name_to_sid(struct winbindd_domain
*domain
,
1762 const char *domain_name
,
1764 struct dom_sid
*sid
,
1765 enum lsa_SidType
*type
)
1767 struct winbind_cache
*cache
= get_cache(domain
);
1768 struct cache_entry
*centry
;
1772 if (cache
->tdb
== NULL
) {
1773 return NT_STATUS_NOT_FOUND
;
1776 uname
= talloc_strdup_upper(talloc_tos(), name
);
1777 if (uname
== NULL
) {
1778 return NT_STATUS_NO_MEMORY
;
1781 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1783 if (centry
== NULL
) {
1784 return NT_STATUS_NOT_FOUND
;
1787 status
= centry
->status
;
1788 if (NT_STATUS_IS_OK(status
)) {
1789 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1790 centry_sid(centry
, sid
);
1793 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1794 "%s\n", domain
->name
, nt_errstr(status
) ));
1796 centry_free(centry
);
1800 /* convert a single name to a sid in a domain */
1801 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
1802 TALLOC_CTX
*mem_ctx
,
1803 const char *domain_name
,
1806 struct dom_sid
*sid
,
1807 enum lsa_SidType
*type
)
1812 old_status
= domain
->online
;
1814 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1815 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1821 /* If the seq number check indicated that there is a problem
1822 * with this DC, then return that status... except for
1823 * access_denied. This is special because the dc may be in
1824 * "restrict anonymous = 1" mode, in which case it will deny
1825 * most unauthenticated operations, but *will* allow the LSA
1826 * name-to-sid that we try as a fallback. */
1828 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1829 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1830 return domain
->last_status
;
1832 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1835 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
,
1836 name
, flags
, sid
, type
);
1838 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1839 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1840 if (!domain
->internal
&& old_status
) {
1841 set_domain_offline(domain
);
1843 if (!domain
->internal
&&
1846 NTSTATUS cache_status
;
1847 cache_status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1848 return cache_status
;
1852 refresh_sequence_number(domain
, false);
1854 if (domain
->online
&&
1855 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1856 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1858 /* Only save the reverse mapping if this was not a UPN */
1859 if (!strchr(name
, '@')) {
1860 strupper_m(CONST_DISCARD(char *,domain_name
));
1861 strlower_m(CONST_DISCARD(char *,name
));
1862 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1869 NTSTATUS
wcache_sid_to_name(struct winbindd_domain
*domain
,
1870 const struct dom_sid
*sid
,
1871 TALLOC_CTX
*mem_ctx
,
1874 enum lsa_SidType
*type
)
1876 struct winbind_cache
*cache
= get_cache(domain
);
1877 struct cache_entry
*centry
;
1881 if (cache
->tdb
== NULL
) {
1882 return NT_STATUS_NOT_FOUND
;
1885 sid_string
= sid_string_tos(sid
);
1886 if (sid_string
== NULL
) {
1887 return NT_STATUS_NO_MEMORY
;
1890 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_string
);
1891 TALLOC_FREE(sid_string
);
1892 if (centry
== NULL
) {
1893 return NT_STATUS_NOT_FOUND
;
1896 if (NT_STATUS_IS_OK(centry
->status
)) {
1897 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1898 *domain_name
= centry_string(centry
, mem_ctx
);
1899 *name
= centry_string(centry
, mem_ctx
);
1902 status
= centry
->status
;
1903 centry_free(centry
);
1905 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1906 "%s\n", domain
->name
, nt_errstr(status
) ));
1911 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1913 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1914 TALLOC_CTX
*mem_ctx
,
1915 const struct dom_sid
*sid
,
1918 enum lsa_SidType
*type
)
1923 old_status
= domain
->online
;
1924 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
1926 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1931 *domain_name
= NULL
;
1933 /* If the seq number check indicated that there is a problem
1934 * with this DC, then return that status... except for
1935 * access_denied. This is special because the dc may be in
1936 * "restrict anonymous = 1" mode, in which case it will deny
1937 * most unauthenticated operations, but *will* allow the LSA
1938 * sid-to-name that we try as a fallback. */
1940 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1941 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1942 return domain
->last_status
;
1944 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1947 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1949 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1950 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1951 if (!domain
->internal
&& old_status
) {
1952 set_domain_offline(domain
);
1954 if (!domain
->internal
&&
1957 NTSTATUS cache_status
;
1958 cache_status
= wcache_sid_to_name(domain
, sid
, mem_ctx
,
1959 domain_name
, name
, type
);
1960 return cache_status
;
1964 refresh_sequence_number(domain
, false);
1965 if (!NT_STATUS_IS_OK(status
)) {
1968 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
1970 /* We can't save the name to sid mapping here, as with sid history a
1971 * later name2sid would give the wrong sid. */
1976 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
1977 TALLOC_CTX
*mem_ctx
,
1978 const struct dom_sid
*domain_sid
,
1983 enum lsa_SidType
**types
)
1985 struct winbind_cache
*cache
= get_cache(domain
);
1987 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1992 old_status
= domain
->online
;
1993 *domain_name
= NULL
;
2001 if (num_rids
== 0) {
2002 return NT_STATUS_OK
;
2005 *names
= TALLOC_ARRAY(mem_ctx
, char *, num_rids
);
2006 *types
= TALLOC_ARRAY(mem_ctx
, enum lsa_SidType
, num_rids
);
2008 if ((*names
== NULL
) || (*types
== NULL
)) {
2009 result
= NT_STATUS_NO_MEMORY
;
2013 have_mapped
= have_unmapped
= false;
2015 for (i
=0; i
<num_rids
; i
++) {
2017 struct cache_entry
*centry
;
2020 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2021 result
= NT_STATUS_INTERNAL_ERROR
;
2025 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2026 sid_to_fstring(tmp
, &sid
));
2031 (*types
)[i
] = SID_NAME_UNKNOWN
;
2032 (*names
)[i
] = talloc_strdup(*names
, "");
2034 if (NT_STATUS_IS_OK(centry
->status
)) {
2037 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2039 dom
= centry_string(centry
, mem_ctx
);
2040 if (*domain_name
== NULL
) {
2046 (*names
)[i
] = centry_string(centry
, *names
);
2048 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)
2049 || NT_STATUS_EQUAL(centry
->status
, STATUS_SOME_UNMAPPED
)) {
2050 have_unmapped
= true;
2053 /* something's definitely wrong */
2054 result
= centry
->status
;
2058 centry_free(centry
);
2062 return NT_STATUS_NONE_MAPPED
;
2064 if (!have_unmapped
) {
2065 return NT_STATUS_OK
;
2067 return STATUS_SOME_UNMAPPED
;
2071 TALLOC_FREE(*names
);
2072 TALLOC_FREE(*types
);
2074 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
2075 rids
, num_rids
, domain_name
,
2078 if (NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
2079 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2080 if (!domain
->internal
&& old_status
) {
2081 set_domain_offline(domain
);
2084 !domain
->internal
&&
2087 have_mapped
= have_unmapped
= false;
2089 for (i
=0; i
<num_rids
; i
++) {
2091 struct cache_entry
*centry
;
2094 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2095 result
= NT_STATUS_INTERNAL_ERROR
;
2099 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2100 sid_to_fstring(tmp
, &sid
));
2102 (*types
)[i
] = SID_NAME_UNKNOWN
;
2103 (*names
)[i
] = talloc_strdup(*names
, "");
2107 (*types
)[i
] = SID_NAME_UNKNOWN
;
2108 (*names
)[i
] = talloc_strdup(*names
, "");
2110 if (NT_STATUS_IS_OK(centry
->status
)) {
2113 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2115 dom
= centry_string(centry
, mem_ctx
);
2116 if (*domain_name
== NULL
) {
2122 (*names
)[i
] = centry_string(centry
, *names
);
2124 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)) {
2125 have_unmapped
= true;
2128 /* something's definitely wrong */
2129 result
= centry
->status
;
2133 centry_free(centry
);
2137 return NT_STATUS_NONE_MAPPED
;
2139 if (!have_unmapped
) {
2140 return NT_STATUS_OK
;
2142 return STATUS_SOME_UNMAPPED
;
2146 None of the queried rids has been found so save all negative entries
2148 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
2149 for (i
= 0; i
< num_rids
; i
++) {
2151 const char *name
= "";
2152 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
2153 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
2155 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2156 return NT_STATUS_INTERNAL_ERROR
;
2159 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2167 Some or all of the queried rids have been found.
2169 if (!NT_STATUS_IS_OK(result
) &&
2170 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
2174 refresh_sequence_number(domain
, false);
2176 for (i
=0; i
<num_rids
; i
++) {
2180 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2181 result
= NT_STATUS_INTERNAL_ERROR
;
2185 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
2186 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
2188 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2189 (*names
)[i
], (*types
)[i
]);
2195 TALLOC_FREE(*names
);
2196 TALLOC_FREE(*types
);
2200 NTSTATUS
wcache_query_user(struct winbindd_domain
*domain
,
2201 TALLOC_CTX
*mem_ctx
,
2202 const struct dom_sid
*user_sid
,
2203 struct wbint_userinfo
*info
)
2205 struct winbind_cache
*cache
= get_cache(domain
);
2206 struct cache_entry
*centry
= NULL
;
2210 if (cache
->tdb
== NULL
) {
2211 return NT_STATUS_NOT_FOUND
;
2214 sid_string
= sid_string_tos(user_sid
);
2215 if (sid_string
== NULL
) {
2216 return NT_STATUS_NO_MEMORY
;
2219 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string
);
2220 TALLOC_FREE(sid_string
);
2221 if (centry
== NULL
) {
2222 return NT_STATUS_NOT_FOUND
;
2226 * If we have an access denied cache entry and a cached info3
2227 * in the samlogon cache then do a query. This will force the
2228 * rpc back end to return the info3 data.
2231 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
) &&
2232 netsamlogon_cache_have(user_sid
)) {
2233 DEBUG(10, ("query_user: cached access denied and have cached "
2235 domain
->last_status
= NT_STATUS_OK
;
2236 centry_free(centry
);
2237 return NT_STATUS_NOT_FOUND
;
2240 /* if status is not ok then this is a negative hit
2241 and the rest of the data doesn't matter */
2242 status
= centry
->status
;
2243 if (NT_STATUS_IS_OK(status
)) {
2244 info
->acct_name
= centry_string(centry
, mem_ctx
);
2245 info
->full_name
= centry_string(centry
, mem_ctx
);
2246 info
->homedir
= centry_string(centry
, mem_ctx
);
2247 info
->shell
= centry_string(centry
, mem_ctx
);
2248 info
->primary_gid
= centry_uint32(centry
);
2249 centry_sid(centry
, &info
->user_sid
);
2250 centry_sid(centry
, &info
->group_sid
);
2253 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2254 "%s\n", domain
->name
, nt_errstr(status
) ));
2256 centry_free(centry
);
2260 /* Lookup user information from a rid */
2261 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
2262 TALLOC_CTX
*mem_ctx
,
2263 const struct dom_sid
*user_sid
,
2264 struct wbint_userinfo
*info
)
2269 old_status
= domain
->online
;
2270 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2271 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2277 /* Return status value returned by seq number check */
2279 if (!NT_STATUS_IS_OK(domain
->last_status
))
2280 return domain
->last_status
;
2282 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2285 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
2287 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2288 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2289 if (!domain
->internal
&& old_status
) {
2290 set_domain_offline(domain
);
2292 if (!domain
->internal
&&
2295 NTSTATUS cache_status
;
2296 cache_status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2297 return cache_status
;
2301 refresh_sequence_number(domain
, false);
2302 if (!NT_STATUS_IS_OK(status
)) {
2305 wcache_save_user(domain
, status
, info
);
2310 NTSTATUS
wcache_lookup_usergroups(struct winbindd_domain
*domain
,
2311 TALLOC_CTX
*mem_ctx
,
2312 const struct dom_sid
*user_sid
,
2313 uint32_t *pnum_sids
,
2314 struct dom_sid
**psids
)
2316 struct winbind_cache
*cache
= get_cache(domain
);
2317 struct cache_entry
*centry
= NULL
;
2319 uint32_t i
, num_sids
;
2320 struct dom_sid
*sids
;
2323 if (cache
->tdb
== NULL
) {
2324 return NT_STATUS_NOT_FOUND
;
2327 centry
= wcache_fetch(cache
, domain
, "UG/%s",
2328 sid_to_fstring(sid_string
, user_sid
));
2329 if (centry
== NULL
) {
2330 return NT_STATUS_NOT_FOUND
;
2333 /* If we have an access denied cache entry and a cached info3 in the
2334 samlogon cache then do a query. This will force the rpc back end
2335 to return the info3 data. */
2337 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)
2338 && netsamlogon_cache_have(user_sid
)) {
2339 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2341 domain
->last_status
= NT_STATUS_OK
;
2342 centry_free(centry
);
2343 return NT_STATUS_NOT_FOUND
;
2346 num_sids
= centry_uint32(centry
);
2347 sids
= talloc_array(mem_ctx
, struct dom_sid
, num_sids
);
2349 centry_free(centry
);
2350 return NT_STATUS_NO_MEMORY
;
2353 for (i
=0; i
<num_sids
; i
++) {
2354 centry_sid(centry
, &sids
[i
]);
2357 status
= centry
->status
;
2359 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2360 "status: %s\n", domain
->name
, nt_errstr(status
)));
2362 centry_free(centry
);
2364 *pnum_sids
= num_sids
;
2369 /* Lookup groups a user is a member of. */
2370 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
2371 TALLOC_CTX
*mem_ctx
,
2372 const struct dom_sid
*user_sid
,
2373 uint32
*num_groups
, struct dom_sid
**user_gids
)
2375 struct cache_entry
*centry
= NULL
;
2381 old_status
= domain
->online
;
2382 status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2383 num_groups
, user_gids
);
2384 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2389 (*user_gids
) = NULL
;
2391 /* Return status value returned by seq number check */
2393 if (!NT_STATUS_IS_OK(domain
->last_status
))
2394 return domain
->last_status
;
2396 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2399 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
2401 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2402 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2403 if (!domain
->internal
&& old_status
) {
2404 set_domain_offline(domain
);
2406 if (!domain
->internal
&&
2409 NTSTATUS cache_status
;
2410 cache_status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2411 num_groups
, user_gids
);
2412 return cache_status
;
2415 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
2419 refresh_sequence_number(domain
, false);
2420 if (!NT_STATUS_IS_OK(status
)) {
2423 centry
= centry_start(domain
, status
);
2427 centry_put_uint32(centry
, *num_groups
);
2428 for (i
=0; i
<(*num_groups
); i
++) {
2429 centry_put_sid(centry
, &(*user_gids
)[i
]);
2432 centry_end(centry
, "UG/%s", sid_to_fstring(sid_string
, user_sid
));
2433 centry_free(centry
);
2439 static char *wcache_make_sidlist(TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2440 const struct dom_sid
*sids
)
2445 sidlist
= talloc_strdup(mem_ctx
, "");
2446 if (sidlist
== NULL
) {
2449 for (i
=0; i
<num_sids
; i
++) {
2451 sidlist
= talloc_asprintf_append_buffer(
2452 sidlist
, "/%s", sid_to_fstring(tmp
, &sids
[i
]));
2453 if (sidlist
== NULL
) {
2460 NTSTATUS
wcache_lookup_useraliases(struct winbindd_domain
*domain
,
2461 TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2462 const struct dom_sid
*sids
,
2463 uint32_t *pnum_aliases
, uint32_t **paliases
)
2465 struct winbind_cache
*cache
= get_cache(domain
);
2466 struct cache_entry
*centry
= NULL
;
2467 uint32_t num_aliases
;
2473 if (cache
->tdb
== NULL
) {
2474 return NT_STATUS_NOT_FOUND
;
2477 if (num_sids
== 0) {
2480 return NT_STATUS_OK
;
2483 /* We need to cache indexed by the whole list of SIDs, the aliases
2484 * resulting might come from any of the SIDs. */
2486 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2487 if (sidlist
== NULL
) {
2488 return NT_STATUS_NO_MEMORY
;
2491 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2492 TALLOC_FREE(sidlist
);
2493 if (centry
== NULL
) {
2494 return NT_STATUS_NOT_FOUND
;
2497 num_aliases
= centry_uint32(centry
);
2498 aliases
= talloc_array(mem_ctx
, uint32_t, num_aliases
);
2499 if (aliases
== NULL
) {
2500 centry_free(centry
);
2501 return NT_STATUS_NO_MEMORY
;
2504 for (i
=0; i
<num_aliases
; i
++) {
2505 aliases
[i
] = centry_uint32(centry
);
2508 status
= centry
->status
;
2510 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2511 "status %s\n", domain
->name
, nt_errstr(status
)));
2513 centry_free(centry
);
2515 *pnum_aliases
= num_aliases
;
2516 *paliases
= aliases
;
2521 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
2522 TALLOC_CTX
*mem_ctx
,
2523 uint32 num_sids
, const struct dom_sid
*sids
,
2524 uint32
*num_aliases
, uint32
**alias_rids
)
2526 struct cache_entry
*centry
= NULL
;
2532 old_status
= domain
->online
;
2533 status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
2534 num_aliases
, alias_rids
);
2535 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2540 (*alias_rids
) = NULL
;
2542 if (!NT_STATUS_IS_OK(domain
->last_status
))
2543 return domain
->last_status
;
2545 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2546 "for domain %s\n", domain
->name
));
2548 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2549 if (sidlist
== NULL
) {
2550 return NT_STATUS_NO_MEMORY
;
2553 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2555 num_aliases
, alias_rids
);
2557 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2558 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2559 if (!domain
->internal
&& old_status
) {
2560 set_domain_offline(domain
);
2562 if (!domain
->internal
&&
2565 NTSTATUS cache_status
;
2566 cache_status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
,
2567 sids
, num_aliases
, alias_rids
);
2568 return cache_status
;
2572 refresh_sequence_number(domain
, false);
2573 if (!NT_STATUS_IS_OK(status
)) {
2576 centry
= centry_start(domain
, status
);
2579 centry_put_uint32(centry
, *num_aliases
);
2580 for (i
=0; i
<(*num_aliases
); i
++)
2581 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2582 centry_end(centry
, "UA%s", sidlist
);
2583 centry_free(centry
);
2589 NTSTATUS
wcache_lookup_groupmem(struct winbindd_domain
*domain
,
2590 TALLOC_CTX
*mem_ctx
,
2591 const struct dom_sid
*group_sid
,
2592 uint32_t *num_names
,
2593 struct dom_sid
**sid_mem
, char ***names
,
2594 uint32_t **name_types
)
2596 struct winbind_cache
*cache
= get_cache(domain
);
2597 struct cache_entry
*centry
= NULL
;
2602 if (cache
->tdb
== NULL
) {
2603 return NT_STATUS_NOT_FOUND
;
2606 sid_string
= sid_string_tos(group_sid
);
2607 if (sid_string
== NULL
) {
2608 return NT_STATUS_NO_MEMORY
;
2611 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_string
);
2612 TALLOC_FREE(sid_string
);
2613 if (centry
== NULL
) {
2614 return NT_STATUS_NOT_FOUND
;
2621 *num_names
= centry_uint32(centry
);
2622 if (*num_names
== 0) {
2623 centry_free(centry
);
2624 return NT_STATUS_OK
;
2627 *sid_mem
= talloc_array(mem_ctx
, struct dom_sid
, *num_names
);
2628 *names
= talloc_array(mem_ctx
, char *, *num_names
);
2629 *name_types
= talloc_array(mem_ctx
, uint32
, *num_names
);
2631 if ((*sid_mem
== NULL
) || (*names
== NULL
) || (*name_types
== NULL
)) {
2632 TALLOC_FREE(*sid_mem
);
2633 TALLOC_FREE(*names
);
2634 TALLOC_FREE(*name_types
);
2635 centry_free(centry
);
2636 return NT_STATUS_NO_MEMORY
;
2639 for (i
=0; i
<(*num_names
); i
++) {
2640 centry_sid(centry
, &(*sid_mem
)[i
]);
2641 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2642 (*name_types
)[i
] = centry_uint32(centry
);
2645 status
= centry
->status
;
2647 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2648 "status: %s\n", domain
->name
, nt_errstr(status
)));
2650 centry_free(centry
);
2654 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
2655 TALLOC_CTX
*mem_ctx
,
2656 const struct dom_sid
*group_sid
,
2657 enum lsa_SidType type
,
2659 struct dom_sid
**sid_mem
, char ***names
,
2660 uint32
**name_types
)
2662 struct cache_entry
*centry
= NULL
;
2668 old_status
= domain
->online
;
2669 status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2670 sid_mem
, names
, name_types
);
2671 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2678 (*name_types
) = NULL
;
2680 /* Return status value returned by seq number check */
2682 if (!NT_STATUS_IS_OK(domain
->last_status
))
2683 return domain
->last_status
;
2685 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2688 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
,
2690 sid_mem
, names
, name_types
);
2692 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2693 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2694 if (!domain
->internal
&& old_status
) {
2695 set_domain_offline(domain
);
2697 if (!domain
->internal
&&
2700 NTSTATUS cache_status
;
2701 cache_status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
,
2702 num_names
, sid_mem
, names
,
2704 return cache_status
;
2708 refresh_sequence_number(domain
, false);
2709 if (!NT_STATUS_IS_OK(status
)) {
2712 centry
= centry_start(domain
, status
);
2715 centry_put_uint32(centry
, *num_names
);
2716 for (i
=0; i
<(*num_names
); i
++) {
2717 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2718 centry_put_string(centry
, (*names
)[i
]);
2719 centry_put_uint32(centry
, (*name_types
)[i
]);
2721 centry_end(centry
, "GM/%s", sid_to_fstring(sid_string
, group_sid
));
2722 centry_free(centry
);
2728 /* find the sequence number for a domain */
2729 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
2731 refresh_sequence_number(domain
, false);
2733 *seq
= domain
->sequence_number
;
2735 return NT_STATUS_OK
;
2738 /* enumerate trusted domains
2739 * (we need to have the list of trustdoms in the cache when we go offline) -
2741 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
2742 TALLOC_CTX
*mem_ctx
,
2743 struct netr_DomainTrustList
*trusts
)
2746 struct winbind_cache
*cache
;
2747 struct winbindd_tdc_domain
*dom_list
= NULL
;
2748 size_t num_domains
= 0;
2749 bool retval
= false;
2753 old_status
= domain
->online
;
2755 trusts
->array
= NULL
;
2757 cache
= get_cache(domain
);
2758 if (!cache
|| !cache
->tdb
) {
2762 if (domain
->online
) {
2766 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2767 if (!retval
|| !num_domains
|| !dom_list
) {
2768 TALLOC_FREE(dom_list
);
2773 trusts
->array
= TALLOC_ZERO_ARRAY(mem_ctx
, struct netr_DomainTrust
, num_domains
);
2774 if (!trusts
->array
) {
2775 TALLOC_FREE(dom_list
);
2776 return NT_STATUS_NO_MEMORY
;
2779 for (i
= 0; i
< num_domains
; i
++) {
2780 struct netr_DomainTrust
*trust
;
2781 struct dom_sid
*sid
;
2782 struct winbindd_domain
*dom
;
2784 dom
= find_domain_from_name_noinit(dom_list
[i
].domain_name
);
2785 if (dom
&& dom
->internal
) {
2789 trust
= &trusts
->array
[trusts
->count
];
2790 trust
->netbios_name
= talloc_strdup(trusts
->array
, dom_list
[i
].domain_name
);
2791 trust
->dns_name
= talloc_strdup(trusts
->array
, dom_list
[i
].dns_name
);
2792 sid
= talloc(trusts
->array
, struct dom_sid
);
2793 if (!trust
->netbios_name
|| !trust
->dns_name
||
2795 TALLOC_FREE(dom_list
);
2796 TALLOC_FREE(trusts
->array
);
2797 return NT_STATUS_NO_MEMORY
;
2800 trust
->trust_flags
= dom_list
[i
].trust_flags
;
2801 trust
->trust_attributes
= dom_list
[i
].trust_attribs
;
2802 trust
->trust_type
= dom_list
[i
].trust_type
;
2803 sid_copy(sid
, &dom_list
[i
].sid
);
2808 TALLOC_FREE(dom_list
);
2809 return NT_STATUS_OK
;
2812 /* Return status value returned by seq number check */
2814 if (!NT_STATUS_IS_OK(domain
->last_status
))
2815 return domain
->last_status
;
2817 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2820 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, trusts
);
2822 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2823 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2824 if (!domain
->internal
&& old_status
) {
2825 set_domain_offline(domain
);
2827 if (!domain
->internal
&&
2830 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2831 if (retval
&& num_domains
&& dom_list
) {
2832 TALLOC_FREE(trusts
->array
);
2834 goto do_fetch_cache
;
2838 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2839 * so that the generic centry handling still applies correctly -
2842 if (!NT_STATUS_IS_ERR(status
)) {
2843 status
= NT_STATUS_OK
;
2848 /* get lockout policy */
2849 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
2850 TALLOC_CTX
*mem_ctx
,
2851 struct samr_DomInfo12
*policy
)
2853 struct winbind_cache
*cache
= get_cache(domain
);
2854 struct cache_entry
*centry
= NULL
;
2858 old_status
= domain
->online
;
2862 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2868 policy
->lockout_duration
= centry_nttime(centry
);
2869 policy
->lockout_window
= centry_nttime(centry
);
2870 policy
->lockout_threshold
= centry_uint16(centry
);
2872 status
= centry
->status
;
2874 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2875 domain
->name
, nt_errstr(status
) ));
2877 centry_free(centry
);
2881 ZERO_STRUCTP(policy
);
2883 /* Return status value returned by seq number check */
2885 if (!NT_STATUS_IS_OK(domain
->last_status
))
2886 return domain
->last_status
;
2888 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2891 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2893 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2894 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2895 if (!domain
->internal
&& old_status
) {
2896 set_domain_offline(domain
);
2899 !domain
->internal
&&
2902 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2904 goto do_fetch_cache
;
2909 refresh_sequence_number(domain
, false);
2910 if (!NT_STATUS_IS_OK(status
)) {
2913 wcache_save_lockout_policy(domain
, status
, policy
);
2918 /* get password policy */
2919 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
2920 TALLOC_CTX
*mem_ctx
,
2921 struct samr_DomInfo1
*policy
)
2923 struct winbind_cache
*cache
= get_cache(domain
);
2924 struct cache_entry
*centry
= NULL
;
2928 old_status
= domain
->online
;
2932 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2938 policy
->min_password_length
= centry_uint16(centry
);
2939 policy
->password_history_length
= centry_uint16(centry
);
2940 policy
->password_properties
= centry_uint32(centry
);
2941 policy
->max_password_age
= centry_nttime(centry
);
2942 policy
->min_password_age
= centry_nttime(centry
);
2944 status
= centry
->status
;
2946 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2947 domain
->name
, nt_errstr(status
) ));
2949 centry_free(centry
);
2953 ZERO_STRUCTP(policy
);
2955 /* Return status value returned by seq number check */
2957 if (!NT_STATUS_IS_OK(domain
->last_status
))
2958 return domain
->last_status
;
2960 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2963 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
2965 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2966 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2967 if (!domain
->internal
&& old_status
) {
2968 set_domain_offline(domain
);
2971 !domain
->internal
&&
2974 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2976 goto do_fetch_cache
;
2981 refresh_sequence_number(domain
, false);
2982 if (!NT_STATUS_IS_OK(status
)) {
2985 wcache_save_password_policy(domain
, status
, policy
);
2991 /* Invalidate cached user and group lists coherently */
2993 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2996 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
2997 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
2998 tdb_delete(the_tdb
, kbuf
);
3003 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
3005 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
3006 const struct dom_sid
*sid
)
3008 fstring key_str
, sid_string
;
3009 struct winbind_cache
*cache
;
3011 /* dont clear cached U/SID and UG/SID entries when we want to logon
3014 if (lp_winbind_offline_logon()) {
3021 cache
= get_cache(domain
);
3027 /* Clear U/SID cache entry */
3028 fstr_sprintf(key_str
, "U/%s", sid_to_fstring(sid_string
, sid
));
3029 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3030 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3032 /* Clear UG/SID cache entry */
3033 fstr_sprintf(key_str
, "UG/%s", sid_to_fstring(sid_string
, sid
));
3034 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3035 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3037 /* Samba/winbindd never needs this. */
3038 netsamlogon_clear_cached_user(sid
);
3041 bool wcache_invalidate_cache(void)
3043 struct winbindd_domain
*domain
;
3045 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3046 struct winbind_cache
*cache
= get_cache(domain
);
3048 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3049 "entries for %s\n", domain
->name
));
3052 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3061 bool wcache_invalidate_cache_noinit(void)
3063 struct winbindd_domain
*domain
;
3065 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3066 struct winbind_cache
*cache
;
3068 /* Skip uninitialized domains. */
3069 if (!domain
->initialized
&& !domain
->internal
) {
3073 cache
= get_cache(domain
);
3075 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3076 "entries for %s\n", domain
->name
));
3079 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3081 * Flushing cache has nothing to with domains.
3082 * return here if we successfully flushed once.
3083 * To avoid unnecessary traversing the cache.
3094 bool init_wcache(void)
3096 if (wcache
== NULL
) {
3097 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
3098 ZERO_STRUCTP(wcache
);
3101 if (wcache
->tdb
!= NULL
)
3104 /* when working offline we must not clear the cache on restart */
3105 wcache
->tdb
= tdb_open_log(cache_path("winbindd_cache.tdb"),
3106 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3107 TDB_INCOMPATIBLE_HASH
|
3108 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3109 O_RDWR
|O_CREAT
, 0600);
3111 if (wcache
->tdb
== NULL
) {
3112 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3119 /************************************************************************
3120 This is called by the parent to initialize the cache file.
3121 We don't need sophisticated locking here as we know we're the
3123 ************************************************************************/
3125 bool initialize_winbindd_cache(void)
3127 bool cache_bad
= true;
3130 if (!init_wcache()) {
3131 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3135 /* Check version number. */
3136 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
3137 vers
== WINBINDD_CACHE_VERSION
) {
3142 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3143 "and re-creating with version number %d\n",
3144 WINBINDD_CACHE_VERSION
));
3146 tdb_close(wcache
->tdb
);
3149 if (unlink(cache_path("winbindd_cache.tdb")) == -1) {
3150 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3151 cache_path("winbindd_cache.tdb"),
3155 if (!init_wcache()) {
3156 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3157 "init_wcache failed.\n"));
3161 /* Write the version. */
3162 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
3163 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3164 tdb_errorstr(wcache
->tdb
) ));
3169 tdb_close(wcache
->tdb
);
3174 void close_winbindd_cache(void)
3180 tdb_close(wcache
->tdb
);
3185 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*sid
,
3186 char **domain_name
, char **name
,
3187 enum lsa_SidType
*type
)
3189 struct winbindd_domain
*domain
;
3192 domain
= find_lookup_domain_from_sid(sid
);
3193 if (domain
== NULL
) {
3196 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
3198 return NT_STATUS_IS_OK(status
);
3201 bool lookup_cached_name(const char *domain_name
,
3203 struct dom_sid
*sid
,
3204 enum lsa_SidType
*type
)
3206 struct winbindd_domain
*domain
;
3208 bool original_online_state
;
3210 domain
= find_lookup_domain_from_name(domain_name
);
3211 if (domain
== NULL
) {
3215 /* If we are doing a cached logon, temporarily set the domain
3216 offline so the cache won't expire the entry */
3218 original_online_state
= domain
->online
;
3219 domain
->online
= false;
3220 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
3221 domain
->online
= original_online_state
;
3223 return NT_STATUS_IS_OK(status
);
3226 void cache_name2sid(struct winbindd_domain
*domain
,
3227 const char *domain_name
, const char *name
,
3228 enum lsa_SidType type
, const struct dom_sid
*sid
)
3230 refresh_sequence_number(domain
, false);
3231 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
3236 * The original idea that this cache only contains centries has
3237 * been blurred - now other stuff gets put in here. Ensure we
3238 * ignore these things on cleanup.
3241 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
3242 TDB_DATA dbuf
, void *state
)
3244 struct cache_entry
*centry
;
3246 if (is_non_centry_key(kbuf
)) {
3250 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
3255 if (!NT_STATUS_IS_OK(centry
->status
)) {
3256 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
3257 tdb_delete(the_tdb
, kbuf
);
3260 centry_free(centry
);
3264 /* flush the cache */
3265 void wcache_flush_cache(void)
3270 tdb_close(wcache
->tdb
);
3273 if (!winbindd_use_cache()) {
3277 /* when working offline we must not clear the cache on restart */
3278 wcache
->tdb
= tdb_open_log(cache_path("winbindd_cache.tdb"),
3279 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3280 TDB_INCOMPATIBLE_HASH
|
3281 (lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
)),
3282 O_RDWR
|O_CREAT
, 0600);
3285 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3289 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
3291 DEBUG(10,("wcache_flush_cache success\n"));
3294 /* Count cached creds */
3296 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3299 int *cred_count
= (int*)state
;
3301 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3307 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
3309 struct winbind_cache
*cache
= get_cache(domain
);
3314 return NT_STATUS_INTERNAL_DB_ERROR
;
3317 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
3319 return NT_STATUS_OK
;
3323 struct cred_list
*prev
, *next
;
3328 static struct cred_list
*wcache_cred_list
;
3330 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3333 struct cred_list
*cred
;
3335 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3337 cred
= SMB_MALLOC_P(struct cred_list
);
3339 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3345 /* save a copy of the key */
3347 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
3348 DLIST_ADD(wcache_cred_list
, cred
);
3354 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
3356 struct winbind_cache
*cache
= get_cache(domain
);
3359 struct cred_list
*cred
, *oldest
= NULL
;
3362 return NT_STATUS_INTERNAL_DB_ERROR
;
3365 /* we possibly already have an entry */
3366 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
3368 fstring key_str
, tmp
;
3370 DEBUG(11,("we already have an entry, deleting that\n"));
3372 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
3374 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3376 return NT_STATUS_OK
;
3379 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
3381 return NT_STATUS_OK
;
3382 } else if ((ret
== -1) || (wcache_cred_list
== NULL
)) {
3383 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3386 ZERO_STRUCTP(oldest
);
3388 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
3393 data
= tdb_fetch(cache
->tdb
, string_tdb_data(cred
->name
));
3395 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3397 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3401 t
= IVAL(data
.dptr
, 0);
3402 SAFE_FREE(data
.dptr
);
3405 oldest
= SMB_MALLOC_P(struct cred_list
);
3406 if (oldest
== NULL
) {
3407 status
= NT_STATUS_NO_MEMORY
;
3411 fstrcpy(oldest
->name
, cred
->name
);
3412 oldest
->created
= t
;
3416 if (t
< oldest
->created
) {
3417 fstrcpy(oldest
->name
, cred
->name
);
3418 oldest
->created
= t
;
3422 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3423 status
= NT_STATUS_OK
;
3425 status
= NT_STATUS_UNSUCCESSFUL
;
3428 SAFE_FREE(wcache_cred_list
);
3434 /* Change the global online/offline state. */
3435 bool set_global_winbindd_state_offline(void)
3439 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3441 /* Only go offline if someone has created
3442 the key "WINBINDD_OFFLINE" in the cache tdb. */
3444 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3445 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3449 if (!lp_winbind_offline_logon()) {
3450 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3454 if (global_winbindd_offline_state
) {
3455 /* Already offline. */
3459 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
3461 if (!data
.dptr
|| data
.dsize
!= 4) {
3462 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3463 SAFE_FREE(data
.dptr
);
3466 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3467 global_winbindd_offline_state
= true;
3468 SAFE_FREE(data
.dptr
);
3473 void set_global_winbindd_state_online(void)
3475 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3477 if (!lp_winbind_offline_logon()) {
3478 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3482 if (!global_winbindd_offline_state
) {
3483 /* Already online. */
3486 global_winbindd_offline_state
= false;
3492 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3493 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3496 bool get_global_winbindd_state_offline(void)
3498 return global_winbindd_offline_state
;
3501 /***********************************************************************
3502 Validate functions for all possible cache tdb keys.
3503 ***********************************************************************/
3505 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3506 struct tdb_validation_status
*state
)
3508 struct cache_entry
*centry
;
3510 centry
= SMB_XMALLOC_P(struct cache_entry
);
3511 centry
->data
= (unsigned char *)memdup(data
.dptr
, data
.dsize
);
3512 if (!centry
->data
) {
3516 centry
->len
= data
.dsize
;
3519 if (centry
->len
< 16) {
3520 /* huh? corrupt cache? */
3521 DEBUG(0,("create_centry_validate: Corrupt cache for key %s "
3522 "(len < 16) ?\n", kstr
));
3523 centry_free(centry
);
3524 state
->bad_entry
= true;
3525 state
->success
= false;
3529 centry
->status
= NT_STATUS(centry_uint32(centry
));
3530 centry
->sequence_number
= centry_uint32(centry
);
3531 centry
->timeout
= centry_uint64_t(centry
);
3535 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3536 struct tdb_validation_status
*state
)
3538 if (dbuf
.dsize
!= 8) {
3539 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3540 keystr
, (unsigned int)dbuf
.dsize
));
3541 state
->bad_entry
= true;
3547 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3548 struct tdb_validation_status
*state
)
3550 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3555 (void)centry_uint32(centry
);
3556 if (NT_STATUS_IS_OK(centry
->status
)) {
3558 (void)centry_sid(centry
, &sid
);
3561 centry_free(centry
);
3563 if (!(state
->success
)) {
3566 DEBUG(10,("validate_ns: %s ok\n", keystr
));
3570 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3571 struct tdb_validation_status
*state
)
3573 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3578 if (NT_STATUS_IS_OK(centry
->status
)) {
3579 (void)centry_uint32(centry
);
3580 (void)centry_string(centry
, mem_ctx
);
3581 (void)centry_string(centry
, mem_ctx
);
3584 centry_free(centry
);
3586 if (!(state
->success
)) {
3589 DEBUG(10,("validate_sn: %s ok\n", keystr
));
3593 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3594 struct tdb_validation_status
*state
)
3596 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3603 (void)centry_string(centry
, mem_ctx
);
3604 (void)centry_string(centry
, mem_ctx
);
3605 (void)centry_string(centry
, mem_ctx
);
3606 (void)centry_string(centry
, mem_ctx
);
3607 (void)centry_uint32(centry
);
3608 (void)centry_sid(centry
, &sid
);
3609 (void)centry_sid(centry
, &sid
);
3611 centry_free(centry
);
3613 if (!(state
->success
)) {
3616 DEBUG(10,("validate_u: %s ok\n", keystr
));
3620 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3621 struct tdb_validation_status
*state
)
3623 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3629 (void)centry_nttime(centry
);
3630 (void)centry_nttime(centry
);
3631 (void)centry_uint16(centry
);
3633 centry_free(centry
);
3635 if (!(state
->success
)) {
3638 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3642 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3643 struct tdb_validation_status
*state
)
3645 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3651 (void)centry_uint16(centry
);
3652 (void)centry_uint16(centry
);
3653 (void)centry_uint32(centry
);
3654 (void)centry_nttime(centry
);
3655 (void)centry_nttime(centry
);
3657 centry_free(centry
);
3659 if (!(state
->success
)) {
3662 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3666 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3667 struct tdb_validation_status
*state
)
3669 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3675 (void)centry_time(centry
);
3676 (void)centry_hash16(centry
, mem_ctx
);
3678 /* We only have 17 bytes more data in the salted cred case. */
3679 if (centry
->len
- centry
->ofs
== 17) {
3680 (void)centry_hash16(centry
, mem_ctx
);
3683 centry_free(centry
);
3685 if (!(state
->success
)) {
3688 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3692 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3693 struct tdb_validation_status
*state
)
3695 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3696 int32 num_entries
, i
;
3702 num_entries
= (int32
)centry_uint32(centry
);
3704 for (i
=0; i
< num_entries
; i
++) {
3706 (void)centry_string(centry
, mem_ctx
);
3707 (void)centry_string(centry
, mem_ctx
);
3708 (void)centry_string(centry
, mem_ctx
);
3709 (void)centry_string(centry
, mem_ctx
);
3710 (void)centry_sid(centry
, &sid
);
3711 (void)centry_sid(centry
, &sid
);
3714 centry_free(centry
);
3716 if (!(state
->success
)) {
3719 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3723 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3724 struct tdb_validation_status
*state
)
3726 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3727 int32 num_entries
, i
;
3733 num_entries
= centry_uint32(centry
);
3735 for (i
=0; i
< num_entries
; i
++) {
3736 (void)centry_string(centry
, mem_ctx
);
3737 (void)centry_string(centry
, mem_ctx
);
3738 (void)centry_uint32(centry
);
3741 centry_free(centry
);
3743 if (!(state
->success
)) {
3746 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3750 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3751 struct tdb_validation_status
*state
)
3753 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3754 int32 num_groups
, i
;
3760 num_groups
= centry_uint32(centry
);
3762 for (i
=0; i
< num_groups
; i
++) {
3764 centry_sid(centry
, &sid
);
3767 centry_free(centry
);
3769 if (!(state
->success
)) {
3772 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3776 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3777 struct tdb_validation_status
*state
)
3779 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3780 int32 num_aliases
, i
;
3786 num_aliases
= centry_uint32(centry
);
3788 for (i
=0; i
< num_aliases
; i
++) {
3789 (void)centry_uint32(centry
);
3792 centry_free(centry
);
3794 if (!(state
->success
)) {
3797 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3801 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3802 struct tdb_validation_status
*state
)
3804 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3811 num_names
= centry_uint32(centry
);
3813 for (i
=0; i
< num_names
; i
++) {
3815 centry_sid(centry
, &sid
);
3816 (void)centry_string(centry
, mem_ctx
);
3817 (void)centry_uint32(centry
);
3820 centry_free(centry
);
3822 if (!(state
->success
)) {
3825 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3829 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3830 struct tdb_validation_status
*state
)
3832 /* Can't say anything about this other than must be nonzero. */
3833 if (dbuf
.dsize
== 0) {
3834 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3836 state
->bad_entry
= true;
3837 state
->success
= false;
3841 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3845 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3846 struct tdb_validation_status
*state
)
3848 /* Can't say anything about this other than must be nonzero. */
3849 if (dbuf
.dsize
== 0) {
3850 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3852 state
->bad_entry
= true;
3853 state
->success
= false;
3857 DEBUG(10,("validate_de: %s ok\n", keystr
));
3861 static int validate_pwinfo(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3862 TDB_DATA dbuf
, struct tdb_validation_status
*state
)
3864 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3870 (void)centry_string(centry
, mem_ctx
);
3871 (void)centry_string(centry
, mem_ctx
);
3872 (void)centry_string(centry
, mem_ctx
);
3873 (void)centry_uint32(centry
);
3875 centry_free(centry
);
3877 if (!(state
->success
)) {
3880 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3884 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3886 struct tdb_validation_status
*state
)
3888 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3894 (void)centry_string( centry
, mem_ctx
);
3896 centry_free(centry
);
3898 if (!(state
->success
)) {
3901 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3905 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3907 struct tdb_validation_status
*state
)
3909 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3915 (void)centry_string( centry
, mem_ctx
);
3917 centry_free(centry
);
3919 if (!(state
->success
)) {
3922 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3926 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3928 struct tdb_validation_status
*state
)
3930 if (dbuf
.dsize
== 0) {
3931 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3932 "key %s (len ==0) ?\n", keystr
));
3933 state
->bad_entry
= true;
3934 state
->success
= false;
3938 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3939 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3943 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3944 struct tdb_validation_status
*state
)
3946 if (dbuf
.dsize
!= 4) {
3947 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3948 keystr
, (unsigned int)dbuf
.dsize
));
3949 state
->bad_entry
= true;
3950 state
->success
= false;
3953 DEBUG(10,("validate_offline: %s ok\n", keystr
));
3957 static int validate_ndr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3958 struct tdb_validation_status
*state
)
3961 * Ignore validation for now. The proper way to do this is with a
3962 * checksum. Just pure parsing does not really catch much.
3967 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3968 struct tdb_validation_status
*state
)
3970 if (dbuf
.dsize
!= 4) {
3971 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3972 "key %s (len %u != 4) ?\n",
3973 keystr
, (unsigned int)dbuf
.dsize
));
3974 state
->bad_entry
= true;
3975 state
->success
= false;
3979 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
3983 /***********************************************************************
3984 A list of all possible cache tdb keys with associated validation
3986 ***********************************************************************/
3988 struct key_val_struct
{
3989 const char *keyname
;
3990 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
3992 {"SEQNUM/", validate_seqnum
},
3993 {"NS/", validate_ns
},
3994 {"SN/", validate_sn
},
3996 {"LOC_POL/", validate_loc_pol
},
3997 {"PWD_POL/", validate_pwd_pol
},
3998 {"CRED/", validate_cred
},
3999 {"UL/", validate_ul
},
4000 {"GL/", validate_gl
},
4001 {"UG/", validate_ug
},
4002 {"UA", validate_ua
},
4003 {"GM/", validate_gm
},
4004 {"DR/", validate_dr
},
4005 {"DE/", validate_de
},
4006 {"NSS/PWINFO/", validate_pwinfo
},
4007 {"TRUSTDOMCACHE/", validate_trustdomcache
},
4008 {"NSS/NA/", validate_nss_na
},
4009 {"NSS/AN/", validate_nss_an
},
4010 {"WINBINDD_OFFLINE", validate_offline
},
4011 {"NDR/", validate_ndr
},
4012 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
4016 /***********************************************************************
4017 Function to look at every entry in the tdb and validate it as far as
4019 ***********************************************************************/
4021 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
4024 unsigned int max_key_len
= 1024;
4025 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
4027 /* Paranoia check. */
4028 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0) {
4029 max_key_len
= 1024 * 1024;
4031 if (kbuf
.dsize
> max_key_len
) {
4032 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
4034 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
4038 for (i
= 0; key_val
[i
].keyname
; i
++) {
4039 size_t namelen
= strlen(key_val
[i
].keyname
);
4040 if (kbuf
.dsize
>= namelen
&& (
4041 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
4042 TALLOC_CTX
*mem_ctx
;
4046 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
4050 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
4051 keystr
[kbuf
.dsize
] = '\0';
4053 mem_ctx
= talloc_init("validate_ctx");
4059 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
4063 talloc_destroy(mem_ctx
);
4068 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4069 dump_data(0, (uint8
*)kbuf
.dptr
, kbuf
.dsize
);
4070 DEBUG(0,("data :\n"));
4071 dump_data(0, (uint8
*)dbuf
.dptr
, dbuf
.dsize
);
4072 v_state
->unknown_key
= true;
4073 v_state
->success
= false;
4074 return 1; /* terminate. */
4077 static void validate_panic(const char *const why
)
4079 DEBUG(0,("validating cache: would panic %s\n", why
));
4080 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4084 /***********************************************************************
4085 Try and validate every entry in the winbindd cache. If we fail here,
4086 delete the cache tdb and return non-zero.
4087 ***********************************************************************/
4089 int winbindd_validate_cache(void)
4092 const char *tdb_path
= cache_path("winbindd_cache.tdb");
4093 TDB_CONTEXT
*tdb
= NULL
;
4095 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4096 smb_panic_fn
= validate_panic
;
4099 tdb
= tdb_open_log(tdb_path
,
4100 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
4101 TDB_INCOMPATIBLE_HASH
|
4102 ( lp_winbind_offline_logon()
4104 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
4108 DEBUG(0, ("winbindd_validate_cache: "
4109 "error opening/initializing tdb\n"));
4114 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
4117 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4118 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
4123 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4124 smb_panic_fn
= smb_panic
;
4128 /***********************************************************************
4129 Try and validate every entry in the winbindd cache.
4130 ***********************************************************************/
4132 int winbindd_validate_cache_nobackup(void)
4135 const char *tdb_path
= cache_path("winbindd_cache.tdb");
4137 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4138 smb_panic_fn
= validate_panic
;
4141 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
4142 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
4144 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
4148 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4152 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4154 smb_panic_fn
= smb_panic
;
4158 bool winbindd_cache_validate_and_initialize(void)
4160 close_winbindd_cache();
4162 if (lp_winbind_offline_logon()) {
4163 if (winbindd_validate_cache() < 0) {
4164 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4165 "could be restored.\n"));
4169 return initialize_winbindd_cache();
4172 /*********************************************************************
4173 ********************************************************************/
4175 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
4176 struct winbindd_tdc_domain
**domains
,
4177 size_t *num_domains
)
4179 struct winbindd_tdc_domain
*list
= NULL
;
4182 bool set_only
= false;
4184 /* don't allow duplicates */
4189 for ( i
=0; i
< (*num_domains
); i
++ ) {
4190 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
4191 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4202 list
= TALLOC_ARRAY( NULL
, struct winbindd_tdc_domain
, 1 );
4205 list
= TALLOC_REALLOC_ARRAY( *domains
, *domains
,
4206 struct winbindd_tdc_domain
,
4211 ZERO_STRUCT( list
[idx
] );
4217 list
[idx
].domain_name
= talloc_strdup( list
, new_dom
->name
);
4218 list
[idx
].dns_name
= talloc_strdup( list
, new_dom
->alt_name
);
4220 if ( !is_null_sid( &new_dom
->sid
) ) {
4221 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
4223 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
4226 if ( new_dom
->domain_flags
!= 0x0 )
4227 list
[idx
].trust_flags
= new_dom
->domain_flags
;
4229 if ( new_dom
->domain_type
!= 0x0 )
4230 list
[idx
].trust_type
= new_dom
->domain_type
;
4232 if ( new_dom
->domain_trust_attribs
!= 0x0 )
4233 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
4237 *num_domains
= idx
+ 1;
4243 /*********************************************************************
4244 ********************************************************************/
4246 static TDB_DATA
make_tdc_key( const char *domain_name
)
4248 char *keystr
= NULL
;
4249 TDB_DATA key
= { NULL
, 0 };
4251 if ( !domain_name
) {
4252 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4256 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
4259 key
= string_term_tdb_data(keystr
);
4264 /*********************************************************************
4265 ********************************************************************/
4267 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
4269 unsigned char **buf
)
4271 unsigned char *buffer
= NULL
;
4276 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4284 /* Store the number of array items first */
4285 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
4288 /* now pack each domain trust record */
4289 for ( i
=0; i
<num_domains
; i
++ ) {
4294 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4295 domains
[i
].domain_name
,
4296 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
4299 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
4300 domains
[i
].domain_name
,
4301 domains
[i
].dns_name
,
4302 sid_to_fstring(tmp
, &domains
[i
].sid
),
4303 domains
[i
].trust_flags
,
4304 domains
[i
].trust_attribs
,
4305 domains
[i
].trust_type
);
4308 if ( buflen
< len
) {
4310 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
4311 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4325 /*********************************************************************
4326 ********************************************************************/
4328 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
4329 struct winbindd_tdc_domain
**domains
)
4331 fstring domain_name
, dns_name
, sid_string
;
4332 uint32 type
, attribs
, flags
;
4336 struct winbindd_tdc_domain
*list
= NULL
;
4338 /* get the number of domains */
4339 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
4341 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4345 list
= TALLOC_ARRAY( NULL
, struct winbindd_tdc_domain
, num_domains
);
4347 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4351 for ( i
=0; i
<num_domains
; i
++ ) {
4352 len
+= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
4361 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4362 TALLOC_FREE( list
);
4366 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4367 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4368 domain_name
, dns_name
, sid_string
,
4369 flags
, attribs
, type
));
4371 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
4372 list
[i
].dns_name
= talloc_strdup( list
, dns_name
);
4373 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
4374 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4377 list
[i
].trust_flags
= flags
;
4378 list
[i
].trust_attribs
= attribs
;
4379 list
[i
].trust_type
= type
;
4387 /*********************************************************************
4388 ********************************************************************/
4390 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
4392 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4393 TDB_DATA data
= { NULL
, 0 };
4399 /* See if we were asked to delete the cache entry */
4402 ret
= tdb_delete( wcache
->tdb
, key
);
4406 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4413 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4416 SAFE_FREE( data
.dptr
);
4417 SAFE_FREE( key
.dptr
);
4419 return ( ret
!= -1 );
4422 /*********************************************************************
4423 ********************************************************************/
4425 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4427 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4428 TDB_DATA data
= { NULL
, 0 };
4436 data
= tdb_fetch( wcache
->tdb
, key
);
4438 SAFE_FREE( key
.dptr
);
4443 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4445 SAFE_FREE( data
.dptr
);
4453 /*********************************************************************
4454 ********************************************************************/
4456 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4458 struct winbindd_tdc_domain
*dom_list
= NULL
;
4459 size_t num_domains
= 0;
4462 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4463 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4464 domain
->name
, domain
->alt_name
,
4465 sid_string_dbg(&domain
->sid
),
4466 domain
->domain_flags
,
4467 domain
->domain_trust_attribs
,
4468 domain
->domain_type
));
4470 if ( !init_wcache() ) {
4474 /* fetch the list */
4476 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4478 /* add the new domain */
4480 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4484 /* pack the domain */
4486 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4494 TALLOC_FREE( dom_list
);
4499 /*********************************************************************
4500 ********************************************************************/
4502 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4504 struct winbindd_tdc_domain
*dom_list
= NULL
;
4505 size_t num_domains
= 0;
4507 struct winbindd_tdc_domain
*d
= NULL
;
4509 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4511 if ( !init_wcache() ) {
4515 /* fetch the list */
4517 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4519 for ( i
=0; i
<num_domains
; i
++ ) {
4520 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4521 strequal(name
, dom_list
[i
].dns_name
) )
4523 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4526 d
= TALLOC_P( ctx
, struct winbindd_tdc_domain
);
4530 d
->domain_name
= talloc_strdup( d
, dom_list
[i
].domain_name
);
4531 d
->dns_name
= talloc_strdup( d
, dom_list
[i
].dns_name
);
4532 sid_copy( &d
->sid
, &dom_list
[i
].sid
);
4533 d
->trust_flags
= dom_list
[i
].trust_flags
;
4534 d
->trust_type
= dom_list
[i
].trust_type
;
4535 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
4541 TALLOC_FREE( dom_list
);
4546 /*********************************************************************
4547 ********************************************************************/
4549 struct winbindd_tdc_domain
*
4550 wcache_tdc_fetch_domainbysid(TALLOC_CTX
*ctx
,
4551 const struct dom_sid
*sid
)
4553 struct winbindd_tdc_domain
*dom_list
= NULL
;
4554 size_t num_domains
= 0;
4556 struct winbindd_tdc_domain
*d
= NULL
;
4558 DEBUG(10,("wcache_tdc_fetch_domainbysid: Searching for domain %s\n",
4559 sid_string_dbg(sid
)));
4561 if (!init_wcache()) {
4565 /* fetch the list */
4567 wcache_tdc_fetch_list(&dom_list
, &num_domains
);
4569 for (i
= 0; i
<num_domains
; i
++) {
4570 if (sid_equal(sid
, &(dom_list
[i
].sid
))) {
4571 DEBUG(10, ("wcache_tdc_fetch_domainbysid: "
4572 "Found domain %s for SID %s\n",
4573 dom_list
[i
].domain_name
,
4574 sid_string_dbg(sid
)));
4576 d
= TALLOC_P(ctx
, struct winbindd_tdc_domain
);
4580 d
->domain_name
= talloc_strdup(d
,
4581 dom_list
[i
].domain_name
);
4583 d
->dns_name
= talloc_strdup(d
, dom_list
[i
].dns_name
);
4584 sid_copy(&d
->sid
, &dom_list
[i
].sid
);
4585 d
->trust_flags
= dom_list
[i
].trust_flags
;
4586 d
->trust_type
= dom_list
[i
].trust_type
;
4587 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
4593 TALLOC_FREE(dom_list
);
4599 /*********************************************************************
4600 ********************************************************************/
4602 void wcache_tdc_clear( void )
4604 if ( !init_wcache() )
4607 wcache_tdc_store_list( NULL
, 0 );
4613 /*********************************************************************
4614 ********************************************************************/
4616 static void wcache_save_user_pwinfo(struct winbindd_domain
*domain
,
4618 const struct dom_sid
*user_sid
,
4619 const char *homedir
,
4624 struct cache_entry
*centry
;
4627 if ( (centry
= centry_start(domain
, status
)) == NULL
)
4630 centry_put_string( centry
, homedir
);
4631 centry_put_string( centry
, shell
);
4632 centry_put_string( centry
, gecos
);
4633 centry_put_uint32( centry
, gid
);
4635 centry_end(centry
, "NSS/PWINFO/%s", sid_to_fstring(tmp
, user_sid
) );
4637 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid
) ));
4639 centry_free(centry
);
4644 NTSTATUS
nss_get_info_cached( struct winbindd_domain
*domain
,
4645 const struct dom_sid
*user_sid
,
4647 const char **homedir
, const char **shell
,
4648 const char **gecos
, gid_t
*p_gid
)
4650 struct winbind_cache
*cache
= get_cache(domain
);
4651 struct cache_entry
*centry
= NULL
;
4658 centry
= wcache_fetch(cache
, domain
, "NSS/PWINFO/%s",
4659 sid_to_fstring(tmp
, user_sid
));
4664 *homedir
= centry_string( centry
, ctx
);
4665 *shell
= centry_string( centry
, ctx
);
4666 *gecos
= centry_string( centry
, ctx
);
4667 *p_gid
= centry_uint32( centry
);
4669 centry_free(centry
);
4671 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4672 sid_string_dbg(user_sid
)));
4674 return NT_STATUS_OK
;
4678 nt_status
= nss_get_info( domain
->name
, user_sid
, ctx
,
4679 homedir
, shell
, gecos
, p_gid
);
4681 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status
)));
4683 if ( NT_STATUS_IS_OK(nt_status
) ) {
4684 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir
));
4685 DEBUGADD(10, ("\tshell = '%s'\n", *shell
));
4686 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos
));
4687 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid
));
4689 wcache_save_user_pwinfo( domain
, nt_status
, user_sid
,
4690 *homedir
, *shell
, *gecos
, *p_gid
);
4693 if ( NT_STATUS_EQUAL( nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
4694 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4696 set_domain_offline( domain
);
4704 /* the cache backend methods are exposed via this structure */
4705 struct winbindd_methods cache_methods
= {
4723 static bool wcache_ndr_key(TALLOC_CTX
*mem_ctx
, char *domain_name
,
4724 uint32_t opnum
, const DATA_BLOB
*req
,
4730 key
= talloc_asprintf(mem_ctx
, "NDR/%s/%d/", domain_name
, (int)opnum
);
4734 keylen
= talloc_get_size(key
) - 1;
4736 key
= talloc_realloc(mem_ctx
, key
, char, keylen
+ req
->length
);
4740 memcpy(key
+ keylen
, req
->data
, req
->length
);
4742 pkey
->dptr
= (uint8_t *)key
;
4743 pkey
->dsize
= talloc_get_size(key
);
4747 static bool wcache_opnum_cacheable(uint32_t opnum
)
4750 case NDR_WBINT_PING
:
4751 case NDR_WBINT_QUERYSEQUENCENUMBER
:
4752 case NDR_WBINT_ALLOCATEUID
:
4753 case NDR_WBINT_ALLOCATEGID
:
4754 case NDR_WBINT_CHECKMACHINEACCOUNT
:
4755 case NDR_WBINT_CHANGEMACHINEACCOUNT
:
4756 case NDR_WBINT_PINGDC
:
4762 bool wcache_fetch_ndr(TALLOC_CTX
*mem_ctx
, struct winbindd_domain
*domain
,
4763 uint32_t opnum
, const DATA_BLOB
*req
, DATA_BLOB
*resp
)
4768 if (!wcache_opnum_cacheable(opnum
) ||
4769 is_my_own_sam_domain(domain
) ||
4770 is_builtin_domain(domain
)) {
4774 if (wcache
->tdb
== NULL
) {
4778 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4781 data
= tdb_fetch(wcache
->tdb
, key
);
4782 TALLOC_FREE(key
.dptr
);
4784 if (data
.dptr
== NULL
) {
4787 if (data
.dsize
< 12) {
4791 if (!is_domain_offline(domain
)) {
4792 uint32_t entry_seqnum
, dom_seqnum
, last_check
;
4793 uint64_t entry_timeout
;
4795 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
,
4799 entry_seqnum
= IVAL(data
.dptr
, 0);
4800 if (entry_seqnum
!= dom_seqnum
) {
4801 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4802 (int)entry_seqnum
));
4805 entry_timeout
= BVAL(data
.dptr
, 4);
4806 if (entry_timeout
> time(NULL
)) {
4807 DEBUG(10, ("Entry has timed out\n"));
4812 resp
->data
= (uint8_t *)talloc_memdup(mem_ctx
, data
.dptr
+ 12,
4814 if (resp
->data
== NULL
) {
4815 DEBUG(10, ("talloc failed\n"));
4818 resp
->length
= data
.dsize
- 12;
4822 SAFE_FREE(data
.dptr
);
4826 void wcache_store_ndr(struct winbindd_domain
*domain
, uint32_t opnum
,
4827 const DATA_BLOB
*req
, const DATA_BLOB
*resp
)
4830 uint32_t dom_seqnum
, last_check
;
4833 if (!wcache_opnum_cacheable(opnum
) ||
4834 is_my_own_sam_domain(domain
) ||
4835 is_builtin_domain(domain
)) {
4839 if (wcache
->tdb
== NULL
) {
4843 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
, &last_check
)) {
4844 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4849 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4853 timeout
= time(NULL
) + lp_winbind_cache_time();
4855 data
.dsize
= resp
->length
+ 12;
4856 data
.dptr
= talloc_array(key
.dptr
, uint8_t, data
.dsize
);
4857 if (data
.dptr
== NULL
) {
4861 SIVAL(data
.dptr
, 0, dom_seqnum
);
4862 SBVAL(data
.dptr
, 4, timeout
);
4863 memcpy(data
.dptr
+ 12, resp
->data
, resp
->length
);
4865 tdb_store(wcache
->tdb
, key
, data
, 0);
4868 TALLOC_FREE(key
.dptr
);