2 Unix SMB/CIFS implementation.
4 Winbind cache backend functions
6 Copyright (C) Andrew Tridgell 2001
7 Copyright (C) Gerald Carter 2003-2007
8 Copyright (C) Volker Lendecke 2005
9 Copyright (C) Guenther Deschner 2005
10 Copyright (C) Michael Adam 2007
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 #include "tdb_validate.h"
29 #include "../libcli/auth/libcli_auth.h"
30 #include "../librpc/gen_ndr/ndr_wbint.h"
35 #define DBGC_CLASS DBGC_WINBIND
37 #define WINBINDD_CACHE_VERSION 1
38 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
40 extern struct winbindd_methods reconnect_methods
;
42 extern struct winbindd_methods ads_methods
;
44 extern struct winbindd_methods builtin_passdb_methods
;
45 extern struct winbindd_methods sam_passdb_methods
;
48 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
49 * Here are the list of entry types that are *not* stored
50 * as form struct cache_entry in the cache.
53 static const char *non_centry_keys
[] = {
58 WINBINDD_CACHE_VERSION_KEYSTR
,
62 /************************************************************************
63 Is this key a non-centry type ?
64 ************************************************************************/
66 static bool is_non_centry_key(TDB_DATA kbuf
)
70 if (kbuf
.dptr
== NULL
|| kbuf
.dsize
== 0) {
73 for (i
= 0; non_centry_keys
[i
] != NULL
; i
++) {
74 size_t namelen
= strlen(non_centry_keys
[i
]);
75 if (kbuf
.dsize
< namelen
) {
78 if (strncmp(non_centry_keys
[i
], (const char *)kbuf
.dptr
, namelen
) == 0) {
85 /* Global online/offline state - False when online. winbindd starts up online
86 and sets this to true if the first query fails and there's an entry in
87 the cache tdb telling us to stay offline. */
89 static bool global_winbindd_offline_state
;
91 struct winbind_cache
{
97 uint32 sequence_number
;
102 void (*smb_panic_fn
)(const char *const why
) = smb_panic
;
104 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
106 static struct winbind_cache
*wcache
;
108 /* get the winbind_cache structure */
109 static struct winbind_cache
*get_cache(struct winbindd_domain
*domain
)
111 struct winbind_cache
*ret
= wcache
;
113 /* We have to know what type of domain we are dealing with first. */
115 if (domain
->internal
) {
116 domain
->backend
= &builtin_passdb_methods
;
117 domain
->initialized
= True
;
120 if (strequal(domain
->name
, get_global_sam_name()) &&
121 sid_equal(&domain
->sid
, get_global_sam_sid())) {
122 domain
->backend
= &sam_passdb_methods
;
123 domain
->initialized
= True
;
126 if ( !domain
->initialized
) {
127 init_dc_connection( domain
);
131 OK. listen up becasue I'm only going to say this once.
132 We have the following scenarios to consider
133 (a) trusted AD domains on a Samba DC,
134 (b) trusted AD domains and we are joined to a non-kerberos domain
135 (c) trusted AD domains and we are joined to a kerberos (AD) domain
137 For (a) we can always contact the trusted domain using krb5
138 since we have the domain trust account password
140 For (b) we can only use RPC since we have no way of
141 getting a krb5 ticket in our own domain
143 For (c) we can always use krb5 since we have a kerberos trust
148 if (!domain
->backend
) {
150 struct winbindd_domain
*our_domain
= domain
;
152 /* find our domain first so we can figure out if we
153 are joined to a kerberized domain */
155 if ( !domain
->primary
)
156 our_domain
= find_our_domain();
158 if ((our_domain
->active_directory
|| IS_DC
)
159 && domain
->active_directory
160 && !lp_winbind_rpc_only()) {
161 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain
->name
));
162 domain
->backend
= &ads_methods
;
164 #endif /* HAVE_ADS */
165 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain
->name
));
166 domain
->backend
= &reconnect_methods
;
169 #endif /* HAVE_ADS */
175 ret
= SMB_XMALLOC_P(struct winbind_cache
);
179 wcache_flush_cache();
185 free a centry structure
187 static void centry_free(struct cache_entry
*centry
)
191 SAFE_FREE(centry
->data
);
195 static bool centry_check_bytes(struct cache_entry
*centry
, size_t nbytes
)
197 if (centry
->len
- centry
->ofs
< nbytes
) {
198 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
199 (unsigned int)nbytes
,
200 centry
->len
- centry
->ofs
));
207 pull a uint32 from a cache entry
209 static uint32
centry_uint32(struct cache_entry
*centry
)
213 if (!centry_check_bytes(centry
, 4)) {
214 smb_panic_fn("centry_uint32");
216 ret
= IVAL(centry
->data
, centry
->ofs
);
222 pull a uint16 from a cache entry
224 static uint16
centry_uint16(struct cache_entry
*centry
)
227 if (!centry_check_bytes(centry
, 2)) {
228 smb_panic_fn("centry_uint16");
230 ret
= CVAL(centry
->data
, centry
->ofs
);
236 pull a uint8 from a cache entry
238 static uint8
centry_uint8(struct cache_entry
*centry
)
241 if (!centry_check_bytes(centry
, 1)) {
242 smb_panic_fn("centry_uint8");
244 ret
= CVAL(centry
->data
, centry
->ofs
);
250 pull a NTTIME from a cache entry
252 static NTTIME
centry_nttime(struct cache_entry
*centry
)
255 if (!centry_check_bytes(centry
, 8)) {
256 smb_panic_fn("centry_nttime");
258 ret
= IVAL(centry
->data
, centry
->ofs
);
260 ret
+= (uint64_t)IVAL(centry
->data
, centry
->ofs
) << 32;
266 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
268 static time_t centry_time(struct cache_entry
*centry
)
270 return (time_t)centry_nttime(centry
);
273 /* pull a string from a cache entry, using the supplied
276 static char *centry_string(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
281 len
= centry_uint8(centry
);
284 /* a deliberate NULL string */
288 if (!centry_check_bytes(centry
, (size_t)len
)) {
289 smb_panic_fn("centry_string");
292 ret
= TALLOC_ARRAY(mem_ctx
, char, len
+1);
294 smb_panic_fn("centry_string out of memory\n");
296 memcpy(ret
,centry
->data
+ centry
->ofs
, len
);
302 /* pull a hash16 from a cache entry, using the supplied
305 static char *centry_hash16(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
310 len
= centry_uint8(centry
);
313 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
318 if (!centry_check_bytes(centry
, 16)) {
322 ret
= TALLOC_ARRAY(mem_ctx
, char, 16);
324 smb_panic_fn("centry_hash out of memory\n");
326 memcpy(ret
,centry
->data
+ centry
->ofs
, 16);
331 /* pull a sid from a cache entry, using the supplied
334 static bool centry_sid(struct cache_entry
*centry
, struct dom_sid
*sid
)
339 sid_string
= centry_string(centry
, talloc_tos());
340 if (sid_string
== NULL
) {
343 ret
= string_to_sid(sid
, sid_string
);
344 TALLOC_FREE(sid_string
);
350 pull a NTSTATUS from a cache entry
352 static NTSTATUS
centry_ntstatus(struct cache_entry
*centry
)
356 status
= NT_STATUS(centry_uint32(centry
));
361 /* the server is considered down if it can't give us a sequence number */
362 static bool wcache_server_down(struct winbindd_domain
*domain
)
369 ret
= (domain
->sequence_number
== DOM_SEQUENCE_NONE
);
372 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
377 static bool wcache_fetch_seqnum(const char *domain_name
, uint32_t *seqnum
,
378 uint32_t *last_seq_check
)
383 if (wcache
->tdb
== NULL
) {
384 DEBUG(10,("wcache_fetch_seqnum: tdb == NULL\n"));
388 key
= talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name
);
390 DEBUG(10, ("talloc failed\n"));
394 data
= tdb_fetch_bystring(wcache
->tdb
, key
);
397 if (data
.dptr
== NULL
) {
398 DEBUG(10, ("wcache_fetch_seqnum: %s not found\n",
402 if (data
.dsize
!= 8) {
403 DEBUG(10, ("wcache_fetch_seqnum: invalid data size %d\n",
405 SAFE_FREE(data
.dptr
);
409 *seqnum
= IVAL(data
.dptr
, 0);
410 *last_seq_check
= IVAL(data
.dptr
, 4);
411 SAFE_FREE(data
.dptr
);
416 static NTSTATUS
fetch_cache_seqnum( struct winbindd_domain
*domain
, time_t now
)
418 uint32 last_check
, time_diff
;
420 if (!wcache_fetch_seqnum(domain
->name
, &domain
->sequence_number
,
422 return NT_STATUS_UNSUCCESSFUL
;
424 domain
->last_seq_check
= last_check
;
426 /* have we expired? */
428 time_diff
= now
- domain
->last_seq_check
;
429 if ( time_diff
> lp_winbind_cache_time() ) {
430 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
431 domain
->name
, domain
->sequence_number
,
432 (uint32
)domain
->last_seq_check
));
433 return NT_STATUS_UNSUCCESSFUL
;
436 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
437 domain
->name
, domain
->sequence_number
,
438 (uint32
)domain
->last_seq_check
));
443 bool wcache_store_seqnum(const char *domain_name
, uint32_t seqnum
,
444 time_t last_seq_check
)
450 if (wcache
->tdb
== NULL
) {
451 DEBUG(10, ("wcache_store_seqnum: wcache->tdb == NULL\n"));
455 key_str
= talloc_asprintf(talloc_tos(), "SEQNUM/%s", domain_name
);
456 if (key_str
== NULL
) {
457 DEBUG(10, ("talloc_asprintf failed\n"));
461 SIVAL(buf
, 0, seqnum
);
462 SIVAL(buf
, 4, last_seq_check
);
464 ret
= tdb_store_bystring(wcache
->tdb
, key_str
,
465 make_tdb_data(buf
, sizeof(buf
)), TDB_REPLACE
);
466 TALLOC_FREE(key_str
);
468 DEBUG(10, ("tdb_store_bystring failed: %s\n",
469 tdb_errorstr(wcache
->tdb
)));
470 TALLOC_FREE(key_str
);
474 DEBUG(10, ("wcache_store_seqnum: success [%s][%u @ %u]\n",
475 domain_name
, seqnum
, (unsigned)last_seq_check
));
480 static bool store_cache_seqnum( struct winbindd_domain
*domain
)
482 return wcache_store_seqnum(domain
->name
, domain
->sequence_number
,
483 domain
->last_seq_check
);
487 refresh the domain sequence number. If force is true
488 then always refresh it, no matter how recently we fetched it
491 static void refresh_sequence_number(struct winbindd_domain
*domain
, bool force
)
495 time_t t
= time(NULL
);
496 unsigned cache_time
= lp_winbind_cache_time();
498 if (is_domain_offline(domain
)) {
504 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
505 /* trying to reconnect is expensive, don't do it too often */
506 if (domain
->sequence_number
== DOM_SEQUENCE_NONE
) {
511 time_diff
= t
- domain
->last_seq_check
;
513 /* see if we have to refetch the domain sequence number */
514 if (!force
&& (time_diff
< cache_time
) &&
515 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
516 NT_STATUS_IS_OK(domain
->last_status
)) {
517 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain
->name
));
521 /* try to get the sequence number from the tdb cache first */
522 /* this will update the timestamp as well */
524 status
= fetch_cache_seqnum( domain
, t
);
525 if (NT_STATUS_IS_OK(status
) &&
526 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
527 NT_STATUS_IS_OK(domain
->last_status
)) {
531 /* important! make sure that we know if this is a native
532 mode domain or not. And that we can contact it. */
534 if ( winbindd_can_contact_domain( domain
) ) {
535 status
= domain
->backend
->sequence_number(domain
,
536 &domain
->sequence_number
);
538 /* just use the current time */
539 status
= NT_STATUS_OK
;
540 domain
->sequence_number
= time(NULL
);
544 /* the above call could have set our domain->backend to NULL when
545 * coming from offline to online mode, make sure to reinitialize the
546 * backend - Guenther */
549 if (!NT_STATUS_IS_OK(status
)) {
550 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status
)));
551 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
554 domain
->last_status
= status
;
555 domain
->last_seq_check
= time(NULL
);
557 /* save the new sequence number in the cache */
558 store_cache_seqnum( domain
);
561 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
562 domain
->name
, domain
->sequence_number
));
568 decide if a cache entry has expired
570 static bool centry_expired(struct winbindd_domain
*domain
, const char *keystr
, struct cache_entry
*centry
)
572 /* If we've been told to be offline - stay in that state... */
573 if (lp_winbind_offline_logon() && global_winbindd_offline_state
) {
574 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
575 keystr
, domain
->name
));
579 /* when the domain is offline return the cached entry.
580 * This deals with transient offline states... */
582 if (!domain
->online
) {
583 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
584 keystr
, domain
->name
));
588 /* if the server is OK and our cache entry came from when it was down then
589 the entry is invalid */
590 if ((domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
591 (centry
->sequence_number
== DOM_SEQUENCE_NONE
)) {
592 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
593 keystr
, domain
->name
));
597 /* if the server is down or the cache entry is not older than the
598 current sequence number then it is OK */
599 if (wcache_server_down(domain
) ||
600 centry
->sequence_number
== domain
->sequence_number
) {
601 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
602 keystr
, domain
->name
));
606 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
607 keystr
, domain
->name
));
613 static struct cache_entry
*wcache_fetch_raw(char *kstr
)
616 struct cache_entry
*centry
;
619 key
= string_tdb_data(kstr
);
620 data
= tdb_fetch(wcache
->tdb
, key
);
626 centry
= SMB_XMALLOC_P(struct cache_entry
);
627 centry
->data
= (unsigned char *)data
.dptr
;
628 centry
->len
= data
.dsize
;
631 if (centry
->len
< 8) {
632 /* huh? corrupt cache? */
633 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr
));
638 centry
->status
= centry_ntstatus(centry
);
639 centry
->sequence_number
= centry_uint32(centry
);
644 static bool is_my_own_sam_domain(struct winbindd_domain
*domain
)
646 if (strequal(domain
->name
, get_global_sam_name()) &&
647 sid_equal(&domain
->sid
, get_global_sam_sid())) {
654 static bool is_builtin_domain(struct winbindd_domain
*domain
)
656 if (strequal(domain
->name
, "BUILTIN") &&
657 sid_equal(&domain
->sid
, &global_sid_Builtin
)) {
665 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
666 number and return status
668 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
669 struct winbindd_domain
*domain
,
670 const char *format
, ...) PRINTF_ATTRIBUTE(3,4);
671 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
672 struct winbindd_domain
*domain
,
673 const char *format
, ...)
677 struct cache_entry
*centry
;
679 if (!winbindd_use_cache() ||
680 is_my_own_sam_domain(domain
) ||
681 is_builtin_domain(domain
)) {
685 refresh_sequence_number(domain
, false);
687 va_start(ap
, format
);
688 smb_xvasprintf(&kstr
, format
, ap
);
691 centry
= wcache_fetch_raw(kstr
);
692 if (centry
== NULL
) {
697 if (centry_expired(domain
, kstr
, centry
)) {
699 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
700 kstr
, domain
->name
));
707 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
708 kstr
, domain
->name
));
714 static void wcache_delete(const char *format
, ...) PRINTF_ATTRIBUTE(1,2);
715 static void wcache_delete(const char *format
, ...)
721 va_start(ap
, format
);
722 smb_xvasprintf(&kstr
, format
, ap
);
725 key
= string_tdb_data(kstr
);
727 tdb_delete(wcache
->tdb
, key
);
732 make sure we have at least len bytes available in a centry
734 static void centry_expand(struct cache_entry
*centry
, uint32 len
)
736 if (centry
->len
- centry
->ofs
>= len
)
739 centry
->data
= SMB_REALLOC_ARRAY(centry
->data
, unsigned char,
742 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry
->len
));
743 smb_panic_fn("out of memory in centry_expand");
748 push a uint32 into a centry
750 static void centry_put_uint32(struct cache_entry
*centry
, uint32 v
)
752 centry_expand(centry
, 4);
753 SIVAL(centry
->data
, centry
->ofs
, v
);
758 push a uint16 into a centry
760 static void centry_put_uint16(struct cache_entry
*centry
, uint16 v
)
762 centry_expand(centry
, 2);
763 SIVAL(centry
->data
, centry
->ofs
, v
);
768 push a uint8 into a centry
770 static void centry_put_uint8(struct cache_entry
*centry
, uint8 v
)
772 centry_expand(centry
, 1);
773 SCVAL(centry
->data
, centry
->ofs
, v
);
778 push a string into a centry
780 static void centry_put_string(struct cache_entry
*centry
, const char *s
)
785 /* null strings are marked as len 0xFFFF */
786 centry_put_uint8(centry
, 0xFF);
791 /* can't handle more than 254 char strings. Truncating is probably best */
793 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len
));
796 centry_put_uint8(centry
, len
);
797 centry_expand(centry
, len
);
798 memcpy(centry
->data
+ centry
->ofs
, s
, len
);
803 push a 16 byte hash into a centry - treat as 16 byte string.
805 static void centry_put_hash16(struct cache_entry
*centry
, const uint8 val
[16])
807 centry_put_uint8(centry
, 16);
808 centry_expand(centry
, 16);
809 memcpy(centry
->data
+ centry
->ofs
, val
, 16);
813 static void centry_put_sid(struct cache_entry
*centry
, const struct dom_sid
*sid
)
816 centry_put_string(centry
, sid_to_fstring(sid_string
, sid
));
821 put NTSTATUS into a centry
823 static void centry_put_ntstatus(struct cache_entry
*centry
, NTSTATUS status
)
825 uint32 status_value
= NT_STATUS_V(status
);
826 centry_put_uint32(centry
, status_value
);
831 push a NTTIME into a centry
833 static void centry_put_nttime(struct cache_entry
*centry
, NTTIME nt
)
835 centry_expand(centry
, 8);
836 SIVAL(centry
->data
, centry
->ofs
, nt
& 0xFFFFFFFF);
838 SIVAL(centry
->data
, centry
->ofs
, nt
>> 32);
843 push a time_t into a centry - use a 64 bit size.
844 NTTIME here is being used as a convenient 64-bit size.
846 static void centry_put_time(struct cache_entry
*centry
, time_t t
)
848 NTTIME nt
= (NTTIME
)t
;
849 centry_put_nttime(centry
, nt
);
853 start a centry for output. When finished, call centry_end()
855 struct cache_entry
*centry_start(struct winbindd_domain
*domain
, NTSTATUS status
)
857 struct cache_entry
*centry
;
862 centry
= SMB_XMALLOC_P(struct cache_entry
);
864 centry
->len
= 8192; /* reasonable default */
865 centry
->data
= SMB_XMALLOC_ARRAY(uint8
, centry
->len
);
867 centry
->sequence_number
= domain
->sequence_number
;
868 centry_put_ntstatus(centry
, status
);
869 centry_put_uint32(centry
, centry
->sequence_number
);
874 finish a centry and write it to the tdb
876 static void centry_end(struct cache_entry
*centry
, const char *format
, ...) PRINTF_ATTRIBUTE(2,3);
877 static void centry_end(struct cache_entry
*centry
, const char *format
, ...)
883 if (!winbindd_use_cache()) {
887 va_start(ap
, format
);
888 smb_xvasprintf(&kstr
, format
, ap
);
891 key
= string_tdb_data(kstr
);
892 data
.dptr
= centry
->data
;
893 data
.dsize
= centry
->ofs
;
895 tdb_store(wcache
->tdb
, key
, data
, TDB_REPLACE
);
899 static void wcache_save_name_to_sid(struct winbindd_domain
*domain
,
900 NTSTATUS status
, const char *domain_name
,
901 const char *name
, const struct dom_sid
*sid
,
902 enum lsa_SidType type
)
904 struct cache_entry
*centry
;
907 centry
= centry_start(domain
, status
);
910 centry_put_uint32(centry
, type
);
911 centry_put_sid(centry
, sid
);
912 fstrcpy(uname
, name
);
914 centry_end(centry
, "NS/%s/%s", domain_name
, uname
);
915 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name
,
916 uname
, sid_string_dbg(sid
), nt_errstr(status
)));
920 static void wcache_save_sid_to_name(struct winbindd_domain
*domain
, NTSTATUS status
,
921 const struct dom_sid
*sid
, const char *domain_name
, const char *name
, enum lsa_SidType type
)
923 struct cache_entry
*centry
;
926 centry
= centry_start(domain
, status
);
930 if (NT_STATUS_IS_OK(status
)) {
931 centry_put_uint32(centry
, type
);
932 centry_put_string(centry
, domain_name
);
933 centry_put_string(centry
, name
);
936 centry_end(centry
, "SN/%s", sid_to_fstring(sid_string
, sid
));
937 DEBUG(10,("wcache_save_sid_to_name: %s -> %s (%s)\n", sid_string
,
938 name
, nt_errstr(status
)));
943 static void wcache_save_user(struct winbindd_domain
*domain
, NTSTATUS status
,
944 struct wbint_userinfo
*info
)
946 struct cache_entry
*centry
;
949 if (is_null_sid(&info
->user_sid
)) {
953 centry
= centry_start(domain
, status
);
956 centry_put_string(centry
, info
->acct_name
);
957 centry_put_string(centry
, info
->full_name
);
958 centry_put_string(centry
, info
->homedir
);
959 centry_put_string(centry
, info
->shell
);
960 centry_put_uint32(centry
, info
->primary_gid
);
961 centry_put_sid(centry
, &info
->user_sid
);
962 centry_put_sid(centry
, &info
->group_sid
);
963 centry_end(centry
, "U/%s", sid_to_fstring(sid_string
,
965 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string
, info
->acct_name
));
969 static void wcache_save_lockout_policy(struct winbindd_domain
*domain
,
971 struct samr_DomInfo12
*lockout_policy
)
973 struct cache_entry
*centry
;
975 centry
= centry_start(domain
, status
);
979 centry_put_nttime(centry
, lockout_policy
->lockout_duration
);
980 centry_put_nttime(centry
, lockout_policy
->lockout_window
);
981 centry_put_uint16(centry
, lockout_policy
->lockout_threshold
);
983 centry_end(centry
, "LOC_POL/%s", domain
->name
);
985 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain
->name
));
992 static void wcache_save_password_policy(struct winbindd_domain
*domain
,
994 struct samr_DomInfo1
*policy
)
996 struct cache_entry
*centry
;
998 centry
= centry_start(domain
, status
);
1002 centry_put_uint16(centry
, policy
->min_password_length
);
1003 centry_put_uint16(centry
, policy
->password_history_length
);
1004 centry_put_uint32(centry
, policy
->password_properties
);
1005 centry_put_nttime(centry
, policy
->max_password_age
);
1006 centry_put_nttime(centry
, policy
->min_password_age
);
1008 centry_end(centry
, "PWD_POL/%s", domain
->name
);
1010 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
1012 centry_free(centry
);
1015 /***************************************************************************
1016 ***************************************************************************/
1018 static void wcache_save_username_alias(struct winbindd_domain
*domain
,
1020 const char *name
, const char *alias
)
1022 struct cache_entry
*centry
;
1025 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1028 centry_put_string( centry
, alias
);
1030 fstrcpy(uname
, name
);
1032 centry_end(centry
, "NSS/NA/%s", uname
);
1034 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name
, alias
));
1036 centry_free(centry
);
1039 static void wcache_save_alias_username(struct winbindd_domain
*domain
,
1041 const char *alias
, const char *name
)
1043 struct cache_entry
*centry
;
1046 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1049 centry_put_string( centry
, name
);
1051 fstrcpy(uname
, alias
);
1053 centry_end(centry
, "NSS/AN/%s", uname
);
1055 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias
, name
));
1057 centry_free(centry
);
1060 /***************************************************************************
1061 ***************************************************************************/
1063 NTSTATUS
resolve_username_to_alias( TALLOC_CTX
*mem_ctx
,
1064 struct winbindd_domain
*domain
,
1065 const char *name
, char **alias
)
1067 struct winbind_cache
*cache
= get_cache(domain
);
1068 struct cache_entry
*centry
= NULL
;
1072 if ( domain
->internal
)
1073 return NT_STATUS_NOT_SUPPORTED
;
1078 if ( (upper_name
= SMB_STRDUP(name
)) == NULL
)
1079 return NT_STATUS_NO_MEMORY
;
1080 strupper_m(upper_name
);
1082 centry
= wcache_fetch(cache
, domain
, "NSS/NA/%s", upper_name
);
1084 SAFE_FREE( upper_name
);
1089 status
= centry
->status
;
1091 if (!NT_STATUS_IS_OK(status
)) {
1092 centry_free(centry
);
1096 *alias
= centry_string( centry
, mem_ctx
);
1098 centry_free(centry
);
1100 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1101 name
, *alias
? *alias
: "(none)"));
1103 return (*alias
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1107 /* If its not in cache and we are offline, then fail */
1109 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1110 DEBUG(8,("resolve_username_to_alias: rejecting query "
1111 "in offline mode\n"));
1112 return NT_STATUS_NOT_FOUND
;
1115 status
= nss_map_to_alias( mem_ctx
, domain
->name
, name
, alias
);
1117 if ( NT_STATUS_IS_OK( status
) ) {
1118 wcache_save_username_alias(domain
, status
, name
, *alias
);
1121 if ( NT_STATUS_EQUAL( status
, NT_STATUS_NONE_MAPPED
) ) {
1122 wcache_save_username_alias(domain
, status
, name
, "(NULL)");
1125 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1126 nt_errstr(status
)));
1128 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1129 set_domain_offline( domain
);
1135 /***************************************************************************
1136 ***************************************************************************/
1138 NTSTATUS
resolve_alias_to_username( TALLOC_CTX
*mem_ctx
,
1139 struct winbindd_domain
*domain
,
1140 const char *alias
, char **name
)
1142 struct winbind_cache
*cache
= get_cache(domain
);
1143 struct cache_entry
*centry
= NULL
;
1147 if ( domain
->internal
)
1148 return NT_STATUS_NOT_SUPPORTED
;
1153 if ( (upper_name
= SMB_STRDUP(alias
)) == NULL
)
1154 return NT_STATUS_NO_MEMORY
;
1155 strupper_m(upper_name
);
1157 centry
= wcache_fetch(cache
, domain
, "NSS/AN/%s", upper_name
);
1159 SAFE_FREE( upper_name
);
1164 status
= centry
->status
;
1166 if (!NT_STATUS_IS_OK(status
)) {
1167 centry_free(centry
);
1171 *name
= centry_string( centry
, mem_ctx
);
1173 centry_free(centry
);
1175 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1176 alias
, *name
? *name
: "(none)"));
1178 return (*name
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1182 /* If its not in cache and we are offline, then fail */
1184 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1185 DEBUG(8,("resolve_alias_to_username: rejecting query "
1186 "in offline mode\n"));
1187 return NT_STATUS_NOT_FOUND
;
1190 /* an alias cannot contain a domain prefix or '@' */
1192 if (strchr(alias
, '\\') || strchr(alias
, '@')) {
1193 DEBUG(10,("resolve_alias_to_username: skipping fully "
1194 "qualified name %s\n", alias
));
1195 return NT_STATUS_OBJECT_NAME_INVALID
;
1198 status
= nss_map_from_alias( mem_ctx
, domain
->name
, alias
, name
);
1200 if ( NT_STATUS_IS_OK( status
) ) {
1201 wcache_save_alias_username( domain
, status
, alias
, *name
);
1204 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1205 wcache_save_alias_username(domain
, status
, alias
, "(NULL)");
1208 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1209 nt_errstr(status
)));
1211 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1212 set_domain_offline( domain
);
1218 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
1220 struct winbind_cache
*cache
= get_cache(domain
);
1222 fstring key_str
, tmp
;
1226 return NT_STATUS_INTERNAL_DB_ERROR
;
1229 if (is_null_sid(sid
)) {
1230 return NT_STATUS_INVALID_SID
;
1233 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1234 return NT_STATUS_INVALID_SID
;
1237 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
1239 data
= tdb_fetch(cache
->tdb
, string_tdb_data(key_str
));
1241 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1244 SAFE_FREE(data
.dptr
);
1245 return NT_STATUS_OK
;
1248 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1249 as new salted ones. */
1251 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
1252 TALLOC_CTX
*mem_ctx
,
1253 const struct dom_sid
*sid
,
1254 const uint8
**cached_nt_pass
,
1255 const uint8
**cached_salt
)
1257 struct winbind_cache
*cache
= get_cache(domain
);
1258 struct cache_entry
*centry
= NULL
;
1265 return NT_STATUS_INTERNAL_DB_ERROR
;
1268 if (is_null_sid(sid
)) {
1269 return NT_STATUS_INVALID_SID
;
1272 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1273 return NT_STATUS_INVALID_SID
;
1276 /* Try and get a salted cred first. If we can't
1277 fall back to an unsalted cred. */
1279 centry
= wcache_fetch(cache
, domain
, "CRED/%s",
1280 sid_to_fstring(tmp
, sid
));
1282 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1283 sid_string_dbg(sid
)));
1284 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1287 t
= centry_time(centry
);
1289 /* In the salted case this isn't actually the nt_hash itself,
1290 but the MD5 of the salt + nt_hash. Let the caller
1291 sort this out. It can tell as we only return the cached_salt
1292 if we are returning a salted cred. */
1294 *cached_nt_pass
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1295 if (*cached_nt_pass
== NULL
) {
1298 sid_to_fstring(sidstr
, sid
);
1300 /* Bad (old) cred cache. Delete and pretend we
1302 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1304 wcache_delete("CRED/%s", sidstr
);
1305 centry_free(centry
);
1306 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1309 /* We only have 17 bytes more data in the salted cred case. */
1310 if (centry
->len
- centry
->ofs
== 17) {
1311 *cached_salt
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1313 *cached_salt
= NULL
;
1316 dump_data_pw("cached_nt_pass", *cached_nt_pass
, NT_HASH_LEN
);
1318 dump_data_pw("cached_salt", *cached_salt
, NT_HASH_LEN
);
1321 status
= centry
->status
;
1323 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1324 sid_string_dbg(sid
), nt_errstr(status
) ));
1326 centry_free(centry
);
1330 /* Store creds for a SID - only writes out new salted ones. */
1332 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1333 const struct dom_sid
*sid
,
1334 const uint8 nt_pass
[NT_HASH_LEN
])
1336 struct cache_entry
*centry
;
1339 uint8 cred_salt
[NT_HASH_LEN
];
1340 uint8 salted_hash
[NT_HASH_LEN
];
1342 if (is_null_sid(sid
)) {
1343 return NT_STATUS_INVALID_SID
;
1346 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1347 return NT_STATUS_INVALID_SID
;
1350 centry
= centry_start(domain
, NT_STATUS_OK
);
1352 return NT_STATUS_INTERNAL_DB_ERROR
;
1355 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1357 centry_put_time(centry
, time(NULL
));
1359 /* Create a salt and then salt the hash. */
1360 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1361 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1363 centry_put_hash16(centry
, salted_hash
);
1364 centry_put_hash16(centry
, cred_salt
);
1365 centry_end(centry
, "CRED/%s", sid_to_fstring(sid_string
, sid
));
1367 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1369 centry_free(centry
);
1371 return NT_STATUS_OK
;
1375 /* Query display info. This is the basic user list fn */
1376 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
1377 TALLOC_CTX
*mem_ctx
,
1378 uint32
*num_entries
,
1379 struct wbint_userinfo
**info
)
1381 struct winbind_cache
*cache
= get_cache(domain
);
1382 struct cache_entry
*centry
= NULL
;
1384 unsigned int i
, retry
;
1385 bool old_status
= domain
->online
;
1390 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1395 *num_entries
= centry_uint32(centry
);
1397 if (*num_entries
== 0)
1400 (*info
) = TALLOC_ARRAY(mem_ctx
, struct wbint_userinfo
, *num_entries
);
1402 smb_panic_fn("query_user_list out of memory");
1404 for (i
=0; i
<(*num_entries
); i
++) {
1405 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
1406 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
1407 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
1408 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
1409 centry_sid(centry
, &(*info
)[i
].user_sid
);
1410 centry_sid(centry
, &(*info
)[i
].group_sid
);
1414 status
= centry
->status
;
1416 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1417 domain
->name
, nt_errstr(status
) ));
1419 centry_free(centry
);
1426 /* Return status value returned by seq number check */
1428 if (!NT_STATUS_IS_OK(domain
->last_status
))
1429 return domain
->last_status
;
1431 /* Put the query_user_list() in a retry loop. There appears to be
1432 * some bug either with Windows 2000 or Samba's handling of large
1433 * rpc replies. This manifests itself as sudden disconnection
1434 * at a random point in the enumeration of a large (60k) user list.
1435 * The retry loop simply tries the operation again. )-: It's not
1436 * pretty but an acceptable workaround until we work out what the
1437 * real problem is. */
1442 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1445 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
1446 if (!NT_STATUS_IS_OK(status
)) {
1447 DEBUG(3, ("query_user_list: returned 0x%08x, "
1448 "retrying\n", NT_STATUS_V(status
)));
1450 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1451 DEBUG(3, ("query_user_list: flushing "
1452 "connection cache\n"));
1453 invalidate_cm_connection(&domain
->conn
);
1455 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1456 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1457 if (!domain
->internal
&& old_status
) {
1458 set_domain_offline(domain
);
1460 /* store partial response. */
1461 if (*num_entries
> 0) {
1463 * humm, what about the status used for cache?
1464 * Should it be NT_STATUS_OK?
1469 * domain is offline now, and there is no user entries,
1470 * try to fetch from cache again.
1472 if (cache
->tdb
&& !domain
->online
&& !domain
->internal
&& old_status
) {
1473 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1474 /* partial response... */
1478 goto do_fetch_cache
;
1485 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1489 refresh_sequence_number(domain
, false);
1490 if (!NT_STATUS_IS_OK(status
)) {
1493 centry
= centry_start(domain
, status
);
1496 centry_put_uint32(centry
, *num_entries
);
1497 for (i
=0; i
<(*num_entries
); i
++) {
1498 centry_put_string(centry
, (*info
)[i
].acct_name
);
1499 centry_put_string(centry
, (*info
)[i
].full_name
);
1500 centry_put_string(centry
, (*info
)[i
].homedir
);
1501 centry_put_string(centry
, (*info
)[i
].shell
);
1502 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1503 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1504 if (domain
->backend
&& domain
->backend
->consistent
) {
1505 /* when the backend is consistent we can pre-prime some mappings */
1506 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1508 (*info
)[i
].acct_name
,
1509 &(*info
)[i
].user_sid
,
1511 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1512 &(*info
)[i
].user_sid
,
1514 (*info
)[i
].acct_name
,
1516 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1519 centry_end(centry
, "UL/%s", domain
->name
);
1520 centry_free(centry
);
1526 /* list all domain groups */
1527 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
1528 TALLOC_CTX
*mem_ctx
,
1529 uint32
*num_entries
,
1530 struct acct_info
**info
)
1532 struct winbind_cache
*cache
= get_cache(domain
);
1533 struct cache_entry
*centry
= NULL
;
1538 old_status
= domain
->online
;
1542 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1547 *num_entries
= centry_uint32(centry
);
1549 if (*num_entries
== 0)
1552 (*info
) = TALLOC_ARRAY(mem_ctx
, struct acct_info
, *num_entries
);
1554 smb_panic_fn("enum_dom_groups out of memory");
1556 for (i
=0; i
<(*num_entries
); i
++) {
1557 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1558 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1559 (*info
)[i
].rid
= centry_uint32(centry
);
1563 status
= centry
->status
;
1565 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1566 domain
->name
, nt_errstr(status
) ));
1568 centry_free(centry
);
1575 /* Return status value returned by seq number check */
1577 if (!NT_STATUS_IS_OK(domain
->last_status
))
1578 return domain
->last_status
;
1580 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1583 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1585 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1586 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1587 if (!domain
->internal
&& old_status
) {
1588 set_domain_offline(domain
);
1592 !domain
->internal
&&
1594 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1596 goto do_fetch_cache
;
1601 refresh_sequence_number(domain
, false);
1602 if (!NT_STATUS_IS_OK(status
)) {
1605 centry
= centry_start(domain
, status
);
1608 centry_put_uint32(centry
, *num_entries
);
1609 for (i
=0; i
<(*num_entries
); i
++) {
1610 centry_put_string(centry
, (*info
)[i
].acct_name
);
1611 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1612 centry_put_uint32(centry
, (*info
)[i
].rid
);
1614 centry_end(centry
, "GL/%s/domain", domain
->name
);
1615 centry_free(centry
);
1621 /* list all domain groups */
1622 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
1623 TALLOC_CTX
*mem_ctx
,
1624 uint32
*num_entries
,
1625 struct acct_info
**info
)
1627 struct winbind_cache
*cache
= get_cache(domain
);
1628 struct cache_entry
*centry
= NULL
;
1633 old_status
= domain
->online
;
1637 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1642 *num_entries
= centry_uint32(centry
);
1644 if (*num_entries
== 0)
1647 (*info
) = TALLOC_ARRAY(mem_ctx
, struct acct_info
, *num_entries
);
1649 smb_panic_fn("enum_dom_groups out of memory");
1651 for (i
=0; i
<(*num_entries
); i
++) {
1652 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1653 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1654 (*info
)[i
].rid
= centry_uint32(centry
);
1659 /* If we are returning cached data and the domain controller
1660 is down then we don't know whether the data is up to date
1661 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1664 if (wcache_server_down(domain
)) {
1665 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1666 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1668 status
= centry
->status
;
1670 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1671 domain
->name
, nt_errstr(status
) ));
1673 centry_free(centry
);
1680 /* Return status value returned by seq number check */
1682 if (!NT_STATUS_IS_OK(domain
->last_status
))
1683 return domain
->last_status
;
1685 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1688 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1690 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1691 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1692 if (!domain
->internal
&& old_status
) {
1693 set_domain_offline(domain
);
1696 !domain
->internal
&&
1699 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1701 goto do_fetch_cache
;
1706 refresh_sequence_number(domain
, false);
1707 if (!NT_STATUS_IS_OK(status
)) {
1710 centry
= centry_start(domain
, status
);
1713 centry_put_uint32(centry
, *num_entries
);
1714 for (i
=0; i
<(*num_entries
); i
++) {
1715 centry_put_string(centry
, (*info
)[i
].acct_name
);
1716 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1717 centry_put_uint32(centry
, (*info
)[i
].rid
);
1719 centry_end(centry
, "GL/%s/local", domain
->name
);
1720 centry_free(centry
);
1726 NTSTATUS
wcache_name_to_sid(struct winbindd_domain
*domain
,
1727 const char *domain_name
,
1729 struct dom_sid
*sid
,
1730 enum lsa_SidType
*type
)
1732 struct winbind_cache
*cache
= get_cache(domain
);
1733 struct cache_entry
*centry
;
1737 if (cache
->tdb
== NULL
) {
1738 return NT_STATUS_NOT_FOUND
;
1741 uname
= talloc_strdup_upper(talloc_tos(), name
);
1742 if (uname
== NULL
) {
1743 return NT_STATUS_NO_MEMORY
;
1746 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1748 if (centry
== NULL
) {
1749 return NT_STATUS_NOT_FOUND
;
1752 status
= centry
->status
;
1753 if (NT_STATUS_IS_OK(status
)) {
1754 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1755 centry_sid(centry
, sid
);
1758 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: "
1759 "%s\n", domain
->name
, nt_errstr(status
) ));
1761 centry_free(centry
);
1765 /* convert a single name to a sid in a domain */
1766 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
1767 TALLOC_CTX
*mem_ctx
,
1768 const char *domain_name
,
1771 struct dom_sid
*sid
,
1772 enum lsa_SidType
*type
)
1777 old_status
= domain
->online
;
1779 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1780 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1786 /* If the seq number check indicated that there is a problem
1787 * with this DC, then return that status... except for
1788 * access_denied. This is special because the dc may be in
1789 * "restrict anonymous = 1" mode, in which case it will deny
1790 * most unauthenticated operations, but *will* allow the LSA
1791 * name-to-sid that we try as a fallback. */
1793 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1794 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1795 return domain
->last_status
;
1797 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1800 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
,
1801 name
, flags
, sid
, type
);
1803 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1804 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1805 if (!domain
->internal
&& old_status
) {
1806 set_domain_offline(domain
);
1808 if (!domain
->internal
&&
1811 NTSTATUS cache_status
;
1812 cache_status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
1813 return cache_status
;
1817 refresh_sequence_number(domain
, false);
1819 if (domain
->online
&&
1820 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1821 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1823 /* Only save the reverse mapping if this was not a UPN */
1824 if (!strchr(name
, '@')) {
1825 strupper_m(CONST_DISCARD(char *,domain_name
));
1826 strlower_m(CONST_DISCARD(char *,name
));
1827 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1834 NTSTATUS
wcache_sid_to_name(struct winbindd_domain
*domain
,
1835 const struct dom_sid
*sid
,
1836 TALLOC_CTX
*mem_ctx
,
1839 enum lsa_SidType
*type
)
1841 struct winbind_cache
*cache
= get_cache(domain
);
1842 struct cache_entry
*centry
;
1846 if (cache
->tdb
== NULL
) {
1847 return NT_STATUS_NOT_FOUND
;
1850 sid_string
= sid_string_tos(sid
);
1851 if (sid_string
== NULL
) {
1852 return NT_STATUS_NO_MEMORY
;
1855 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_string
);
1856 TALLOC_FREE(sid_string
);
1857 if (centry
== NULL
) {
1858 return NT_STATUS_NOT_FOUND
;
1861 if (NT_STATUS_IS_OK(centry
->status
)) {
1862 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1863 *domain_name
= centry_string(centry
, mem_ctx
);
1864 *name
= centry_string(centry
, mem_ctx
);
1867 status
= centry
->status
;
1868 centry_free(centry
);
1870 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: "
1871 "%s\n", domain
->name
, nt_errstr(status
) ));
1876 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1878 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1879 TALLOC_CTX
*mem_ctx
,
1880 const struct dom_sid
*sid
,
1883 enum lsa_SidType
*type
)
1888 old_status
= domain
->online
;
1889 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
1891 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
1896 *domain_name
= NULL
;
1898 /* If the seq number check indicated that there is a problem
1899 * with this DC, then return that status... except for
1900 * access_denied. This is special because the dc may be in
1901 * "restrict anonymous = 1" mode, in which case it will deny
1902 * most unauthenticated operations, but *will* allow the LSA
1903 * sid-to-name that we try as a fallback. */
1905 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1906 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1907 return domain
->last_status
;
1909 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1912 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1914 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
1915 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1916 if (!domain
->internal
&& old_status
) {
1917 set_domain_offline(domain
);
1919 if (!domain
->internal
&&
1922 NTSTATUS cache_status
;
1923 cache_status
= wcache_sid_to_name(domain
, sid
, mem_ctx
,
1924 domain_name
, name
, type
);
1925 return cache_status
;
1929 refresh_sequence_number(domain
, false);
1930 if (!NT_STATUS_IS_OK(status
)) {
1933 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
1935 /* We can't save the name to sid mapping here, as with sid history a
1936 * later name2sid would give the wrong sid. */
1941 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
1942 TALLOC_CTX
*mem_ctx
,
1943 const struct dom_sid
*domain_sid
,
1948 enum lsa_SidType
**types
)
1950 struct winbind_cache
*cache
= get_cache(domain
);
1952 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1957 old_status
= domain
->online
;
1958 *domain_name
= NULL
;
1966 if (num_rids
== 0) {
1967 return NT_STATUS_OK
;
1970 *names
= TALLOC_ARRAY(mem_ctx
, char *, num_rids
);
1971 *types
= TALLOC_ARRAY(mem_ctx
, enum lsa_SidType
, num_rids
);
1973 if ((*names
== NULL
) || (*types
== NULL
)) {
1974 result
= NT_STATUS_NO_MEMORY
;
1978 have_mapped
= have_unmapped
= false;
1980 for (i
=0; i
<num_rids
; i
++) {
1982 struct cache_entry
*centry
;
1985 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
1986 result
= NT_STATUS_INTERNAL_ERROR
;
1990 centry
= wcache_fetch(cache
, domain
, "SN/%s",
1991 sid_to_fstring(tmp
, &sid
));
1996 (*types
)[i
] = SID_NAME_UNKNOWN
;
1997 (*names
)[i
] = talloc_strdup(*names
, "");
1999 if (NT_STATUS_IS_OK(centry
->status
)) {
2002 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2004 dom
= centry_string(centry
, mem_ctx
);
2005 if (*domain_name
== NULL
) {
2011 (*names
)[i
] = centry_string(centry
, *names
);
2013 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)) {
2014 have_unmapped
= true;
2017 /* something's definitely wrong */
2018 result
= centry
->status
;
2022 centry_free(centry
);
2026 return NT_STATUS_NONE_MAPPED
;
2028 if (!have_unmapped
) {
2029 return NT_STATUS_OK
;
2031 return STATUS_SOME_UNMAPPED
;
2035 TALLOC_FREE(*names
);
2036 TALLOC_FREE(*types
);
2038 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
2039 rids
, num_rids
, domain_name
,
2042 if (NT_STATUS_EQUAL(result
, NT_STATUS_IO_TIMEOUT
) ||
2043 NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2044 if (!domain
->internal
&& old_status
) {
2045 set_domain_offline(domain
);
2048 !domain
->internal
&&
2051 have_mapped
= have_unmapped
= false;
2053 for (i
=0; i
<num_rids
; i
++) {
2055 struct cache_entry
*centry
;
2058 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2059 result
= NT_STATUS_INTERNAL_ERROR
;
2063 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2064 sid_to_fstring(tmp
, &sid
));
2066 (*types
)[i
] = SID_NAME_UNKNOWN
;
2067 (*names
)[i
] = talloc_strdup(*names
, "");
2071 (*types
)[i
] = SID_NAME_UNKNOWN
;
2072 (*names
)[i
] = talloc_strdup(*names
, "");
2074 if (NT_STATUS_IS_OK(centry
->status
)) {
2077 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
2079 dom
= centry_string(centry
, mem_ctx
);
2080 if (*domain_name
== NULL
) {
2086 (*names
)[i
] = centry_string(centry
, *names
);
2088 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)) {
2089 have_unmapped
= true;
2092 /* something's definitely wrong */
2093 result
= centry
->status
;
2097 centry_free(centry
);
2101 return NT_STATUS_NONE_MAPPED
;
2103 if (!have_unmapped
) {
2104 return NT_STATUS_OK
;
2106 return STATUS_SOME_UNMAPPED
;
2110 None of the queried rids has been found so save all negative entries
2112 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
2113 for (i
= 0; i
< num_rids
; i
++) {
2115 const char *name
= "";
2116 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
2117 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
2119 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2120 return NT_STATUS_INTERNAL_ERROR
;
2123 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2131 Some or all of the queried rids have been found.
2133 if (!NT_STATUS_IS_OK(result
) &&
2134 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
2138 refresh_sequence_number(domain
, false);
2140 for (i
=0; i
<num_rids
; i
++) {
2144 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
2145 result
= NT_STATUS_INTERNAL_ERROR
;
2149 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
2150 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
2152 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
2153 (*names
)[i
], (*types
)[i
]);
2159 TALLOC_FREE(*names
);
2160 TALLOC_FREE(*types
);
2164 NTSTATUS
wcache_query_user(struct winbindd_domain
*domain
,
2165 TALLOC_CTX
*mem_ctx
,
2166 const struct dom_sid
*user_sid
,
2167 struct wbint_userinfo
*info
)
2169 struct winbind_cache
*cache
= get_cache(domain
);
2170 struct cache_entry
*centry
= NULL
;
2174 if (cache
->tdb
== NULL
) {
2175 return NT_STATUS_NOT_FOUND
;
2178 sid_string
= sid_string_tos(user_sid
);
2179 if (sid_string
== NULL
) {
2180 return NT_STATUS_NO_MEMORY
;
2183 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string
);
2184 TALLOC_FREE(sid_string
);
2185 if (centry
== NULL
) {
2186 return NT_STATUS_NOT_FOUND
;
2190 * If we have an access denied cache entry and a cached info3
2191 * in the samlogon cache then do a query. This will force the
2192 * rpc back end to return the info3 data.
2195 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
) &&
2196 netsamlogon_cache_have(user_sid
)) {
2197 DEBUG(10, ("query_user: cached access denied and have cached "
2199 domain
->last_status
= NT_STATUS_OK
;
2200 centry_free(centry
);
2201 return NT_STATUS_NOT_FOUND
;
2204 /* if status is not ok then this is a negative hit
2205 and the rest of the data doesn't matter */
2206 status
= centry
->status
;
2207 if (NT_STATUS_IS_OK(status
)) {
2208 info
->acct_name
= centry_string(centry
, mem_ctx
);
2209 info
->full_name
= centry_string(centry
, mem_ctx
);
2210 info
->homedir
= centry_string(centry
, mem_ctx
);
2211 info
->shell
= centry_string(centry
, mem_ctx
);
2212 info
->primary_gid
= centry_uint32(centry
);
2213 centry_sid(centry
, &info
->user_sid
);
2214 centry_sid(centry
, &info
->group_sid
);
2217 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: "
2218 "%s\n", domain
->name
, nt_errstr(status
) ));
2220 centry_free(centry
);
2224 /* Lookup user information from a rid */
2225 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
2226 TALLOC_CTX
*mem_ctx
,
2227 const struct dom_sid
*user_sid
,
2228 struct wbint_userinfo
*info
)
2233 old_status
= domain
->online
;
2234 status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2235 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2241 /* Return status value returned by seq number check */
2243 if (!NT_STATUS_IS_OK(domain
->last_status
))
2244 return domain
->last_status
;
2246 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
2249 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
2251 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2252 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2253 if (!domain
->internal
&& old_status
) {
2254 set_domain_offline(domain
);
2256 if (!domain
->internal
&&
2259 NTSTATUS cache_status
;
2260 cache_status
= wcache_query_user(domain
, mem_ctx
, user_sid
, info
);
2261 return cache_status
;
2265 refresh_sequence_number(domain
, false);
2266 if (!NT_STATUS_IS_OK(status
)) {
2269 wcache_save_user(domain
, status
, info
);
2274 NTSTATUS
wcache_lookup_usergroups(struct winbindd_domain
*domain
,
2275 TALLOC_CTX
*mem_ctx
,
2276 const struct dom_sid
*user_sid
,
2277 uint32_t *pnum_sids
,
2278 struct dom_sid
**psids
)
2280 struct winbind_cache
*cache
= get_cache(domain
);
2281 struct cache_entry
*centry
= NULL
;
2283 uint32_t i
, num_sids
;
2284 struct dom_sid
*sids
;
2287 if (cache
->tdb
== NULL
) {
2288 return NT_STATUS_NOT_FOUND
;
2291 centry
= wcache_fetch(cache
, domain
, "UG/%s",
2292 sid_to_fstring(sid_string
, user_sid
));
2293 if (centry
== NULL
) {
2294 return NT_STATUS_NOT_FOUND
;
2297 /* If we have an access denied cache entry and a cached info3 in the
2298 samlogon cache then do a query. This will force the rpc back end
2299 to return the info3 data. */
2301 if (NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)
2302 && netsamlogon_cache_have(user_sid
)) {
2303 DEBUG(10, ("lookup_usergroups: cached access denied and have "
2305 domain
->last_status
= NT_STATUS_OK
;
2306 centry_free(centry
);
2307 return NT_STATUS_NOT_FOUND
;
2310 num_sids
= centry_uint32(centry
);
2311 sids
= talloc_array(mem_ctx
, struct dom_sid
, num_sids
);
2313 centry_free(centry
);
2314 return NT_STATUS_NO_MEMORY
;
2317 for (i
=0; i
<num_sids
; i
++) {
2318 centry_sid(centry
, &sids
[i
]);
2321 status
= centry
->status
;
2323 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s "
2324 "status: %s\n", domain
->name
, nt_errstr(status
)));
2326 centry_free(centry
);
2328 *pnum_sids
= num_sids
;
2333 /* Lookup groups a user is a member of. */
2334 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
2335 TALLOC_CTX
*mem_ctx
,
2336 const struct dom_sid
*user_sid
,
2337 uint32
*num_groups
, struct dom_sid
**user_gids
)
2339 struct cache_entry
*centry
= NULL
;
2345 old_status
= domain
->online
;
2346 status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2347 num_groups
, user_gids
);
2348 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2353 (*user_gids
) = NULL
;
2355 /* Return status value returned by seq number check */
2357 if (!NT_STATUS_IS_OK(domain
->last_status
))
2358 return domain
->last_status
;
2360 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2363 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
2365 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2366 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2367 if (!domain
->internal
&& old_status
) {
2368 set_domain_offline(domain
);
2370 if (!domain
->internal
&&
2373 NTSTATUS cache_status
;
2374 cache_status
= wcache_lookup_usergroups(domain
, mem_ctx
, user_sid
,
2375 num_groups
, user_gids
);
2376 return cache_status
;
2379 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
2383 refresh_sequence_number(domain
, false);
2384 if (!NT_STATUS_IS_OK(status
)) {
2387 centry
= centry_start(domain
, status
);
2391 centry_put_uint32(centry
, *num_groups
);
2392 for (i
=0; i
<(*num_groups
); i
++) {
2393 centry_put_sid(centry
, &(*user_gids
)[i
]);
2396 centry_end(centry
, "UG/%s", sid_to_fstring(sid_string
, user_sid
));
2397 centry_free(centry
);
2403 static char *wcache_make_sidlist(TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2404 const struct dom_sid
*sids
)
2409 sidlist
= talloc_strdup(mem_ctx
, "");
2410 if (sidlist
== NULL
) {
2413 for (i
=0; i
<num_sids
; i
++) {
2415 sidlist
= talloc_asprintf_append_buffer(
2416 sidlist
, "/%s", sid_to_fstring(tmp
, &sids
[i
]));
2417 if (sidlist
== NULL
) {
2424 NTSTATUS
wcache_lookup_useraliases(struct winbindd_domain
*domain
,
2425 TALLOC_CTX
*mem_ctx
, uint32_t num_sids
,
2426 const struct dom_sid
*sids
,
2427 uint32_t *pnum_aliases
, uint32_t **paliases
)
2429 struct winbind_cache
*cache
= get_cache(domain
);
2430 struct cache_entry
*centry
= NULL
;
2431 uint32_t num_aliases
;
2437 if (cache
->tdb
== NULL
) {
2438 return NT_STATUS_NOT_FOUND
;
2441 if (num_sids
== 0) {
2444 return NT_STATUS_OK
;
2447 /* We need to cache indexed by the whole list of SIDs, the aliases
2448 * resulting might come from any of the SIDs. */
2450 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2451 if (sidlist
== NULL
) {
2452 return NT_STATUS_NO_MEMORY
;
2455 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2456 TALLOC_FREE(sidlist
);
2457 if (centry
== NULL
) {
2458 return NT_STATUS_NOT_FOUND
;
2461 num_aliases
= centry_uint32(centry
);
2462 aliases
= talloc_array(mem_ctx
, uint32_t, num_aliases
);
2463 if (aliases
== NULL
) {
2464 centry_free(centry
);
2465 return NT_STATUS_NO_MEMORY
;
2468 for (i
=0; i
<num_aliases
; i
++) {
2469 aliases
[i
] = centry_uint32(centry
);
2472 status
= centry
->status
;
2474 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2475 "status %s\n", domain
->name
, nt_errstr(status
)));
2477 centry_free(centry
);
2479 *pnum_aliases
= num_aliases
;
2480 *paliases
= aliases
;
2485 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
2486 TALLOC_CTX
*mem_ctx
,
2487 uint32 num_sids
, const struct dom_sid
*sids
,
2488 uint32
*num_aliases
, uint32
**alias_rids
)
2490 struct cache_entry
*centry
= NULL
;
2496 old_status
= domain
->online
;
2497 status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
2498 num_aliases
, alias_rids
);
2499 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2504 (*alias_rids
) = NULL
;
2506 if (!NT_STATUS_IS_OK(domain
->last_status
))
2507 return domain
->last_status
;
2509 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2510 "for domain %s\n", domain
->name
));
2512 sidlist
= wcache_make_sidlist(talloc_tos(), num_sids
, sids
);
2513 if (sidlist
== NULL
) {
2514 return NT_STATUS_NO_MEMORY
;
2517 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2519 num_aliases
, alias_rids
);
2521 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2522 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2523 if (!domain
->internal
&& old_status
) {
2524 set_domain_offline(domain
);
2526 if (!domain
->internal
&&
2529 NTSTATUS cache_status
;
2530 cache_status
= wcache_lookup_useraliases(domain
, mem_ctx
, num_sids
,
2531 sids
, num_aliases
, alias_rids
);
2532 return cache_status
;
2536 refresh_sequence_number(domain
, false);
2537 if (!NT_STATUS_IS_OK(status
)) {
2540 centry
= centry_start(domain
, status
);
2543 centry_put_uint32(centry
, *num_aliases
);
2544 for (i
=0; i
<(*num_aliases
); i
++)
2545 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2546 centry_end(centry
, "UA%s", sidlist
);
2547 centry_free(centry
);
2553 NTSTATUS
wcache_lookup_groupmem(struct winbindd_domain
*domain
,
2554 TALLOC_CTX
*mem_ctx
,
2555 const struct dom_sid
*group_sid
,
2556 uint32_t *num_names
,
2557 struct dom_sid
**sid_mem
, char ***names
,
2558 uint32_t **name_types
)
2560 struct winbind_cache
*cache
= get_cache(domain
);
2561 struct cache_entry
*centry
= NULL
;
2566 if (cache
->tdb
== NULL
) {
2567 return NT_STATUS_NOT_FOUND
;
2570 sid_string
= sid_string_tos(group_sid
);
2571 if (sid_string
== NULL
) {
2572 return NT_STATUS_NO_MEMORY
;
2575 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_string
);
2576 TALLOC_FREE(sid_string
);
2577 if (centry
== NULL
) {
2578 return NT_STATUS_NOT_FOUND
;
2585 *num_names
= centry_uint32(centry
);
2586 if (*num_names
== 0) {
2587 centry_free(centry
);
2588 return NT_STATUS_OK
;
2591 *sid_mem
= talloc_array(mem_ctx
, struct dom_sid
, *num_names
);
2592 *names
= talloc_array(mem_ctx
, char *, *num_names
);
2593 *name_types
= talloc_array(mem_ctx
, uint32
, *num_names
);
2595 if ((*sid_mem
== NULL
) || (*names
== NULL
) || (*name_types
== NULL
)) {
2596 TALLOC_FREE(*sid_mem
);
2597 TALLOC_FREE(*names
);
2598 TALLOC_FREE(*name_types
);
2599 centry_free(centry
);
2600 return NT_STATUS_NO_MEMORY
;
2603 for (i
=0; i
<(*num_names
); i
++) {
2604 centry_sid(centry
, &(*sid_mem
)[i
]);
2605 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2606 (*name_types
)[i
] = centry_uint32(centry
);
2609 status
= centry
->status
;
2611 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s "
2612 "status: %s\n", domain
->name
, nt_errstr(status
)));
2614 centry_free(centry
);
2618 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
2619 TALLOC_CTX
*mem_ctx
,
2620 const struct dom_sid
*group_sid
,
2621 enum lsa_SidType type
,
2623 struct dom_sid
**sid_mem
, char ***names
,
2624 uint32
**name_types
)
2626 struct cache_entry
*centry
= NULL
;
2632 old_status
= domain
->online
;
2633 status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2634 sid_mem
, names
, name_types
);
2635 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
2642 (*name_types
) = NULL
;
2644 /* Return status value returned by seq number check */
2646 if (!NT_STATUS_IS_OK(domain
->last_status
))
2647 return domain
->last_status
;
2649 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2652 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
,
2654 sid_mem
, names
, name_types
);
2656 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2657 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2658 if (!domain
->internal
&& old_status
) {
2659 set_domain_offline(domain
);
2661 if (!domain
->internal
&&
2664 NTSTATUS cache_status
;
2665 cache_status
= wcache_lookup_groupmem(domain
, mem_ctx
, group_sid
,
2666 num_names
, sid_mem
, names
,
2668 return cache_status
;
2672 refresh_sequence_number(domain
, false);
2673 if (!NT_STATUS_IS_OK(status
)) {
2676 centry
= centry_start(domain
, status
);
2679 centry_put_uint32(centry
, *num_names
);
2680 for (i
=0; i
<(*num_names
); i
++) {
2681 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2682 centry_put_string(centry
, (*names
)[i
]);
2683 centry_put_uint32(centry
, (*name_types
)[i
]);
2685 centry_end(centry
, "GM/%s", sid_to_fstring(sid_string
, group_sid
));
2686 centry_free(centry
);
2692 /* find the sequence number for a domain */
2693 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
2695 refresh_sequence_number(domain
, false);
2697 *seq
= domain
->sequence_number
;
2699 return NT_STATUS_OK
;
2702 /* enumerate trusted domains
2703 * (we need to have the list of trustdoms in the cache when we go offline) -
2705 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
2706 TALLOC_CTX
*mem_ctx
,
2707 struct netr_DomainTrustList
*trusts
)
2710 struct winbind_cache
*cache
;
2711 struct winbindd_tdc_domain
*dom_list
= NULL
;
2712 size_t num_domains
= 0;
2713 bool retval
= false;
2717 old_status
= domain
->online
;
2719 trusts
->array
= NULL
;
2721 cache
= get_cache(domain
);
2722 if (!cache
|| !cache
->tdb
) {
2726 if (domain
->online
) {
2730 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2731 if (!retval
|| !num_domains
|| !dom_list
) {
2732 TALLOC_FREE(dom_list
);
2737 trusts
->array
= TALLOC_ZERO_ARRAY(mem_ctx
, struct netr_DomainTrust
, num_domains
);
2738 if (!trusts
->array
) {
2739 TALLOC_FREE(dom_list
);
2740 return NT_STATUS_NO_MEMORY
;
2743 for (i
= 0; i
< num_domains
; i
++) {
2744 struct netr_DomainTrust
*trust
;
2745 struct dom_sid
*sid
;
2746 struct winbindd_domain
*dom
;
2748 dom
= find_domain_from_name_noinit(dom_list
[i
].domain_name
);
2749 if (dom
&& dom
->internal
) {
2753 trust
= &trusts
->array
[trusts
->count
];
2754 trust
->netbios_name
= talloc_strdup(trusts
->array
, dom_list
[i
].domain_name
);
2755 trust
->dns_name
= talloc_strdup(trusts
->array
, dom_list
[i
].dns_name
);
2756 sid
= talloc(trusts
->array
, struct dom_sid
);
2757 if (!trust
->netbios_name
|| !trust
->dns_name
||
2759 TALLOC_FREE(dom_list
);
2760 TALLOC_FREE(trusts
->array
);
2761 return NT_STATUS_NO_MEMORY
;
2764 trust
->trust_flags
= dom_list
[i
].trust_flags
;
2765 trust
->trust_attributes
= dom_list
[i
].trust_attribs
;
2766 trust
->trust_type
= dom_list
[i
].trust_type
;
2767 sid_copy(sid
, &dom_list
[i
].sid
);
2772 TALLOC_FREE(dom_list
);
2773 return NT_STATUS_OK
;
2776 /* Return status value returned by seq number check */
2778 if (!NT_STATUS_IS_OK(domain
->last_status
))
2779 return domain
->last_status
;
2781 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2784 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, trusts
);
2786 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2787 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2788 if (!domain
->internal
&& old_status
) {
2789 set_domain_offline(domain
);
2791 if (!domain
->internal
&&
2794 retval
= wcache_tdc_fetch_list(&dom_list
, &num_domains
);
2795 if (retval
&& num_domains
&& dom_list
) {
2796 TALLOC_FREE(trusts
->array
);
2798 goto do_fetch_cache
;
2802 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2803 * so that the generic centry handling still applies correctly -
2806 if (!NT_STATUS_IS_ERR(status
)) {
2807 status
= NT_STATUS_OK
;
2812 /* get lockout policy */
2813 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
2814 TALLOC_CTX
*mem_ctx
,
2815 struct samr_DomInfo12
*policy
)
2817 struct winbind_cache
*cache
= get_cache(domain
);
2818 struct cache_entry
*centry
= NULL
;
2822 old_status
= domain
->online
;
2826 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2832 policy
->lockout_duration
= centry_nttime(centry
);
2833 policy
->lockout_window
= centry_nttime(centry
);
2834 policy
->lockout_threshold
= centry_uint16(centry
);
2836 status
= centry
->status
;
2838 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2839 domain
->name
, nt_errstr(status
) ));
2841 centry_free(centry
);
2845 ZERO_STRUCTP(policy
);
2847 /* Return status value returned by seq number check */
2849 if (!NT_STATUS_IS_OK(domain
->last_status
))
2850 return domain
->last_status
;
2852 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2855 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2857 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2858 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2859 if (!domain
->internal
&& old_status
) {
2860 set_domain_offline(domain
);
2863 !domain
->internal
&&
2866 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2868 goto do_fetch_cache
;
2873 refresh_sequence_number(domain
, false);
2874 if (!NT_STATUS_IS_OK(status
)) {
2877 wcache_save_lockout_policy(domain
, status
, policy
);
2882 /* get password policy */
2883 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
2884 TALLOC_CTX
*mem_ctx
,
2885 struct samr_DomInfo1
*policy
)
2887 struct winbind_cache
*cache
= get_cache(domain
);
2888 struct cache_entry
*centry
= NULL
;
2892 old_status
= domain
->online
;
2896 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2902 policy
->min_password_length
= centry_uint16(centry
);
2903 policy
->password_history_length
= centry_uint16(centry
);
2904 policy
->password_properties
= centry_uint32(centry
);
2905 policy
->max_password_age
= centry_nttime(centry
);
2906 policy
->min_password_age
= centry_nttime(centry
);
2908 status
= centry
->status
;
2910 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2911 domain
->name
, nt_errstr(status
) ));
2913 centry_free(centry
);
2917 ZERO_STRUCTP(policy
);
2919 /* Return status value returned by seq number check */
2921 if (!NT_STATUS_IS_OK(domain
->last_status
))
2922 return domain
->last_status
;
2924 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2927 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
2929 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
2930 NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2931 if (!domain
->internal
&& old_status
) {
2932 set_domain_offline(domain
);
2935 !domain
->internal
&&
2938 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2940 goto do_fetch_cache
;
2945 refresh_sequence_number(domain
, false);
2946 if (!NT_STATUS_IS_OK(status
)) {
2949 wcache_save_password_policy(domain
, status
, policy
);
2955 /* Invalidate cached user and group lists coherently */
2957 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2960 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
2961 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
2962 tdb_delete(the_tdb
, kbuf
);
2967 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2969 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
2970 struct netr_SamInfo3
*info3
)
2973 fstring key_str
, sid_string
;
2974 struct winbind_cache
*cache
;
2976 /* dont clear cached U/SID and UG/SID entries when we want to logon
2979 if (lp_winbind_offline_logon()) {
2986 cache
= get_cache(domain
);
2992 sid_compose(&sid
, info3
->base
.domain_sid
, info3
->base
.rid
);
2994 /* Clear U/SID cache entry */
2995 fstr_sprintf(key_str
, "U/%s", sid_to_fstring(sid_string
, &sid
));
2996 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
2997 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
2999 /* Clear UG/SID cache entry */
3000 fstr_sprintf(key_str
, "UG/%s", sid_to_fstring(sid_string
, &sid
));
3001 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
3002 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3004 /* Samba/winbindd never needs this. */
3005 netsamlogon_clear_cached_user(info3
);
3008 bool wcache_invalidate_cache(void)
3010 struct winbindd_domain
*domain
;
3012 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3013 struct winbind_cache
*cache
= get_cache(domain
);
3015 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3016 "entries for %s\n", domain
->name
));
3019 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3028 bool wcache_invalidate_cache_noinit(void)
3030 struct winbindd_domain
*domain
;
3032 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
3033 struct winbind_cache
*cache
;
3035 /* Skip uninitialized domains. */
3036 if (!domain
->initialized
&& !domain
->internal
) {
3040 cache
= get_cache(domain
);
3042 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
3043 "entries for %s\n", domain
->name
));
3046 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
3048 * Flushing cache has nothing to with domains.
3049 * return here if we successfully flushed once.
3050 * To avoid unnecessary traversing the cache.
3061 bool init_wcache(void)
3063 if (wcache
== NULL
) {
3064 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
3065 ZERO_STRUCTP(wcache
);
3068 if (wcache
->tdb
!= NULL
)
3071 /* when working offline we must not clear the cache on restart */
3072 wcache
->tdb
= tdb_open_log(cache_path("winbindd_cache.tdb"),
3073 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3074 lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
3075 O_RDWR
|O_CREAT
, 0600);
3077 if (wcache
->tdb
== NULL
) {
3078 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3085 /************************************************************************
3086 This is called by the parent to initialize the cache file.
3087 We don't need sophisticated locking here as we know we're the
3089 ************************************************************************/
3091 bool initialize_winbindd_cache(void)
3093 bool cache_bad
= true;
3096 if (!init_wcache()) {
3097 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
3101 /* Check version number. */
3102 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
3103 vers
== WINBINDD_CACHE_VERSION
) {
3108 DEBUG(0,("initialize_winbindd_cache: clearing cache "
3109 "and re-creating with version number %d\n",
3110 WINBINDD_CACHE_VERSION
));
3112 tdb_close(wcache
->tdb
);
3115 if (unlink(cache_path("winbindd_cache.tdb")) == -1) {
3116 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
3117 cache_path("winbindd_cache.tdb"),
3121 if (!init_wcache()) {
3122 DEBUG(0,("initialize_winbindd_cache: re-initialization "
3123 "init_wcache failed.\n"));
3127 /* Write the version. */
3128 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
3129 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
3130 tdb_errorstr(wcache
->tdb
) ));
3135 tdb_close(wcache
->tdb
);
3140 void close_winbindd_cache(void)
3146 tdb_close(wcache
->tdb
);
3151 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*sid
,
3152 char **domain_name
, char **name
,
3153 enum lsa_SidType
*type
)
3155 struct winbindd_domain
*domain
;
3158 domain
= find_lookup_domain_from_sid(sid
);
3159 if (domain
== NULL
) {
3162 status
= wcache_sid_to_name(domain
, sid
, mem_ctx
, domain_name
, name
,
3164 return NT_STATUS_IS_OK(status
);
3167 bool lookup_cached_name(const char *domain_name
,
3169 struct dom_sid
*sid
,
3170 enum lsa_SidType
*type
)
3172 struct winbindd_domain
*domain
;
3174 bool original_online_state
;
3176 domain
= find_lookup_domain_from_name(domain_name
);
3177 if (domain
== NULL
) {
3181 /* If we are doing a cached logon, temporarily set the domain
3182 offline so the cache won't expire the entry */
3184 original_online_state
= domain
->online
;
3185 domain
->online
= false;
3186 status
= wcache_name_to_sid(domain
, domain_name
, name
, sid
, type
);
3187 domain
->online
= original_online_state
;
3189 return NT_STATUS_IS_OK(status
);
3192 void cache_name2sid(struct winbindd_domain
*domain
,
3193 const char *domain_name
, const char *name
,
3194 enum lsa_SidType type
, const struct dom_sid
*sid
)
3196 refresh_sequence_number(domain
, false);
3197 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
3202 * The original idea that this cache only contains centries has
3203 * been blurred - now other stuff gets put in here. Ensure we
3204 * ignore these things on cleanup.
3207 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
3208 TDB_DATA dbuf
, void *state
)
3210 struct cache_entry
*centry
;
3212 if (is_non_centry_key(kbuf
)) {
3216 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
3221 if (!NT_STATUS_IS_OK(centry
->status
)) {
3222 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
3223 tdb_delete(the_tdb
, kbuf
);
3226 centry_free(centry
);
3230 /* flush the cache */
3231 void wcache_flush_cache(void)
3236 tdb_close(wcache
->tdb
);
3239 if (!winbindd_use_cache()) {
3243 /* when working offline we must not clear the cache on restart */
3244 wcache
->tdb
= tdb_open_log(cache_path("winbindd_cache.tdb"),
3245 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3246 lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
3247 O_RDWR
|O_CREAT
, 0600);
3250 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
3254 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
3256 DEBUG(10,("wcache_flush_cache success\n"));
3259 /* Count cached creds */
3261 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3264 int *cred_count
= (int*)state
;
3266 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3272 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
3274 struct winbind_cache
*cache
= get_cache(domain
);
3279 return NT_STATUS_INTERNAL_DB_ERROR
;
3282 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
3284 return NT_STATUS_OK
;
3288 struct cred_list
*prev
, *next
;
3293 static struct cred_list
*wcache_cred_list
;
3295 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
3298 struct cred_list
*cred
;
3300 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
3302 cred
= SMB_MALLOC_P(struct cred_list
);
3304 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
3310 /* save a copy of the key */
3312 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
3313 DLIST_ADD(wcache_cred_list
, cred
);
3319 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const struct dom_sid
*sid
)
3321 struct winbind_cache
*cache
= get_cache(domain
);
3324 struct cred_list
*cred
, *oldest
= NULL
;
3327 return NT_STATUS_INTERNAL_DB_ERROR
;
3330 /* we possibly already have an entry */
3331 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
3333 fstring key_str
, tmp
;
3335 DEBUG(11,("we already have an entry, deleting that\n"));
3337 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
3339 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
3341 return NT_STATUS_OK
;
3344 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
3346 return NT_STATUS_OK
;
3347 } else if ((ret
== -1) || (wcache_cred_list
== NULL
)) {
3348 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3351 ZERO_STRUCTP(oldest
);
3353 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
3358 data
= tdb_fetch(cache
->tdb
, string_tdb_data(cred
->name
));
3360 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
3362 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
3366 t
= IVAL(data
.dptr
, 0);
3367 SAFE_FREE(data
.dptr
);
3370 oldest
= SMB_MALLOC_P(struct cred_list
);
3371 if (oldest
== NULL
) {
3372 status
= NT_STATUS_NO_MEMORY
;
3376 fstrcpy(oldest
->name
, cred
->name
);
3377 oldest
->created
= t
;
3381 if (t
< oldest
->created
) {
3382 fstrcpy(oldest
->name
, cred
->name
);
3383 oldest
->created
= t
;
3387 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3388 status
= NT_STATUS_OK
;
3390 status
= NT_STATUS_UNSUCCESSFUL
;
3393 SAFE_FREE(wcache_cred_list
);
3399 /* Change the global online/offline state. */
3400 bool set_global_winbindd_state_offline(void)
3404 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3406 /* Only go offline if someone has created
3407 the key "WINBINDD_OFFLINE" in the cache tdb. */
3409 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3410 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3414 if (!lp_winbind_offline_logon()) {
3415 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3419 if (global_winbindd_offline_state
) {
3420 /* Already offline. */
3424 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
3426 if (!data
.dptr
|| data
.dsize
!= 4) {
3427 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3428 SAFE_FREE(data
.dptr
);
3431 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3432 global_winbindd_offline_state
= true;
3433 SAFE_FREE(data
.dptr
);
3438 void set_global_winbindd_state_online(void)
3440 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3442 if (!lp_winbind_offline_logon()) {
3443 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3447 if (!global_winbindd_offline_state
) {
3448 /* Already online. */
3451 global_winbindd_offline_state
= false;
3457 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3458 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3461 bool get_global_winbindd_state_offline(void)
3463 return global_winbindd_offline_state
;
3466 /***********************************************************************
3467 Validate functions for all possible cache tdb keys.
3468 ***********************************************************************/
3470 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3471 struct tdb_validation_status
*state
)
3473 struct cache_entry
*centry
;
3475 centry
= SMB_XMALLOC_P(struct cache_entry
);
3476 centry
->data
= (unsigned char *)memdup(data
.dptr
, data
.dsize
);
3477 if (!centry
->data
) {
3481 centry
->len
= data
.dsize
;
3484 if (centry
->len
< 8) {
3485 /* huh? corrupt cache? */
3486 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr
));
3487 centry_free(centry
);
3488 state
->bad_entry
= true;
3489 state
->success
= false;
3493 centry
->status
= NT_STATUS(centry_uint32(centry
));
3494 centry
->sequence_number
= centry_uint32(centry
);
3498 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3499 struct tdb_validation_status
*state
)
3501 if (dbuf
.dsize
!= 8) {
3502 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3503 keystr
, (unsigned int)dbuf
.dsize
));
3504 state
->bad_entry
= true;
3510 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3511 struct tdb_validation_status
*state
)
3513 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3518 (void)centry_uint32(centry
);
3519 if (NT_STATUS_IS_OK(centry
->status
)) {
3521 (void)centry_sid(centry
, &sid
);
3524 centry_free(centry
);
3526 if (!(state
->success
)) {
3529 DEBUG(10,("validate_ns: %s ok\n", keystr
));
3533 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3534 struct tdb_validation_status
*state
)
3536 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3541 if (NT_STATUS_IS_OK(centry
->status
)) {
3542 (void)centry_uint32(centry
);
3543 (void)centry_string(centry
, mem_ctx
);
3544 (void)centry_string(centry
, mem_ctx
);
3547 centry_free(centry
);
3549 if (!(state
->success
)) {
3552 DEBUG(10,("validate_sn: %s ok\n", keystr
));
3556 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3557 struct tdb_validation_status
*state
)
3559 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3566 (void)centry_string(centry
, mem_ctx
);
3567 (void)centry_string(centry
, mem_ctx
);
3568 (void)centry_string(centry
, mem_ctx
);
3569 (void)centry_string(centry
, mem_ctx
);
3570 (void)centry_uint32(centry
);
3571 (void)centry_sid(centry
, &sid
);
3572 (void)centry_sid(centry
, &sid
);
3574 centry_free(centry
);
3576 if (!(state
->success
)) {
3579 DEBUG(10,("validate_u: %s ok\n", keystr
));
3583 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3584 struct tdb_validation_status
*state
)
3586 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3592 (void)centry_nttime(centry
);
3593 (void)centry_nttime(centry
);
3594 (void)centry_uint16(centry
);
3596 centry_free(centry
);
3598 if (!(state
->success
)) {
3601 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3605 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3606 struct tdb_validation_status
*state
)
3608 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3614 (void)centry_uint16(centry
);
3615 (void)centry_uint16(centry
);
3616 (void)centry_uint32(centry
);
3617 (void)centry_nttime(centry
);
3618 (void)centry_nttime(centry
);
3620 centry_free(centry
);
3622 if (!(state
->success
)) {
3625 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3629 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3630 struct tdb_validation_status
*state
)
3632 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3638 (void)centry_time(centry
);
3639 (void)centry_hash16(centry
, mem_ctx
);
3641 /* We only have 17 bytes more data in the salted cred case. */
3642 if (centry
->len
- centry
->ofs
== 17) {
3643 (void)centry_hash16(centry
, mem_ctx
);
3646 centry_free(centry
);
3648 if (!(state
->success
)) {
3651 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3655 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3656 struct tdb_validation_status
*state
)
3658 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3659 int32 num_entries
, i
;
3665 num_entries
= (int32
)centry_uint32(centry
);
3667 for (i
=0; i
< num_entries
; i
++) {
3669 (void)centry_string(centry
, mem_ctx
);
3670 (void)centry_string(centry
, mem_ctx
);
3671 (void)centry_string(centry
, mem_ctx
);
3672 (void)centry_string(centry
, mem_ctx
);
3673 (void)centry_sid(centry
, &sid
);
3674 (void)centry_sid(centry
, &sid
);
3677 centry_free(centry
);
3679 if (!(state
->success
)) {
3682 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3686 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3687 struct tdb_validation_status
*state
)
3689 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3690 int32 num_entries
, i
;
3696 num_entries
= centry_uint32(centry
);
3698 for (i
=0; i
< num_entries
; i
++) {
3699 (void)centry_string(centry
, mem_ctx
);
3700 (void)centry_string(centry
, mem_ctx
);
3701 (void)centry_uint32(centry
);
3704 centry_free(centry
);
3706 if (!(state
->success
)) {
3709 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3713 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3714 struct tdb_validation_status
*state
)
3716 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3717 int32 num_groups
, i
;
3723 num_groups
= centry_uint32(centry
);
3725 for (i
=0; i
< num_groups
; i
++) {
3727 centry_sid(centry
, &sid
);
3730 centry_free(centry
);
3732 if (!(state
->success
)) {
3735 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3739 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3740 struct tdb_validation_status
*state
)
3742 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3743 int32 num_aliases
, i
;
3749 num_aliases
= centry_uint32(centry
);
3751 for (i
=0; i
< num_aliases
; i
++) {
3752 (void)centry_uint32(centry
);
3755 centry_free(centry
);
3757 if (!(state
->success
)) {
3760 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3764 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3765 struct tdb_validation_status
*state
)
3767 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3774 num_names
= centry_uint32(centry
);
3776 for (i
=0; i
< num_names
; i
++) {
3778 centry_sid(centry
, &sid
);
3779 (void)centry_string(centry
, mem_ctx
);
3780 (void)centry_uint32(centry
);
3783 centry_free(centry
);
3785 if (!(state
->success
)) {
3788 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3792 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3793 struct tdb_validation_status
*state
)
3795 /* Can't say anything about this other than must be nonzero. */
3796 if (dbuf
.dsize
== 0) {
3797 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3799 state
->bad_entry
= true;
3800 state
->success
= false;
3804 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3808 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3809 struct tdb_validation_status
*state
)
3811 /* Can't say anything about this other than must be nonzero. */
3812 if (dbuf
.dsize
== 0) {
3813 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3815 state
->bad_entry
= true;
3816 state
->success
= false;
3820 DEBUG(10,("validate_de: %s ok\n", keystr
));
3824 static int validate_pwinfo(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3825 TDB_DATA dbuf
, struct tdb_validation_status
*state
)
3827 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3833 (void)centry_string(centry
, mem_ctx
);
3834 (void)centry_string(centry
, mem_ctx
);
3835 (void)centry_string(centry
, mem_ctx
);
3836 (void)centry_uint32(centry
);
3838 centry_free(centry
);
3840 if (!(state
->success
)) {
3843 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3847 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3849 struct tdb_validation_status
*state
)
3851 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3857 (void)centry_string( centry
, mem_ctx
);
3859 centry_free(centry
);
3861 if (!(state
->success
)) {
3864 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3868 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3870 struct tdb_validation_status
*state
)
3872 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3878 (void)centry_string( centry
, mem_ctx
);
3880 centry_free(centry
);
3882 if (!(state
->success
)) {
3885 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3889 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3891 struct tdb_validation_status
*state
)
3893 if (dbuf
.dsize
== 0) {
3894 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3895 "key %s (len ==0) ?\n", keystr
));
3896 state
->bad_entry
= true;
3897 state
->success
= false;
3901 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3902 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3906 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3907 struct tdb_validation_status
*state
)
3909 if (dbuf
.dsize
!= 4) {
3910 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3911 keystr
, (unsigned int)dbuf
.dsize
));
3912 state
->bad_entry
= true;
3913 state
->success
= false;
3916 DEBUG(10,("validate_offline: %s ok\n", keystr
));
3920 static int validate_ndr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3921 struct tdb_validation_status
*state
)
3924 * Ignore validation for now. The proper way to do this is with a
3925 * checksum. Just pure parsing does not really catch much.
3930 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3931 struct tdb_validation_status
*state
)
3933 if (dbuf
.dsize
!= 4) {
3934 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3935 "key %s (len %u != 4) ?\n",
3936 keystr
, (unsigned int)dbuf
.dsize
));
3937 state
->bad_entry
= true;
3938 state
->success
= false;
3942 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
3946 /***********************************************************************
3947 A list of all possible cache tdb keys with associated validation
3949 ***********************************************************************/
3951 struct key_val_struct
{
3952 const char *keyname
;
3953 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
3955 {"SEQNUM/", validate_seqnum
},
3956 {"NS/", validate_ns
},
3957 {"SN/", validate_sn
},
3959 {"LOC_POL/", validate_loc_pol
},
3960 {"PWD_POL/", validate_pwd_pol
},
3961 {"CRED/", validate_cred
},
3962 {"UL/", validate_ul
},
3963 {"GL/", validate_gl
},
3964 {"UG/", validate_ug
},
3965 {"UA", validate_ua
},
3966 {"GM/", validate_gm
},
3967 {"DR/", validate_dr
},
3968 {"DE/", validate_de
},
3969 {"NSS/PWINFO/", validate_pwinfo
},
3970 {"TRUSTDOMCACHE/", validate_trustdomcache
},
3971 {"NSS/NA/", validate_nss_na
},
3972 {"NSS/AN/", validate_nss_an
},
3973 {"WINBINDD_OFFLINE", validate_offline
},
3974 {"NDR/", validate_ndr
},
3975 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
3979 /***********************************************************************
3980 Function to look at every entry in the tdb and validate it as far as
3982 ***********************************************************************/
3984 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
3987 unsigned int max_key_len
= 1024;
3988 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
3990 /* Paranoia check. */
3991 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0) {
3992 max_key_len
= 1024 * 1024;
3994 if (kbuf
.dsize
> max_key_len
) {
3995 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
3997 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
4001 for (i
= 0; key_val
[i
].keyname
; i
++) {
4002 size_t namelen
= strlen(key_val
[i
].keyname
);
4003 if (kbuf
.dsize
>= namelen
&& (
4004 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
4005 TALLOC_CTX
*mem_ctx
;
4009 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
4013 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
4014 keystr
[kbuf
.dsize
] = '\0';
4016 mem_ctx
= talloc_init("validate_ctx");
4022 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
4026 talloc_destroy(mem_ctx
);
4031 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
4032 dump_data(0, (uint8
*)kbuf
.dptr
, kbuf
.dsize
);
4033 DEBUG(0,("data :\n"));
4034 dump_data(0, (uint8
*)dbuf
.dptr
, dbuf
.dsize
);
4035 v_state
->unknown_key
= true;
4036 v_state
->success
= false;
4037 return 1; /* terminate. */
4040 static void validate_panic(const char *const why
)
4042 DEBUG(0,("validating cache: would panic %s\n", why
));
4043 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
4047 /***********************************************************************
4048 Try and validate every entry in the winbindd cache. If we fail here,
4049 delete the cache tdb and return non-zero.
4050 ***********************************************************************/
4052 int winbindd_validate_cache(void)
4055 const char *tdb_path
= cache_path("winbindd_cache.tdb");
4056 TDB_CONTEXT
*tdb
= NULL
;
4058 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4059 smb_panic_fn
= validate_panic
;
4062 tdb
= tdb_open_log(tdb_path
,
4063 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
4064 ( lp_winbind_offline_logon()
4066 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
4070 DEBUG(0, ("winbindd_validate_cache: "
4071 "error opening/initializing tdb\n"));
4076 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
4079 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
4080 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
4085 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
4086 smb_panic_fn
= smb_panic
;
4090 /***********************************************************************
4091 Try and validate every entry in the winbindd cache.
4092 ***********************************************************************/
4094 int winbindd_validate_cache_nobackup(void)
4097 const char *tdb_path
= cache_path("winbindd_cache.tdb");
4099 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
4100 smb_panic_fn
= validate_panic
;
4103 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
4104 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
4106 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
4110 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
4114 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
4116 smb_panic_fn
= smb_panic
;
4120 bool winbindd_cache_validate_and_initialize(void)
4122 close_winbindd_cache();
4124 if (lp_winbind_offline_logon()) {
4125 if (winbindd_validate_cache() < 0) {
4126 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
4127 "could be restored.\n"));
4131 return initialize_winbindd_cache();
4134 /*********************************************************************
4135 ********************************************************************/
4137 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
4138 struct winbindd_tdc_domain
**domains
,
4139 size_t *num_domains
)
4141 struct winbindd_tdc_domain
*list
= NULL
;
4144 bool set_only
= false;
4146 /* don't allow duplicates */
4151 for ( i
=0; i
< (*num_domains
); i
++ ) {
4152 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
4153 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
4164 list
= TALLOC_ARRAY( NULL
, struct winbindd_tdc_domain
, 1 );
4167 list
= TALLOC_REALLOC_ARRAY( *domains
, *domains
,
4168 struct winbindd_tdc_domain
,
4173 ZERO_STRUCT( list
[idx
] );
4179 list
[idx
].domain_name
= talloc_strdup( list
, new_dom
->name
);
4180 list
[idx
].dns_name
= talloc_strdup( list
, new_dom
->alt_name
);
4182 if ( !is_null_sid( &new_dom
->sid
) ) {
4183 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
4185 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
4188 if ( new_dom
->domain_flags
!= 0x0 )
4189 list
[idx
].trust_flags
= new_dom
->domain_flags
;
4191 if ( new_dom
->domain_type
!= 0x0 )
4192 list
[idx
].trust_type
= new_dom
->domain_type
;
4194 if ( new_dom
->domain_trust_attribs
!= 0x0 )
4195 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
4199 *num_domains
= idx
+ 1;
4205 /*********************************************************************
4206 ********************************************************************/
4208 static TDB_DATA
make_tdc_key( const char *domain_name
)
4210 char *keystr
= NULL
;
4211 TDB_DATA key
= { NULL
, 0 };
4213 if ( !domain_name
) {
4214 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
4218 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
4221 key
= string_term_tdb_data(keystr
);
4226 /*********************************************************************
4227 ********************************************************************/
4229 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
4231 unsigned char **buf
)
4233 unsigned char *buffer
= NULL
;
4238 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
4246 /* Store the number of array items first */
4247 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
4250 /* now pack each domain trust record */
4251 for ( i
=0; i
<num_domains
; i
++ ) {
4256 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
4257 domains
[i
].domain_name
,
4258 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
4261 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
4262 domains
[i
].domain_name
,
4263 domains
[i
].dns_name
,
4264 sid_to_fstring(tmp
, &domains
[i
].sid
),
4265 domains
[i
].trust_flags
,
4266 domains
[i
].trust_attribs
,
4267 domains
[i
].trust_type
);
4270 if ( buflen
< len
) {
4272 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
4273 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
4287 /*********************************************************************
4288 ********************************************************************/
4290 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
4291 struct winbindd_tdc_domain
**domains
)
4293 fstring domain_name
, dns_name
, sid_string
;
4294 uint32 type
, attribs
, flags
;
4298 struct winbindd_tdc_domain
*list
= NULL
;
4300 /* get the number of domains */
4301 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
4303 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4307 list
= TALLOC_ARRAY( NULL
, struct winbindd_tdc_domain
, num_domains
);
4309 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
4313 for ( i
=0; i
<num_domains
; i
++ ) {
4314 len
+= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
4323 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
4324 TALLOC_FREE( list
);
4328 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
4329 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
4330 domain_name
, dns_name
, sid_string
,
4331 flags
, attribs
, type
));
4333 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
4334 list
[i
].dns_name
= talloc_strdup( list
, dns_name
);
4335 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
4336 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
4339 list
[i
].trust_flags
= flags
;
4340 list
[i
].trust_attribs
= attribs
;
4341 list
[i
].trust_type
= type
;
4349 /*********************************************************************
4350 ********************************************************************/
4352 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
4354 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4355 TDB_DATA data
= { NULL
, 0 };
4361 /* See if we were asked to delete the cache entry */
4364 ret
= tdb_delete( wcache
->tdb
, key
);
4368 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4375 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4378 SAFE_FREE( data
.dptr
);
4379 SAFE_FREE( key
.dptr
);
4381 return ( ret
!= -1 );
4384 /*********************************************************************
4385 ********************************************************************/
4387 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4389 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4390 TDB_DATA data
= { NULL
, 0 };
4398 data
= tdb_fetch( wcache
->tdb
, key
);
4400 SAFE_FREE( key
.dptr
);
4405 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4407 SAFE_FREE( data
.dptr
);
4415 /*********************************************************************
4416 ********************************************************************/
4418 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4420 struct winbindd_tdc_domain
*dom_list
= NULL
;
4421 size_t num_domains
= 0;
4424 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4425 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4426 domain
->name
, domain
->alt_name
,
4427 sid_string_dbg(&domain
->sid
),
4428 domain
->domain_flags
,
4429 domain
->domain_trust_attribs
,
4430 domain
->domain_type
));
4432 if ( !init_wcache() ) {
4436 /* fetch the list */
4438 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4440 /* add the new domain */
4442 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4446 /* pack the domain */
4448 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4456 TALLOC_FREE( dom_list
);
4461 /*********************************************************************
4462 ********************************************************************/
4464 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4466 struct winbindd_tdc_domain
*dom_list
= NULL
;
4467 size_t num_domains
= 0;
4469 struct winbindd_tdc_domain
*d
= NULL
;
4471 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4473 if ( !init_wcache() ) {
4477 /* fetch the list */
4479 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4481 for ( i
=0; i
<num_domains
; i
++ ) {
4482 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4483 strequal(name
, dom_list
[i
].dns_name
) )
4485 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4488 d
= TALLOC_P( ctx
, struct winbindd_tdc_domain
);
4492 d
->domain_name
= talloc_strdup( d
, dom_list
[i
].domain_name
);
4493 d
->dns_name
= talloc_strdup( d
, dom_list
[i
].dns_name
);
4494 sid_copy( &d
->sid
, &dom_list
[i
].sid
);
4495 d
->trust_flags
= dom_list
[i
].trust_flags
;
4496 d
->trust_type
= dom_list
[i
].trust_type
;
4497 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
4503 TALLOC_FREE( dom_list
);
4509 /*********************************************************************
4510 ********************************************************************/
4512 void wcache_tdc_clear( void )
4514 if ( !init_wcache() )
4517 wcache_tdc_store_list( NULL
, 0 );
4523 /*********************************************************************
4524 ********************************************************************/
4526 static void wcache_save_user_pwinfo(struct winbindd_domain
*domain
,
4528 const struct dom_sid
*user_sid
,
4529 const char *homedir
,
4534 struct cache_entry
*centry
;
4537 if ( (centry
= centry_start(domain
, status
)) == NULL
)
4540 centry_put_string( centry
, homedir
);
4541 centry_put_string( centry
, shell
);
4542 centry_put_string( centry
, gecos
);
4543 centry_put_uint32( centry
, gid
);
4545 centry_end(centry
, "NSS/PWINFO/%s", sid_to_fstring(tmp
, user_sid
) );
4547 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid
) ));
4549 centry_free(centry
);
4552 NTSTATUS
nss_get_info_cached( struct winbindd_domain
*domain
,
4553 const struct dom_sid
*user_sid
,
4555 ADS_STRUCT
*ads
, LDAPMessage
*msg
,
4556 const char **homedir
, const char **shell
,
4557 const char **gecos
, gid_t
*p_gid
)
4559 struct winbind_cache
*cache
= get_cache(domain
);
4560 struct cache_entry
*centry
= NULL
;
4567 centry
= wcache_fetch(cache
, domain
, "NSS/PWINFO/%s",
4568 sid_to_fstring(tmp
, user_sid
));
4573 *homedir
= centry_string( centry
, ctx
);
4574 *shell
= centry_string( centry
, ctx
);
4575 *gecos
= centry_string( centry
, ctx
);
4576 *p_gid
= centry_uint32( centry
);
4578 centry_free(centry
);
4580 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4581 sid_string_dbg(user_sid
)));
4583 return NT_STATUS_OK
;
4587 nt_status
= nss_get_info( domain
->name
, user_sid
, ctx
, ads
, msg
,
4588 homedir
, shell
, gecos
, p_gid
);
4590 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status
)));
4592 if ( NT_STATUS_IS_OK(nt_status
) ) {
4593 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir
));
4594 DEBUGADD(10, ("\tshell = '%s'\n", *shell
));
4595 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos
));
4596 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid
));
4598 wcache_save_user_pwinfo( domain
, nt_status
, user_sid
,
4599 *homedir
, *shell
, *gecos
, *p_gid
);
4602 if ( NT_STATUS_EQUAL( nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
4603 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4605 set_domain_offline( domain
);
4612 /* the cache backend methods are exposed via this structure */
4613 struct winbindd_methods cache_methods
= {
4631 static bool wcache_ndr_key(TALLOC_CTX
*mem_ctx
, char *domain_name
,
4632 uint32_t opnum
, const DATA_BLOB
*req
,
4638 key
= talloc_asprintf(mem_ctx
, "NDR/%s/%d/", domain_name
, (int)opnum
);
4642 keylen
= talloc_get_size(key
) - 1;
4644 key
= talloc_realloc(mem_ctx
, key
, char, keylen
+ req
->length
);
4648 memcpy(key
+ keylen
, req
->data
, req
->length
);
4650 pkey
->dptr
= (uint8_t *)key
;
4651 pkey
->dsize
= talloc_get_size(key
);
4655 static bool wcache_opnum_cacheable(uint32_t opnum
)
4658 case NDR_WBINT_PING
:
4659 case NDR_WBINT_QUERYSEQUENCENUMBER
:
4660 case NDR_WBINT_ALLOCATEUID
:
4661 case NDR_WBINT_ALLOCATEGID
:
4662 case NDR_WBINT_CHECKMACHINEACCOUNT
:
4663 case NDR_WBINT_CHANGEMACHINEACCOUNT
:
4664 case NDR_WBINT_PINGDC
:
4670 bool wcache_fetch_ndr(TALLOC_CTX
*mem_ctx
, struct winbindd_domain
*domain
,
4671 uint32_t opnum
, const DATA_BLOB
*req
, DATA_BLOB
*resp
)
4676 if (!wcache_opnum_cacheable(opnum
) ||
4677 is_my_own_sam_domain(domain
) ||
4678 is_builtin_domain(domain
)) {
4682 if (wcache
->tdb
== NULL
) {
4686 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4689 data
= tdb_fetch(wcache
->tdb
, key
);
4690 TALLOC_FREE(key
.dptr
);
4692 if (data
.dptr
== NULL
) {
4695 if (data
.dsize
< 4) {
4699 if (!is_domain_offline(domain
)) {
4700 uint32_t entry_seqnum
, dom_seqnum
, last_check
;
4702 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
,
4706 entry_seqnum
= IVAL(data
.dptr
, 0);
4707 if (entry_seqnum
!= dom_seqnum
) {
4708 DEBUG(10, ("Entry has wrong sequence number: %d\n",
4709 (int)entry_seqnum
));
4714 resp
->data
= (uint8_t *)talloc_memdup(mem_ctx
, data
.dptr
+ 4,
4716 if (resp
->data
== NULL
) {
4717 DEBUG(10, ("talloc failed\n"));
4720 resp
->length
= data
.dsize
- 4;
4724 SAFE_FREE(data
.dptr
);
4728 void wcache_store_ndr(struct winbindd_domain
*domain
, uint32_t opnum
,
4729 const DATA_BLOB
*req
, const DATA_BLOB
*resp
)
4732 uint32_t dom_seqnum
, last_check
;
4734 if (!wcache_opnum_cacheable(opnum
) ||
4735 is_my_own_sam_domain(domain
) ||
4736 is_builtin_domain(domain
)) {
4740 if (wcache
->tdb
== NULL
) {
4744 if (!wcache_fetch_seqnum(domain
->name
, &dom_seqnum
, &last_check
)) {
4745 DEBUG(10, ("could not fetch seqnum for domain %s\n",
4750 if (!wcache_ndr_key(talloc_tos(), domain
->name
, opnum
, req
, &key
)) {
4754 data
.dsize
= resp
->length
+ 4;
4755 data
.dptr
= talloc_array(key
.dptr
, uint8_t, data
.dsize
);
4756 if (data
.dptr
== NULL
) {
4760 SIVAL(data
.dptr
, 0, dom_seqnum
);
4761 memcpy(data
.dptr
+4, resp
->data
, resp
->length
);
4763 tdb_store(wcache
->tdb
, key
, data
, 0);
4766 TALLOC_FREE(key
.dptr
);