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"
31 #define DBGC_CLASS DBGC_WINBIND
33 #define WINBINDD_CACHE_VERSION 1
34 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
36 extern struct winbindd_methods reconnect_methods
;
38 extern struct winbindd_methods ads_methods
;
40 extern struct winbindd_methods builtin_passdb_methods
;
43 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
44 * Here are the list of entry types that are *not* stored
45 * as form struct cache_entry in the cache.
48 static const char *non_centry_keys
[] = {
53 WINBINDD_CACHE_VERSION_KEYSTR
,
57 /************************************************************************
58 Is this key a non-centry type ?
59 ************************************************************************/
61 static bool is_non_centry_key(TDB_DATA kbuf
)
65 if (kbuf
.dptr
== NULL
|| kbuf
.dsize
== 0) {
68 for (i
= 0; non_centry_keys
[i
] != NULL
; i
++) {
69 size_t namelen
= strlen(non_centry_keys
[i
]);
70 if (kbuf
.dsize
< namelen
) {
73 if (strncmp(non_centry_keys
[i
], (const char *)kbuf
.dptr
, namelen
) == 0) {
80 /* Global online/offline state - False when online. winbindd starts up online
81 and sets this to true if the first query fails and there's an entry in
82 the cache tdb telling us to stay offline. */
84 static bool global_winbindd_offline_state
;
86 struct winbind_cache
{
92 uint32 sequence_number
;
97 void (*smb_panic_fn
)(const char *const why
) = smb_panic
;
99 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
101 static struct winbind_cache
*wcache
;
103 void winbindd_check_cache_size(time_t t
)
105 static time_t last_check_time
;
108 if (last_check_time
== (time_t)0)
111 if (t
- last_check_time
< 60 && t
- last_check_time
> 0)
114 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
115 DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
119 if (fstat(tdb_fd(wcache
->tdb
), &st
) == -1) {
120 DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno
) ));
124 if (st
.st_size
> WINBINDD_MAX_CACHE_SIZE
) {
125 DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
126 (unsigned long)st
.st_size
,
127 (unsigned long)WINBINDD_MAX_CACHE_SIZE
));
128 wcache_flush_cache();
132 /* get the winbind_cache structure */
133 static struct winbind_cache
*get_cache(struct winbindd_domain
*domain
)
135 struct winbind_cache
*ret
= wcache
;
137 /* We have to know what type of domain we are dealing with first. */
139 if (domain
->internal
) {
140 domain
->backend
= &builtin_passdb_methods
;
141 domain
->initialized
= True
;
143 if ( !domain
->initialized
) {
144 init_dc_connection( domain
);
148 OK. listen up becasue I'm only going to say this once.
149 We have the following scenarios to consider
150 (a) trusted AD domains on a Samba DC,
151 (b) trusted AD domains and we are joined to a non-kerberos domain
152 (c) trusted AD domains and we are joined to a kerberos (AD) domain
154 For (a) we can always contact the trusted domain using krb5
155 since we have the domain trust account password
157 For (b) we can only use RPC since we have no way of
158 getting a krb5 ticket in our own domain
160 For (c) we can always use krb5 since we have a kerberos trust
165 if (!domain
->backend
) {
167 struct winbindd_domain
*our_domain
= domain
;
169 /* find our domain first so we can figure out if we
170 are joined to a kerberized domain */
172 if ( !domain
->primary
)
173 our_domain
= find_our_domain();
175 if ((our_domain
->active_directory
|| IS_DC
)
176 && domain
->active_directory
177 && !lp_winbind_rpc_only()) {
178 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain
->name
));
179 domain
->backend
= &ads_methods
;
181 #endif /* HAVE_ADS */
182 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain
->name
));
183 domain
->backend
= &reconnect_methods
;
186 #endif /* HAVE_ADS */
192 ret
= SMB_XMALLOC_P(struct winbind_cache
);
196 wcache_flush_cache();
202 free a centry structure
204 static void centry_free(struct cache_entry
*centry
)
208 SAFE_FREE(centry
->data
);
212 static bool centry_check_bytes(struct cache_entry
*centry
, size_t nbytes
)
214 if (centry
->len
- centry
->ofs
< nbytes
) {
215 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
216 (unsigned int)nbytes
,
217 centry
->len
- centry
->ofs
));
224 pull a uint32 from a cache entry
226 static uint32
centry_uint32(struct cache_entry
*centry
)
230 if (!centry_check_bytes(centry
, 4)) {
231 smb_panic_fn("centry_uint32");
233 ret
= IVAL(centry
->data
, centry
->ofs
);
239 pull a uint16 from a cache entry
241 static uint16
centry_uint16(struct cache_entry
*centry
)
244 if (!centry_check_bytes(centry
, 2)) {
245 smb_panic_fn("centry_uint16");
247 ret
= CVAL(centry
->data
, centry
->ofs
);
253 pull a uint8 from a cache entry
255 static uint8
centry_uint8(struct cache_entry
*centry
)
258 if (!centry_check_bytes(centry
, 1)) {
259 smb_panic_fn("centry_uint8");
261 ret
= CVAL(centry
->data
, centry
->ofs
);
267 pull a NTTIME from a cache entry
269 static NTTIME
centry_nttime(struct cache_entry
*centry
)
272 if (!centry_check_bytes(centry
, 8)) {
273 smb_panic_fn("centry_nttime");
275 ret
= IVAL(centry
->data
, centry
->ofs
);
277 ret
+= (uint64_t)IVAL(centry
->data
, centry
->ofs
) << 32;
283 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
285 static time_t centry_time(struct cache_entry
*centry
)
287 return (time_t)centry_nttime(centry
);
290 /* pull a string from a cache entry, using the supplied
293 static char *centry_string(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
298 len
= centry_uint8(centry
);
301 /* a deliberate NULL string */
305 if (!centry_check_bytes(centry
, (size_t)len
)) {
306 smb_panic_fn("centry_string");
309 ret
= TALLOC_ARRAY(mem_ctx
, char, len
+1);
311 smb_panic_fn("centry_string out of memory\n");
313 memcpy(ret
,centry
->data
+ centry
->ofs
, len
);
319 /* pull a hash16 from a cache entry, using the supplied
322 static char *centry_hash16(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
327 len
= centry_uint8(centry
);
330 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
335 if (!centry_check_bytes(centry
, 16)) {
339 ret
= TALLOC_ARRAY(mem_ctx
, char, 16);
341 smb_panic_fn("centry_hash out of memory\n");
343 memcpy(ret
,centry
->data
+ centry
->ofs
, 16);
348 /* pull a sid from a cache entry, using the supplied
351 static bool centry_sid(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
, DOM_SID
*sid
)
354 sid_string
= centry_string(centry
, mem_ctx
);
355 if ((sid_string
== NULL
) || (!string_to_sid(sid
, sid_string
))) {
363 pull a NTSTATUS from a cache entry
365 static NTSTATUS
centry_ntstatus(struct cache_entry
*centry
)
369 status
= NT_STATUS(centry_uint32(centry
));
374 /* the server is considered down if it can't give us a sequence number */
375 static bool wcache_server_down(struct winbindd_domain
*domain
)
382 ret
= (domain
->sequence_number
== DOM_SEQUENCE_NONE
);
385 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
390 static NTSTATUS
fetch_cache_seqnum( struct winbindd_domain
*domain
, time_t now
)
397 DEBUG(10,("fetch_cache_seqnum: tdb == NULL\n"));
398 return NT_STATUS_UNSUCCESSFUL
;
401 fstr_sprintf( key
, "SEQNUM/%s", domain
->name
);
403 data
= tdb_fetch_bystring( wcache
->tdb
, key
);
404 if ( !data
.dptr
|| data
.dsize
!=8 ) {
405 DEBUG(10,("fetch_cache_seqnum: invalid data size key [%s]\n", key
));
406 return NT_STATUS_UNSUCCESSFUL
;
409 domain
->sequence_number
= IVAL(data
.dptr
, 0);
410 domain
->last_seq_check
= IVAL(data
.dptr
, 4);
412 SAFE_FREE(data
.dptr
);
414 /* have we expired? */
416 time_diff
= now
- domain
->last_seq_check
;
417 if ( time_diff
> lp_winbind_cache_time() ) {
418 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
419 domain
->name
, domain
->sequence_number
,
420 (uint32
)domain
->last_seq_check
));
421 return NT_STATUS_UNSUCCESSFUL
;
424 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
425 domain
->name
, domain
->sequence_number
,
426 (uint32
)domain
->last_seq_check
));
431 static NTSTATUS
store_cache_seqnum( struct winbindd_domain
*domain
)
438 DEBUG(10,("store_cache_seqnum: tdb == NULL\n"));
439 return NT_STATUS_UNSUCCESSFUL
;
442 fstr_sprintf( key_str
, "SEQNUM/%s", domain
->name
);
444 SIVAL(buf
, 0, domain
->sequence_number
);
445 SIVAL(buf
, 4, domain
->last_seq_check
);
449 if ( tdb_store_bystring( wcache
->tdb
, key_str
, data
, TDB_REPLACE
) == -1 ) {
450 DEBUG(10,("store_cache_seqnum: tdb_store fail key [%s]\n", key_str
));
451 return NT_STATUS_UNSUCCESSFUL
;
454 DEBUG(10,("store_cache_seqnum: success [%s][%u @ %u]\n",
455 domain
->name
, domain
->sequence_number
,
456 (uint32
)domain
->last_seq_check
));
462 refresh the domain sequence number. If force is true
463 then always refresh it, no matter how recently we fetched it
466 static void refresh_sequence_number(struct winbindd_domain
*domain
, bool force
)
470 time_t t
= time(NULL
);
471 unsigned cache_time
= lp_winbind_cache_time();
473 if ( IS_DOMAIN_OFFLINE(domain
) ) {
479 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
480 /* trying to reconnect is expensive, don't do it too often */
481 if (domain
->sequence_number
== DOM_SEQUENCE_NONE
) {
486 time_diff
= t
- domain
->last_seq_check
;
488 /* see if we have to refetch the domain sequence number */
489 if (!force
&& (time_diff
< cache_time
) &&
490 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
491 NT_STATUS_IS_OK(domain
->last_status
)) {
492 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain
->name
));
496 /* try to get the sequence number from the tdb cache first */
497 /* this will update the timestamp as well */
499 status
= fetch_cache_seqnum( domain
, t
);
500 if (NT_STATUS_IS_OK(status
) &&
501 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
502 NT_STATUS_IS_OK(domain
->last_status
)) {
506 /* important! make sure that we know if this is a native
507 mode domain or not. And that we can contact it. */
509 if ( winbindd_can_contact_domain( domain
) ) {
510 status
= domain
->backend
->sequence_number(domain
,
511 &domain
->sequence_number
);
513 /* just use the current time */
514 status
= NT_STATUS_OK
;
515 domain
->sequence_number
= time(NULL
);
519 /* the above call could have set our domain->backend to NULL when
520 * coming from offline to online mode, make sure to reinitialize the
521 * backend - Guenther */
524 if (!NT_STATUS_IS_OK(status
)) {
525 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status
)));
526 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
529 domain
->last_status
= status
;
530 domain
->last_seq_check
= time(NULL
);
532 /* save the new sequence number in the cache */
533 store_cache_seqnum( domain
);
536 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
537 domain
->name
, domain
->sequence_number
));
543 decide if a cache entry has expired
545 static bool centry_expired(struct winbindd_domain
*domain
, const char *keystr
, struct cache_entry
*centry
)
547 /* If we've been told to be offline - stay in that state... */
548 if (lp_winbind_offline_logon() && global_winbindd_offline_state
) {
549 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
550 keystr
, domain
->name
));
554 /* when the domain is offline return the cached entry.
555 * This deals with transient offline states... */
557 if (!domain
->online
) {
558 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
559 keystr
, domain
->name
));
563 /* if the server is OK and our cache entry came from when it was down then
564 the entry is invalid */
565 if ((domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
566 (centry
->sequence_number
== DOM_SEQUENCE_NONE
)) {
567 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
568 keystr
, domain
->name
));
572 /* if the server is down or the cache entry is not older than the
573 current sequence number then it is OK */
574 if (wcache_server_down(domain
) ||
575 centry
->sequence_number
== domain
->sequence_number
) {
576 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
577 keystr
, domain
->name
));
581 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
582 keystr
, domain
->name
));
588 static struct cache_entry
*wcache_fetch_raw(char *kstr
)
591 struct cache_entry
*centry
;
594 key
= string_tdb_data(kstr
);
595 data
= tdb_fetch(wcache
->tdb
, key
);
601 centry
= SMB_XMALLOC_P(struct cache_entry
);
602 centry
->data
= (unsigned char *)data
.dptr
;
603 centry
->len
= data
.dsize
;
606 if (centry
->len
< 8) {
607 /* huh? corrupt cache? */
608 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr
));
613 centry
->status
= centry_ntstatus(centry
);
614 centry
->sequence_number
= centry_uint32(centry
);
620 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
621 number and return status
623 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
624 struct winbindd_domain
*domain
,
625 const char *format
, ...) PRINTF_ATTRIBUTE(3,4);
626 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
627 struct winbindd_domain
*domain
,
628 const char *format
, ...)
632 struct cache_entry
*centry
;
634 if (!winbindd_use_cache()) {
638 refresh_sequence_number(domain
, false);
640 va_start(ap
, format
);
641 smb_xvasprintf(&kstr
, format
, ap
);
644 centry
= wcache_fetch_raw(kstr
);
645 if (centry
== NULL
) {
650 if (centry_expired(domain
, kstr
, centry
)) {
652 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
653 kstr
, domain
->name
));
660 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
661 kstr
, domain
->name
));
667 static void wcache_delete(const char *format
, ...) PRINTF_ATTRIBUTE(1,2);
668 static void wcache_delete(const char *format
, ...)
674 va_start(ap
, format
);
675 smb_xvasprintf(&kstr
, format
, ap
);
678 key
= string_tdb_data(kstr
);
680 tdb_delete(wcache
->tdb
, key
);
685 make sure we have at least len bytes available in a centry
687 static void centry_expand(struct cache_entry
*centry
, uint32 len
)
689 if (centry
->len
- centry
->ofs
>= len
)
692 centry
->data
= SMB_REALLOC_ARRAY(centry
->data
, unsigned char,
695 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry
->len
));
696 smb_panic_fn("out of memory in centry_expand");
701 push a uint32 into a centry
703 static void centry_put_uint32(struct cache_entry
*centry
, uint32 v
)
705 centry_expand(centry
, 4);
706 SIVAL(centry
->data
, centry
->ofs
, v
);
711 push a uint16 into a centry
713 static void centry_put_uint16(struct cache_entry
*centry
, uint16 v
)
715 centry_expand(centry
, 2);
716 SIVAL(centry
->data
, centry
->ofs
, v
);
721 push a uint8 into a centry
723 static void centry_put_uint8(struct cache_entry
*centry
, uint8 v
)
725 centry_expand(centry
, 1);
726 SCVAL(centry
->data
, centry
->ofs
, v
);
731 push a string into a centry
733 static void centry_put_string(struct cache_entry
*centry
, const char *s
)
738 /* null strings are marked as len 0xFFFF */
739 centry_put_uint8(centry
, 0xFF);
744 /* can't handle more than 254 char strings. Truncating is probably best */
746 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len
));
749 centry_put_uint8(centry
, len
);
750 centry_expand(centry
, len
);
751 memcpy(centry
->data
+ centry
->ofs
, s
, len
);
756 push a 16 byte hash into a centry - treat as 16 byte string.
758 static void centry_put_hash16(struct cache_entry
*centry
, const uint8 val
[16])
760 centry_put_uint8(centry
, 16);
761 centry_expand(centry
, 16);
762 memcpy(centry
->data
+ centry
->ofs
, val
, 16);
766 static void centry_put_sid(struct cache_entry
*centry
, const DOM_SID
*sid
)
769 centry_put_string(centry
, sid_to_fstring(sid_string
, sid
));
774 put NTSTATUS into a centry
776 static void centry_put_ntstatus(struct cache_entry
*centry
, NTSTATUS status
)
778 uint32 status_value
= NT_STATUS_V(status
);
779 centry_put_uint32(centry
, status_value
);
784 push a NTTIME into a centry
786 static void centry_put_nttime(struct cache_entry
*centry
, NTTIME nt
)
788 centry_expand(centry
, 8);
789 SIVAL(centry
->data
, centry
->ofs
, nt
& 0xFFFFFFFF);
791 SIVAL(centry
->data
, centry
->ofs
, nt
>> 32);
796 push a time_t into a centry - use a 64 bit size.
797 NTTIME here is being used as a convenient 64-bit size.
799 static void centry_put_time(struct cache_entry
*centry
, time_t t
)
801 NTTIME nt
= (NTTIME
)t
;
802 centry_put_nttime(centry
, nt
);
806 start a centry for output. When finished, call centry_end()
808 struct cache_entry
*centry_start(struct winbindd_domain
*domain
, NTSTATUS status
)
810 struct cache_entry
*centry
;
815 centry
= SMB_XMALLOC_P(struct cache_entry
);
817 centry
->len
= 8192; /* reasonable default */
818 centry
->data
= SMB_XMALLOC_ARRAY(uint8
, centry
->len
);
820 centry
->sequence_number
= domain
->sequence_number
;
821 centry_put_ntstatus(centry
, status
);
822 centry_put_uint32(centry
, centry
->sequence_number
);
827 finish a centry and write it to the tdb
829 static void centry_end(struct cache_entry
*centry
, const char *format
, ...) PRINTF_ATTRIBUTE(2,3);
830 static void centry_end(struct cache_entry
*centry
, const char *format
, ...)
836 if (!winbindd_use_cache()) {
840 va_start(ap
, format
);
841 smb_xvasprintf(&kstr
, format
, ap
);
844 key
= string_tdb_data(kstr
);
845 data
.dptr
= centry
->data
;
846 data
.dsize
= centry
->ofs
;
848 tdb_store(wcache
->tdb
, key
, data
, TDB_REPLACE
);
852 static void wcache_save_name_to_sid(struct winbindd_domain
*domain
,
853 NTSTATUS status
, const char *domain_name
,
854 const char *name
, const DOM_SID
*sid
,
855 enum lsa_SidType type
)
857 struct cache_entry
*centry
;
860 centry
= centry_start(domain
, status
);
863 centry_put_uint32(centry
, type
);
864 centry_put_sid(centry
, sid
);
865 fstrcpy(uname
, name
);
867 centry_end(centry
, "NS/%s/%s", domain_name
, uname
);
868 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name
,
869 uname
, sid_string_dbg(sid
), nt_errstr(status
)));
873 static void wcache_save_sid_to_name(struct winbindd_domain
*domain
, NTSTATUS status
,
874 const DOM_SID
*sid
, const char *domain_name
, const char *name
, enum lsa_SidType type
)
876 struct cache_entry
*centry
;
879 centry
= centry_start(domain
, status
);
883 if (NT_STATUS_IS_OK(status
)) {
884 centry_put_uint32(centry
, type
);
885 centry_put_string(centry
, domain_name
);
886 centry_put_string(centry
, name
);
889 centry_end(centry
, "SN/%s", sid_to_fstring(sid_string
, sid
));
890 DEBUG(10,("wcache_save_sid_to_name: %s -> %s (%s)\n", sid_string
,
891 name
, nt_errstr(status
)));
896 static void wcache_save_user(struct winbindd_domain
*domain
, NTSTATUS status
, WINBIND_USERINFO
*info
)
898 struct cache_entry
*centry
;
901 if (is_null_sid(&info
->user_sid
)) {
905 centry
= centry_start(domain
, status
);
908 centry_put_string(centry
, info
->acct_name
);
909 centry_put_string(centry
, info
->full_name
);
910 centry_put_string(centry
, info
->homedir
);
911 centry_put_string(centry
, info
->shell
);
912 centry_put_uint32(centry
, info
->primary_gid
);
913 centry_put_sid(centry
, &info
->user_sid
);
914 centry_put_sid(centry
, &info
->group_sid
);
915 centry_end(centry
, "U/%s", sid_to_fstring(sid_string
,
917 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string
, info
->acct_name
));
921 static void wcache_save_lockout_policy(struct winbindd_domain
*domain
,
923 struct samr_DomInfo12
*lockout_policy
)
925 struct cache_entry
*centry
;
927 centry
= centry_start(domain
, status
);
931 centry_put_nttime(centry
, lockout_policy
->lockout_duration
);
932 centry_put_nttime(centry
, lockout_policy
->lockout_window
);
933 centry_put_uint16(centry
, lockout_policy
->lockout_threshold
);
935 centry_end(centry
, "LOC_POL/%s", domain
->name
);
937 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain
->name
));
944 static void wcache_save_password_policy(struct winbindd_domain
*domain
,
946 struct samr_DomInfo1
*policy
)
948 struct cache_entry
*centry
;
950 centry
= centry_start(domain
, status
);
954 centry_put_uint16(centry
, policy
->min_password_length
);
955 centry_put_uint16(centry
, policy
->password_history_length
);
956 centry_put_uint32(centry
, policy
->password_properties
);
957 centry_put_nttime(centry
, policy
->max_password_age
);
958 centry_put_nttime(centry
, policy
->min_password_age
);
960 centry_end(centry
, "PWD_POL/%s", domain
->name
);
962 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
967 /***************************************************************************
968 ***************************************************************************/
970 static void wcache_save_username_alias(struct winbindd_domain
*domain
,
972 const char *name
, const char *alias
)
974 struct cache_entry
*centry
;
977 if ( (centry
= centry_start(domain
, status
)) == NULL
)
980 centry_put_string( centry
, alias
);
982 fstrcpy(uname
, name
);
984 centry_end(centry
, "NSS/NA/%s", uname
);
986 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name
, alias
));
991 static void wcache_save_alias_username(struct winbindd_domain
*domain
,
993 const char *alias
, const char *name
)
995 struct cache_entry
*centry
;
998 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1001 centry_put_string( centry
, name
);
1003 fstrcpy(uname
, alias
);
1005 centry_end(centry
, "NSS/AN/%s", uname
);
1007 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias
, name
));
1009 centry_free(centry
);
1012 /***************************************************************************
1013 ***************************************************************************/
1015 NTSTATUS
resolve_username_to_alias( TALLOC_CTX
*mem_ctx
,
1016 struct winbindd_domain
*domain
,
1017 const char *name
, char **alias
)
1019 struct winbind_cache
*cache
= get_cache(domain
);
1020 struct cache_entry
*centry
= NULL
;
1024 if ( domain
->internal
)
1025 return NT_STATUS_NOT_SUPPORTED
;
1030 if ( (upper_name
= SMB_STRDUP(name
)) == NULL
)
1031 return NT_STATUS_NO_MEMORY
;
1032 strupper_m(upper_name
);
1034 centry
= wcache_fetch(cache
, domain
, "NSS/NA/%s", upper_name
);
1036 SAFE_FREE( upper_name
);
1041 status
= centry
->status
;
1043 if (!NT_STATUS_IS_OK(status
)) {
1044 centry_free(centry
);
1048 *alias
= centry_string( centry
, mem_ctx
);
1050 centry_free(centry
);
1052 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1053 name
, *alias
? *alias
: "(none)"));
1055 return (*alias
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1059 /* If its not in cache and we are offline, then fail */
1061 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1062 DEBUG(8,("resolve_username_to_alias: rejecting query "
1063 "in offline mode\n"));
1064 return NT_STATUS_NOT_FOUND
;
1067 status
= nss_map_to_alias( mem_ctx
, domain
->name
, name
, alias
);
1069 if ( NT_STATUS_IS_OK( status
) ) {
1070 wcache_save_username_alias(domain
, status
, name
, *alias
);
1073 if ( NT_STATUS_EQUAL( status
, NT_STATUS_NONE_MAPPED
) ) {
1074 wcache_save_username_alias(domain
, status
, name
, "(NULL)");
1077 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1078 nt_errstr(status
)));
1080 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1081 set_domain_offline( domain
);
1087 /***************************************************************************
1088 ***************************************************************************/
1090 NTSTATUS
resolve_alias_to_username( TALLOC_CTX
*mem_ctx
,
1091 struct winbindd_domain
*domain
,
1092 const char *alias
, char **name
)
1094 struct winbind_cache
*cache
= get_cache(domain
);
1095 struct cache_entry
*centry
= NULL
;
1099 if ( domain
->internal
)
1100 return NT_STATUS_NOT_SUPPORTED
;
1105 if ( (upper_name
= SMB_STRDUP(alias
)) == NULL
)
1106 return NT_STATUS_NO_MEMORY
;
1107 strupper_m(upper_name
);
1109 centry
= wcache_fetch(cache
, domain
, "NSS/AN/%s", upper_name
);
1111 SAFE_FREE( upper_name
);
1116 status
= centry
->status
;
1118 if (!NT_STATUS_IS_OK(status
)) {
1119 centry_free(centry
);
1123 *name
= centry_string( centry
, mem_ctx
);
1125 centry_free(centry
);
1127 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1128 alias
, *name
? *name
: "(none)"));
1130 return (*name
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1134 /* If its not in cache and we are offline, then fail */
1136 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1137 DEBUG(8,("resolve_alias_to_username: rejecting query "
1138 "in offline mode\n"));
1139 return NT_STATUS_NOT_FOUND
;
1142 /* an alias cannot contain a domain prefix or '@' */
1144 if (strchr(alias
, '\\') || strchr(alias
, '@')) {
1145 DEBUG(10,("resolve_alias_to_username: skipping fully "
1146 "qualified name %s\n", alias
));
1147 return NT_STATUS_OBJECT_NAME_INVALID
;
1150 status
= nss_map_from_alias( mem_ctx
, domain
->name
, alias
, name
);
1152 if ( NT_STATUS_IS_OK( status
) ) {
1153 wcache_save_alias_username( domain
, status
, alias
, *name
);
1156 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1157 wcache_save_alias_username(domain
, status
, alias
, "(NULL)");
1160 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1161 nt_errstr(status
)));
1163 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1164 set_domain_offline( domain
);
1170 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const DOM_SID
*sid
)
1172 struct winbind_cache
*cache
= get_cache(domain
);
1174 fstring key_str
, tmp
;
1178 return NT_STATUS_INTERNAL_DB_ERROR
;
1181 if (is_null_sid(sid
)) {
1182 return NT_STATUS_INVALID_SID
;
1185 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1186 return NT_STATUS_INVALID_SID
;
1189 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
1191 data
= tdb_fetch(cache
->tdb
, string_tdb_data(key_str
));
1193 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1196 SAFE_FREE(data
.dptr
);
1197 return NT_STATUS_OK
;
1200 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1201 as new salted ones. */
1203 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
1204 TALLOC_CTX
*mem_ctx
,
1206 const uint8
**cached_nt_pass
,
1207 const uint8
**cached_salt
)
1209 struct winbind_cache
*cache
= get_cache(domain
);
1210 struct cache_entry
*centry
= NULL
;
1217 return NT_STATUS_INTERNAL_DB_ERROR
;
1220 if (is_null_sid(sid
)) {
1221 return NT_STATUS_INVALID_SID
;
1224 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1225 return NT_STATUS_INVALID_SID
;
1228 /* Try and get a salted cred first. If we can't
1229 fall back to an unsalted cred. */
1231 centry
= wcache_fetch(cache
, domain
, "CRED/%s",
1232 sid_to_fstring(tmp
, sid
));
1234 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1235 sid_string_dbg(sid
)));
1236 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1239 t
= centry_time(centry
);
1241 /* In the salted case this isn't actually the nt_hash itself,
1242 but the MD5 of the salt + nt_hash. Let the caller
1243 sort this out. It can tell as we only return the cached_salt
1244 if we are returning a salted cred. */
1246 *cached_nt_pass
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1247 if (*cached_nt_pass
== NULL
) {
1250 sid_to_fstring(sidstr
, sid
);
1252 /* Bad (old) cred cache. Delete and pretend we
1254 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1256 wcache_delete("CRED/%s", sidstr
);
1257 centry_free(centry
);
1258 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1261 /* We only have 17 bytes more data in the salted cred case. */
1262 if (centry
->len
- centry
->ofs
== 17) {
1263 *cached_salt
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1265 *cached_salt
= NULL
;
1268 dump_data_pw("cached_nt_pass", *cached_nt_pass
, NT_HASH_LEN
);
1270 dump_data_pw("cached_salt", *cached_salt
, NT_HASH_LEN
);
1273 status
= centry
->status
;
1275 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1276 sid_string_dbg(sid
), nt_errstr(status
) ));
1278 centry_free(centry
);
1282 /* Store creds for a SID - only writes out new salted ones. */
1284 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1285 TALLOC_CTX
*mem_ctx
,
1287 const uint8 nt_pass
[NT_HASH_LEN
])
1289 struct cache_entry
*centry
;
1292 uint8 cred_salt
[NT_HASH_LEN
];
1293 uint8 salted_hash
[NT_HASH_LEN
];
1295 if (is_null_sid(sid
)) {
1296 return NT_STATUS_INVALID_SID
;
1299 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1300 return NT_STATUS_INVALID_SID
;
1303 centry
= centry_start(domain
, NT_STATUS_OK
);
1305 return NT_STATUS_INTERNAL_DB_ERROR
;
1308 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1310 centry_put_time(centry
, time(NULL
));
1312 /* Create a salt and then salt the hash. */
1313 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1314 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1316 centry_put_hash16(centry
, salted_hash
);
1317 centry_put_hash16(centry
, cred_salt
);
1318 centry_end(centry
, "CRED/%s", sid_to_fstring(sid_string
, sid
));
1320 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1322 centry_free(centry
);
1324 return NT_STATUS_OK
;
1328 /* Query display info. This is the basic user list fn */
1329 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
1330 TALLOC_CTX
*mem_ctx
,
1331 uint32
*num_entries
,
1332 WINBIND_USERINFO
**info
)
1334 struct winbind_cache
*cache
= get_cache(domain
);
1335 struct cache_entry
*centry
= NULL
;
1337 unsigned int i
, retry
;
1342 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1346 *num_entries
= centry_uint32(centry
);
1348 if (*num_entries
== 0)
1351 (*info
) = TALLOC_ARRAY(mem_ctx
, WINBIND_USERINFO
, *num_entries
);
1353 smb_panic_fn("query_user_list out of memory");
1355 for (i
=0; i
<(*num_entries
); i
++) {
1356 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
1357 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
1358 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
1359 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
1360 centry_sid(centry
, mem_ctx
, &(*info
)[i
].user_sid
);
1361 centry_sid(centry
, mem_ctx
, &(*info
)[i
].group_sid
);
1365 status
= centry
->status
;
1367 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1368 domain
->name
, nt_errstr(status
) ));
1370 centry_free(centry
);
1377 /* Return status value returned by seq number check */
1379 if (!NT_STATUS_IS_OK(domain
->last_status
))
1380 return domain
->last_status
;
1382 /* Put the query_user_list() in a retry loop. There appears to be
1383 * some bug either with Windows 2000 or Samba's handling of large
1384 * rpc replies. This manifests itself as sudden disconnection
1385 * at a random point in the enumeration of a large (60k) user list.
1386 * The retry loop simply tries the operation again. )-: It's not
1387 * pretty but an acceptable workaround until we work out what the
1388 * real problem is. */
1393 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1396 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
1397 if (!NT_STATUS_IS_OK(status
)) {
1398 DEBUG(3, ("query_user_list: returned 0x%08x, "
1399 "retrying\n", NT_STATUS_V(status
)));
1401 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1402 DEBUG(3, ("query_user_list: flushing "
1403 "connection cache\n"));
1404 invalidate_cm_connection(&domain
->conn
);
1407 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1411 refresh_sequence_number(domain
, false);
1412 centry
= centry_start(domain
, status
);
1415 centry_put_uint32(centry
, *num_entries
);
1416 for (i
=0; i
<(*num_entries
); i
++) {
1417 centry_put_string(centry
, (*info
)[i
].acct_name
);
1418 centry_put_string(centry
, (*info
)[i
].full_name
);
1419 centry_put_string(centry
, (*info
)[i
].homedir
);
1420 centry_put_string(centry
, (*info
)[i
].shell
);
1421 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1422 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1423 if (domain
->backend
&& domain
->backend
->consistent
) {
1424 /* when the backend is consistent we can pre-prime some mappings */
1425 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1427 (*info
)[i
].acct_name
,
1428 &(*info
)[i
].user_sid
,
1430 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1431 &(*info
)[i
].user_sid
,
1433 (*info
)[i
].acct_name
,
1435 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1438 centry_end(centry
, "UL/%s", domain
->name
);
1439 centry_free(centry
);
1445 /* list all domain groups */
1446 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
1447 TALLOC_CTX
*mem_ctx
,
1448 uint32
*num_entries
,
1449 struct acct_info
**info
)
1451 struct winbind_cache
*cache
= get_cache(domain
);
1452 struct cache_entry
*centry
= NULL
;
1459 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1463 *num_entries
= centry_uint32(centry
);
1465 if (*num_entries
== 0)
1468 (*info
) = TALLOC_ARRAY(mem_ctx
, struct acct_info
, *num_entries
);
1470 smb_panic_fn("enum_dom_groups out of memory");
1472 for (i
=0; i
<(*num_entries
); i
++) {
1473 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1474 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1475 (*info
)[i
].rid
= centry_uint32(centry
);
1479 status
= centry
->status
;
1481 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1482 domain
->name
, nt_errstr(status
) ));
1484 centry_free(centry
);
1491 /* Return status value returned by seq number check */
1493 if (!NT_STATUS_IS_OK(domain
->last_status
))
1494 return domain
->last_status
;
1496 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1499 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1502 refresh_sequence_number(domain
, false);
1503 centry
= centry_start(domain
, status
);
1506 centry_put_uint32(centry
, *num_entries
);
1507 for (i
=0; i
<(*num_entries
); i
++) {
1508 centry_put_string(centry
, (*info
)[i
].acct_name
);
1509 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1510 centry_put_uint32(centry
, (*info
)[i
].rid
);
1512 centry_end(centry
, "GL/%s/domain", domain
->name
);
1513 centry_free(centry
);
1519 /* list all domain groups */
1520 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
1521 TALLOC_CTX
*mem_ctx
,
1522 uint32
*num_entries
,
1523 struct acct_info
**info
)
1525 struct winbind_cache
*cache
= get_cache(domain
);
1526 struct cache_entry
*centry
= NULL
;
1533 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1537 *num_entries
= centry_uint32(centry
);
1539 if (*num_entries
== 0)
1542 (*info
) = TALLOC_ARRAY(mem_ctx
, struct acct_info
, *num_entries
);
1544 smb_panic_fn("enum_dom_groups out of memory");
1546 for (i
=0; i
<(*num_entries
); i
++) {
1547 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1548 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1549 (*info
)[i
].rid
= centry_uint32(centry
);
1554 /* If we are returning cached data and the domain controller
1555 is down then we don't know whether the data is up to date
1556 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1559 if (wcache_server_down(domain
)) {
1560 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1561 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1563 status
= centry
->status
;
1565 DEBUG(10,("enum_local_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_local_groups: [Cached] - doing backend query for list for domain %s\n",
1583 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1586 refresh_sequence_number(domain
, false);
1587 centry
= centry_start(domain
, status
);
1590 centry_put_uint32(centry
, *num_entries
);
1591 for (i
=0; i
<(*num_entries
); i
++) {
1592 centry_put_string(centry
, (*info
)[i
].acct_name
);
1593 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1594 centry_put_uint32(centry
, (*info
)[i
].rid
);
1596 centry_end(centry
, "GL/%s/local", domain
->name
);
1597 centry_free(centry
);
1603 /* convert a single name to a sid in a domain */
1604 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
1605 TALLOC_CTX
*mem_ctx
,
1606 enum winbindd_cmd orig_cmd
,
1607 const char *domain_name
,
1610 enum lsa_SidType
*type
)
1612 struct winbind_cache
*cache
= get_cache(domain
);
1613 struct cache_entry
*centry
= NULL
;
1620 fstrcpy(uname
, name
);
1622 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1626 status
= centry
->status
;
1627 if (NT_STATUS_IS_OK(status
)) {
1628 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1629 centry_sid(centry
, mem_ctx
, sid
);
1632 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: %s\n",
1633 domain
->name
, nt_errstr(status
) ));
1635 centry_free(centry
);
1641 /* If the seq number check indicated that there is a problem
1642 * with this DC, then return that status... except for
1643 * access_denied. This is special because the dc may be in
1644 * "restrict anonymous = 1" mode, in which case it will deny
1645 * most unauthenticated operations, but *will* allow the LSA
1646 * name-to-sid that we try as a fallback. */
1648 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1649 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1650 return domain
->last_status
;
1652 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1655 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, orig_cmd
,
1656 domain_name
, name
, sid
, type
);
1659 refresh_sequence_number(domain
, false);
1661 if (domain
->online
&&
1662 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1663 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1665 /* Only save the reverse mapping if this was not a UPN */
1666 if (!strchr(name
, '@')) {
1667 strupper_m(CONST_DISCARD(char *,domain_name
));
1668 strlower_m(CONST_DISCARD(char *,name
));
1669 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1676 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1678 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1679 TALLOC_CTX
*mem_ctx
,
1683 enum lsa_SidType
*type
)
1685 struct winbind_cache
*cache
= get_cache(domain
);
1686 struct cache_entry
*centry
= NULL
;
1693 centry
= wcache_fetch(cache
, domain
, "SN/%s",
1694 sid_to_fstring(sid_string
, sid
));
1698 status
= centry
->status
;
1699 if (NT_STATUS_IS_OK(status
)) {
1700 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1701 *domain_name
= centry_string(centry
, mem_ctx
);
1702 *name
= centry_string(centry
, mem_ctx
);
1705 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: %s\n",
1706 domain
->name
, nt_errstr(status
) ));
1708 centry_free(centry
);
1713 *domain_name
= NULL
;
1715 /* If the seq number check indicated that there is a problem
1716 * with this DC, then return that status... except for
1717 * access_denied. This is special because the dc may be in
1718 * "restrict anonymous = 1" mode, in which case it will deny
1719 * most unauthenticated operations, but *will* allow the LSA
1720 * sid-to-name that we try as a fallback. */
1722 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1723 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1724 return domain
->last_status
;
1726 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1729 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1732 refresh_sequence_number(domain
, false);
1733 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
1735 /* We can't save the name to sid mapping here, as with sid history a
1736 * later name2sid would give the wrong sid. */
1741 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
1742 TALLOC_CTX
*mem_ctx
,
1743 const DOM_SID
*domain_sid
,
1748 enum lsa_SidType
**types
)
1750 struct winbind_cache
*cache
= get_cache(domain
);
1752 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1756 *domain_name
= NULL
;
1764 if (num_rids
== 0) {
1765 return NT_STATUS_OK
;
1768 *names
= TALLOC_ARRAY(mem_ctx
, char *, num_rids
);
1769 *types
= TALLOC_ARRAY(mem_ctx
, enum lsa_SidType
, num_rids
);
1771 if ((*names
== NULL
) || (*types
== NULL
)) {
1772 result
= NT_STATUS_NO_MEMORY
;
1776 have_mapped
= have_unmapped
= false;
1778 for (i
=0; i
<num_rids
; i
++) {
1780 struct cache_entry
*centry
;
1783 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
1784 result
= NT_STATUS_INTERNAL_ERROR
;
1788 centry
= wcache_fetch(cache
, domain
, "SN/%s",
1789 sid_to_fstring(tmp
, &sid
));
1794 (*types
)[i
] = SID_NAME_UNKNOWN
;
1795 (*names
)[i
] = talloc_strdup(*names
, "");
1797 if (NT_STATUS_IS_OK(centry
->status
)) {
1800 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
1802 dom
= centry_string(centry
, mem_ctx
);
1803 if (*domain_name
== NULL
) {
1809 (*names
)[i
] = centry_string(centry
, *names
);
1811 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)) {
1812 have_unmapped
= true;
1815 /* something's definitely wrong */
1816 result
= centry
->status
;
1820 centry_free(centry
);
1824 return NT_STATUS_NONE_MAPPED
;
1826 if (!have_unmapped
) {
1827 return NT_STATUS_OK
;
1829 return STATUS_SOME_UNMAPPED
;
1833 TALLOC_FREE(*names
);
1834 TALLOC_FREE(*types
);
1836 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
1837 rids
, num_rids
, domain_name
,
1841 None of the queried rids has been found so save all negative entries
1843 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
1844 for (i
= 0; i
< num_rids
; i
++) {
1846 const char *name
= "";
1847 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
1848 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
1850 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
1851 return NT_STATUS_INTERNAL_ERROR
;
1854 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
1862 Some or all of the queried rids have been found.
1864 if (!NT_STATUS_IS_OK(result
) &&
1865 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
1869 refresh_sequence_number(domain
, false);
1871 for (i
=0; i
<num_rids
; i
++) {
1875 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
1876 result
= NT_STATUS_INTERNAL_ERROR
;
1880 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
1881 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
1883 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
1884 (*names
)[i
], (*types
)[i
]);
1891 TALLOC_FREE(*names
);
1892 TALLOC_FREE(*types
);
1896 /* Lookup user information from a rid */
1897 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
1898 TALLOC_CTX
*mem_ctx
,
1899 const DOM_SID
*user_sid
,
1900 WINBIND_USERINFO
*info
)
1902 struct winbind_cache
*cache
= get_cache(domain
);
1903 struct cache_entry
*centry
= NULL
;
1910 centry
= wcache_fetch(cache
, domain
, "U/%s",
1911 sid_to_fstring(tmp
, user_sid
));
1913 /* If we have an access denied cache entry and a cached info3 in the
1914 samlogon cache then do a query. This will force the rpc back end
1915 to return the info3 data. */
1917 if (NT_STATUS_V(domain
->last_status
) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED
) &&
1918 netsamlogon_cache_have(user_sid
)) {
1919 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1920 domain
->last_status
= NT_STATUS_OK
;
1921 centry_free(centry
);
1928 /* if status is not ok then this is a negative hit
1929 and the rest of the data doesn't matter */
1930 status
= centry
->status
;
1931 if (NT_STATUS_IS_OK(status
)) {
1932 info
->acct_name
= centry_string(centry
, mem_ctx
);
1933 info
->full_name
= centry_string(centry
, mem_ctx
);
1934 info
->homedir
= centry_string(centry
, mem_ctx
);
1935 info
->shell
= centry_string(centry
, mem_ctx
);
1936 info
->primary_gid
= centry_uint32(centry
);
1937 centry_sid(centry
, mem_ctx
, &info
->user_sid
);
1938 centry_sid(centry
, mem_ctx
, &info
->group_sid
);
1941 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: %s\n",
1942 domain
->name
, nt_errstr(status
) ));
1944 centry_free(centry
);
1950 /* Return status value returned by seq number check */
1952 if (!NT_STATUS_IS_OK(domain
->last_status
))
1953 return domain
->last_status
;
1955 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
1958 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
1961 refresh_sequence_number(domain
, false);
1962 wcache_save_user(domain
, status
, info
);
1968 /* Lookup groups a user is a member of. */
1969 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
1970 TALLOC_CTX
*mem_ctx
,
1971 const DOM_SID
*user_sid
,
1972 uint32
*num_groups
, DOM_SID
**user_gids
)
1974 struct winbind_cache
*cache
= get_cache(domain
);
1975 struct cache_entry
*centry
= NULL
;
1983 centry
= wcache_fetch(cache
, domain
, "UG/%s",
1984 sid_to_fstring(sid_string
, user_sid
));
1986 /* If we have an access denied cache entry and a cached info3 in the
1987 samlogon cache then do a query. This will force the rpc back end
1988 to return the info3 data. */
1990 if (NT_STATUS_V(domain
->last_status
) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED
) &&
1991 netsamlogon_cache_have(user_sid
)) {
1992 DEBUG(10, ("lookup_usergroups: cached access denied and have cached info3\n"));
1993 domain
->last_status
= NT_STATUS_OK
;
1994 centry_free(centry
);
2001 *num_groups
= centry_uint32(centry
);
2003 if (*num_groups
== 0)
2006 (*user_gids
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_groups
);
2007 if (! (*user_gids
)) {
2008 smb_panic_fn("lookup_usergroups out of memory");
2010 for (i
=0; i
<(*num_groups
); i
++) {
2011 centry_sid(centry
, mem_ctx
, &(*user_gids
)[i
]);
2015 status
= centry
->status
;
2017 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status: %s\n",
2018 domain
->name
, nt_errstr(status
) ));
2020 centry_free(centry
);
2025 (*user_gids
) = NULL
;
2027 /* Return status value returned by seq number check */
2029 if (!NT_STATUS_IS_OK(domain
->last_status
))
2030 return domain
->last_status
;
2032 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2035 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
2037 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
2041 refresh_sequence_number(domain
, false);
2042 centry
= centry_start(domain
, status
);
2046 centry_put_uint32(centry
, *num_groups
);
2047 for (i
=0; i
<(*num_groups
); i
++) {
2048 centry_put_sid(centry
, &(*user_gids
)[i
]);
2051 centry_end(centry
, "UG/%s", sid_to_fstring(sid_string
, user_sid
));
2052 centry_free(centry
);
2058 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
2059 TALLOC_CTX
*mem_ctx
,
2060 uint32 num_sids
, const DOM_SID
*sids
,
2061 uint32
*num_aliases
, uint32
**alias_rids
)
2063 struct winbind_cache
*cache
= get_cache(domain
);
2064 struct cache_entry
*centry
= NULL
;
2066 char *sidlist
= talloc_strdup(mem_ctx
, "");
2072 if (num_sids
== 0) {
2075 return NT_STATUS_OK
;
2078 /* We need to cache indexed by the whole list of SIDs, the aliases
2079 * resulting might come from any of the SIDs. */
2081 for (i
=0; i
<num_sids
; i
++) {
2083 sidlist
= talloc_asprintf(mem_ctx
, "%s/%s", sidlist
,
2084 sid_to_fstring(tmp
, &sids
[i
]));
2085 if (sidlist
== NULL
)
2086 return NT_STATUS_NO_MEMORY
;
2089 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2094 *num_aliases
= centry_uint32(centry
);
2098 (*alias_rids
) = TALLOC_ARRAY(mem_ctx
, uint32
, *num_aliases
);
2100 if ((*alias_rids
) == NULL
) {
2101 centry_free(centry
);
2102 return NT_STATUS_NO_MEMORY
;
2105 (*alias_rids
) = NULL
;
2108 for (i
=0; i
<(*num_aliases
); i
++)
2109 (*alias_rids
)[i
] = centry_uint32(centry
);
2111 status
= centry
->status
;
2113 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2114 "status %s\n", domain
->name
, nt_errstr(status
)));
2116 centry_free(centry
);
2121 (*alias_rids
) = NULL
;
2123 if (!NT_STATUS_IS_OK(domain
->last_status
))
2124 return domain
->last_status
;
2126 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2127 "for domain %s\n", domain
->name
));
2129 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2131 num_aliases
, alias_rids
);
2134 refresh_sequence_number(domain
, false);
2135 centry
= centry_start(domain
, status
);
2138 centry_put_uint32(centry
, *num_aliases
);
2139 for (i
=0; i
<(*num_aliases
); i
++)
2140 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2141 centry_end(centry
, "UA%s", sidlist
);
2142 centry_free(centry
);
2149 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
2150 TALLOC_CTX
*mem_ctx
,
2151 const DOM_SID
*group_sid
, uint32
*num_names
,
2152 DOM_SID
**sid_mem
, char ***names
,
2153 uint32
**name_types
)
2155 struct winbind_cache
*cache
= get_cache(domain
);
2156 struct cache_entry
*centry
= NULL
;
2164 centry
= wcache_fetch(cache
, domain
, "GM/%s",
2165 sid_to_fstring(sid_string
, group_sid
));
2169 *num_names
= centry_uint32(centry
);
2171 if (*num_names
== 0)
2174 (*sid_mem
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_names
);
2175 (*names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_names
);
2176 (*name_types
) = TALLOC_ARRAY(mem_ctx
, uint32
, *num_names
);
2178 if (! (*sid_mem
) || ! (*names
) || ! (*name_types
)) {
2179 smb_panic_fn("lookup_groupmem out of memory");
2182 for (i
=0; i
<(*num_names
); i
++) {
2183 centry_sid(centry
, mem_ctx
, &(*sid_mem
)[i
]);
2184 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2185 (*name_types
)[i
] = centry_uint32(centry
);
2189 status
= centry
->status
;
2191 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status: %s\n",
2192 domain
->name
, nt_errstr(status
)));
2194 centry_free(centry
);
2201 (*name_types
) = NULL
;
2203 /* Return status value returned by seq number check */
2205 if (!NT_STATUS_IS_OK(domain
->last_status
))
2206 return domain
->last_status
;
2208 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2211 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2212 sid_mem
, names
, name_types
);
2215 refresh_sequence_number(domain
, false);
2216 centry
= centry_start(domain
, status
);
2219 centry_put_uint32(centry
, *num_names
);
2220 for (i
=0; i
<(*num_names
); i
++) {
2221 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2222 centry_put_string(centry
, (*names
)[i
]);
2223 centry_put_uint32(centry
, (*name_types
)[i
]);
2225 centry_end(centry
, "GM/%s", sid_to_fstring(sid_string
, group_sid
));
2226 centry_free(centry
);
2232 /* find the sequence number for a domain */
2233 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
2235 refresh_sequence_number(domain
, false);
2237 *seq
= domain
->sequence_number
;
2239 return NT_STATUS_OK
;
2242 /* enumerate trusted domains
2243 * (we need to have the list of trustdoms in the cache when we go offline) -
2245 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
2246 TALLOC_CTX
*mem_ctx
,
2247 uint32
*num_domains
,
2252 struct winbind_cache
*cache
= get_cache(domain
);
2253 struct cache_entry
*centry
= NULL
;
2260 centry
= wcache_fetch(cache
, domain
, "TRUSTDOMS/%s", domain
->name
);
2266 *num_domains
= centry_uint32(centry
);
2269 (*names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
2270 (*alt_names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
2271 (*dom_sids
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_domains
);
2273 if (! (*dom_sids
) || ! (*names
) || ! (*alt_names
)) {
2274 smb_panic_fn("trusted_domains out of memory");
2278 (*alt_names
) = NULL
;
2282 for (i
=0; i
<(*num_domains
); i
++) {
2283 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2284 (*alt_names
)[i
] = centry_string(centry
, mem_ctx
);
2285 if (!centry_sid(centry
, mem_ctx
, &(*dom_sids
)[i
])) {
2286 sid_copy(&(*dom_sids
)[i
], &global_sid_NULL
);
2290 status
= centry
->status
;
2292 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
2293 domain
->name
, *num_domains
, nt_errstr(status
) ));
2295 centry_free(centry
);
2302 (*alt_names
) = NULL
;
2304 /* Return status value returned by seq number check */
2306 if (!NT_STATUS_IS_OK(domain
->last_status
))
2307 return domain
->last_status
;
2309 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2312 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, num_domains
,
2313 names
, alt_names
, dom_sids
);
2315 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2316 * so that the generic centry handling still applies correctly -
2319 if (!NT_STATUS_IS_ERR(status
)) {
2320 status
= NT_STATUS_OK
;
2324 #if 0 /* Disabled as we want the trust dom list to be managed by
2325 the main parent and always to make the query. --jerry */
2328 refresh_sequence_number(domain
, false);
2330 centry
= centry_start(domain
, status
);
2334 centry_put_uint32(centry
, *num_domains
);
2336 for (i
=0; i
<(*num_domains
); i
++) {
2337 centry_put_string(centry
, (*names
)[i
]);
2338 centry_put_string(centry
, (*alt_names
)[i
]);
2339 centry_put_sid(centry
, &(*dom_sids
)[i
]);
2342 centry_end(centry
, "TRUSTDOMS/%s", domain
->name
);
2344 centry_free(centry
);
2352 /* get lockout policy */
2353 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
2354 TALLOC_CTX
*mem_ctx
,
2355 struct samr_DomInfo12
*policy
)
2357 struct winbind_cache
*cache
= get_cache(domain
);
2358 struct cache_entry
*centry
= NULL
;
2364 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2369 policy
->lockout_duration
= centry_nttime(centry
);
2370 policy
->lockout_window
= centry_nttime(centry
);
2371 policy
->lockout_threshold
= centry_uint16(centry
);
2373 status
= centry
->status
;
2375 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2376 domain
->name
, nt_errstr(status
) ));
2378 centry_free(centry
);
2382 ZERO_STRUCTP(policy
);
2384 /* Return status value returned by seq number check */
2386 if (!NT_STATUS_IS_OK(domain
->last_status
))
2387 return domain
->last_status
;
2389 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2392 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2395 refresh_sequence_number(domain
, false);
2396 wcache_save_lockout_policy(domain
, status
, policy
);
2401 /* get password policy */
2402 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
2403 TALLOC_CTX
*mem_ctx
,
2404 struct samr_DomInfo1
*policy
)
2406 struct winbind_cache
*cache
= get_cache(domain
);
2407 struct cache_entry
*centry
= NULL
;
2413 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2418 policy
->min_password_length
= centry_uint16(centry
);
2419 policy
->password_history_length
= centry_uint16(centry
);
2420 policy
->password_properties
= centry_uint32(centry
);
2421 policy
->max_password_age
= centry_nttime(centry
);
2422 policy
->min_password_age
= centry_nttime(centry
);
2424 status
= centry
->status
;
2426 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2427 domain
->name
, nt_errstr(status
) ));
2429 centry_free(centry
);
2433 ZERO_STRUCTP(policy
);
2435 /* Return status value returned by seq number check */
2437 if (!NT_STATUS_IS_OK(domain
->last_status
))
2438 return domain
->last_status
;
2440 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2443 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
2446 refresh_sequence_number(domain
, false);
2447 if (NT_STATUS_IS_OK(status
)) {
2448 wcache_save_password_policy(domain
, status
, policy
);
2455 /* Invalidate cached user and group lists coherently */
2457 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2460 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
2461 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
2462 tdb_delete(the_tdb
, kbuf
);
2467 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2469 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
2470 struct netr_SamInfo3
*info3
)
2473 fstring key_str
, sid_string
;
2474 struct winbind_cache
*cache
;
2476 /* dont clear cached U/SID and UG/SID entries when we want to logon
2479 if (lp_winbind_offline_logon()) {
2486 cache
= get_cache(domain
);
2492 sid_copy(&sid
, info3
->base
.domain_sid
);
2493 sid_append_rid(&sid
, info3
->base
.rid
);
2495 /* Clear U/SID cache entry */
2496 fstr_sprintf(key_str
, "U/%s", sid_to_fstring(sid_string
, &sid
));
2497 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
2498 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
2500 /* Clear UG/SID cache entry */
2501 fstr_sprintf(key_str
, "UG/%s", sid_to_fstring(sid_string
, &sid
));
2502 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
2503 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
2505 /* Samba/winbindd never needs this. */
2506 netsamlogon_clear_cached_user(info3
);
2509 bool wcache_invalidate_cache(void)
2511 struct winbindd_domain
*domain
;
2513 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
2514 struct winbind_cache
*cache
= get_cache(domain
);
2516 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2517 "entries for %s\n", domain
->name
));
2520 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
2529 bool init_wcache(void)
2531 if (wcache
== NULL
) {
2532 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
2533 ZERO_STRUCTP(wcache
);
2536 if (wcache
->tdb
!= NULL
)
2539 /* when working offline we must not clear the cache on restart */
2540 wcache
->tdb
= tdb_open_log(cache_path("winbindd_cache.tdb"),
2541 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
2542 lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
2543 O_RDWR
|O_CREAT
, 0600);
2545 if (wcache
->tdb
== NULL
) {
2546 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2553 /************************************************************************
2554 This is called by the parent to initialize the cache file.
2555 We don't need sophisticated locking here as we know we're the
2557 ************************************************************************/
2559 bool initialize_winbindd_cache(void)
2561 bool cache_bad
= true;
2564 if (!init_wcache()) {
2565 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
2569 /* Check version number. */
2570 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
2571 vers
== WINBINDD_CACHE_VERSION
) {
2576 DEBUG(0,("initialize_winbindd_cache: clearing cache "
2577 "and re-creating with version number %d\n",
2578 WINBINDD_CACHE_VERSION
));
2580 tdb_close(wcache
->tdb
);
2583 if (unlink(cache_path("winbindd_cache.tdb")) == -1) {
2584 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
2585 cache_path("winbindd_cache.tdb"),
2589 if (!init_wcache()) {
2590 DEBUG(0,("initialize_winbindd_cache: re-initialization "
2591 "init_wcache failed.\n"));
2595 /* Write the version. */
2596 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
2597 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
2598 tdb_errorstr(wcache
->tdb
) ));
2603 tdb_close(wcache
->tdb
);
2608 void close_winbindd_cache(void)
2614 tdb_close(wcache
->tdb
);
2619 void cache_store_response(pid_t pid
, struct winbindd_response
*response
)
2626 DEBUG(10, ("Storing response for pid %d, len %d\n",
2627 (int)pid
, response
->length
));
2629 fstr_sprintf(key_str
, "DR/%d", (int)pid
);
2630 if (tdb_store(wcache
->tdb
, string_tdb_data(key_str
),
2631 make_tdb_data((uint8
*)response
, sizeof(*response
)),
2635 if (response
->length
== sizeof(*response
))
2638 /* There's extra data */
2640 DEBUG(10, ("Storing extra data: len=%d\n",
2641 (int)(response
->length
- sizeof(*response
))));
2643 fstr_sprintf(key_str
, "DE/%d", (int)pid
);
2644 if (tdb_store(wcache
->tdb
, string_tdb_data(key_str
),
2645 make_tdb_data((uint8
*)response
->extra_data
.data
,
2646 response
->length
- sizeof(*response
)),
2650 /* We could not store the extra data, make sure the tdb does not
2651 * contain a main record with wrong dangling extra data */
2653 fstr_sprintf(key_str
, "DR/%d", (int)pid
);
2654 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2659 bool cache_retrieve_response(pid_t pid
, struct winbindd_response
* response
)
2667 DEBUG(10, ("Retrieving response for pid %d\n", (int)pid
));
2669 fstr_sprintf(key_str
, "DR/%d", (int)pid
);
2670 data
= tdb_fetch(wcache
->tdb
, string_tdb_data(key_str
));
2672 if (data
.dptr
== NULL
)
2675 if (data
.dsize
!= sizeof(*response
))
2678 memcpy(response
, data
.dptr
, data
.dsize
);
2679 SAFE_FREE(data
.dptr
);
2681 if (response
->length
== sizeof(*response
)) {
2682 response
->extra_data
.data
= NULL
;
2686 /* There's extra data */
2688 DEBUG(10, ("Retrieving extra data length=%d\n",
2689 (int)(response
->length
- sizeof(*response
))));
2691 fstr_sprintf(key_str
, "DE/%d", (int)pid
);
2692 data
= tdb_fetch(wcache
->tdb
, string_tdb_data(key_str
));
2694 if (data
.dptr
== NULL
) {
2695 DEBUG(0, ("Did not find extra data\n"));
2699 if (data
.dsize
!= (response
->length
- sizeof(*response
))) {
2700 DEBUG(0, ("Invalid extra data length: %d\n", (int)data
.dsize
));
2701 SAFE_FREE(data
.dptr
);
2705 dump_data(11, (uint8
*)data
.dptr
, data
.dsize
);
2707 response
->extra_data
.data
= data
.dptr
;
2711 void cache_cleanup_response(pid_t pid
)
2718 fstr_sprintf(key_str
, "DR/%d", (int)pid
);
2719 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2721 fstr_sprintf(key_str
, "DE/%d", (int)pid
);
2722 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2728 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const DOM_SID
*sid
,
2729 char **domain_name
, char **name
,
2730 enum lsa_SidType
*type
)
2732 struct winbindd_domain
*domain
;
2733 struct winbind_cache
*cache
;
2734 struct cache_entry
*centry
= NULL
;
2738 domain
= find_lookup_domain_from_sid(sid
);
2739 if (domain
== NULL
) {
2743 cache
= get_cache(domain
);
2745 if (cache
->tdb
== NULL
) {
2749 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2750 sid_to_fstring(tmp
, sid
));
2751 if (centry
== NULL
) {
2755 if (NT_STATUS_IS_OK(centry
->status
)) {
2756 *type
= (enum lsa_SidType
)centry_uint32(centry
);
2757 *domain_name
= centry_string(centry
, mem_ctx
);
2758 *name
= centry_string(centry
, mem_ctx
);
2761 status
= centry
->status
;
2762 centry_free(centry
);
2763 return NT_STATUS_IS_OK(status
);
2766 bool lookup_cached_name(TALLOC_CTX
*mem_ctx
,
2767 const char *domain_name
,
2770 enum lsa_SidType
*type
)
2772 struct winbindd_domain
*domain
;
2773 struct winbind_cache
*cache
;
2774 struct cache_entry
*centry
= NULL
;
2777 bool original_online_state
;
2779 domain
= find_lookup_domain_from_name(domain_name
);
2780 if (domain
== NULL
) {
2784 cache
= get_cache(domain
);
2786 if (cache
->tdb
== NULL
) {
2790 fstrcpy(uname
, name
);
2793 /* If we are doing a cached logon, temporarily set the domain
2794 offline so the cache won't expire the entry */
2796 original_online_state
= domain
->online
;
2797 domain
->online
= false;
2798 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
2799 domain
->online
= original_online_state
;
2801 if (centry
== NULL
) {
2805 if (NT_STATUS_IS_OK(centry
->status
)) {
2806 *type
= (enum lsa_SidType
)centry_uint32(centry
);
2807 centry_sid(centry
, mem_ctx
, sid
);
2810 status
= centry
->status
;
2811 centry_free(centry
);
2813 return NT_STATUS_IS_OK(status
);
2816 void cache_name2sid(struct winbindd_domain
*domain
,
2817 const char *domain_name
, const char *name
,
2818 enum lsa_SidType type
, const DOM_SID
*sid
)
2820 refresh_sequence_number(domain
, false);
2821 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
2826 * The original idea that this cache only contains centries has
2827 * been blurred - now other stuff gets put in here. Ensure we
2828 * ignore these things on cleanup.
2831 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
2832 TDB_DATA dbuf
, void *state
)
2834 struct cache_entry
*centry
;
2836 if (is_non_centry_key(kbuf
)) {
2840 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
2845 if (!NT_STATUS_IS_OK(centry
->status
)) {
2846 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
2847 tdb_delete(the_tdb
, kbuf
);
2850 centry_free(centry
);
2854 /* flush the cache */
2855 void wcache_flush_cache(void)
2860 tdb_close(wcache
->tdb
);
2863 if (!winbindd_use_cache()) {
2867 /* when working offline we must not clear the cache on restart */
2868 wcache
->tdb
= tdb_open_log(cache_path("winbindd_cache.tdb"),
2869 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
2870 lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
2871 O_RDWR
|O_CREAT
, 0600);
2874 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2878 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
2880 DEBUG(10,("wcache_flush_cache success\n"));
2883 /* Count cached creds */
2885 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2888 int *cred_count
= (int*)state
;
2890 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
2896 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
2898 struct winbind_cache
*cache
= get_cache(domain
);
2903 return NT_STATUS_INTERNAL_DB_ERROR
;
2906 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
2908 return NT_STATUS_OK
;
2912 struct cred_list
*prev
, *next
;
2917 static struct cred_list
*wcache_cred_list
;
2919 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2922 struct cred_list
*cred
;
2924 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
2926 cred
= SMB_MALLOC_P(struct cred_list
);
2928 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2934 /* save a copy of the key */
2936 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
2937 DLIST_ADD(wcache_cred_list
, cred
);
2943 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const DOM_SID
*sid
)
2945 struct winbind_cache
*cache
= get_cache(domain
);
2948 struct cred_list
*cred
, *oldest
= NULL
;
2951 return NT_STATUS_INTERNAL_DB_ERROR
;
2954 /* we possibly already have an entry */
2955 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
2957 fstring key_str
, tmp
;
2959 DEBUG(11,("we already have an entry, deleting that\n"));
2961 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
2963 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
2965 return NT_STATUS_OK
;
2968 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
2970 return NT_STATUS_OK
;
2971 } else if ((ret
== -1) || (wcache_cred_list
== NULL
)) {
2972 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2975 ZERO_STRUCTP(oldest
);
2977 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
2982 data
= tdb_fetch(cache
->tdb
, string_tdb_data(cred
->name
));
2984 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
2986 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2990 t
= IVAL(data
.dptr
, 0);
2991 SAFE_FREE(data
.dptr
);
2994 oldest
= SMB_MALLOC_P(struct cred_list
);
2995 if (oldest
== NULL
) {
2996 status
= NT_STATUS_NO_MEMORY
;
3000 fstrcpy(oldest
->name
, cred
->name
);
3001 oldest
->created
= t
;
3005 if (t
< oldest
->created
) {
3006 fstrcpy(oldest
->name
, cred
->name
);
3007 oldest
->created
= t
;
3011 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3012 status
= NT_STATUS_OK
;
3014 status
= NT_STATUS_UNSUCCESSFUL
;
3017 SAFE_FREE(wcache_cred_list
);
3023 /* Change the global online/offline state. */
3024 bool set_global_winbindd_state_offline(void)
3028 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3030 /* Only go offline if someone has created
3031 the key "WINBINDD_OFFLINE" in the cache tdb. */
3033 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3034 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3038 if (!lp_winbind_offline_logon()) {
3039 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3043 if (global_winbindd_offline_state
) {
3044 /* Already offline. */
3048 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
3050 if (!data
.dptr
|| data
.dsize
!= 4) {
3051 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3052 SAFE_FREE(data
.dptr
);
3055 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3056 global_winbindd_offline_state
= true;
3057 SAFE_FREE(data
.dptr
);
3062 void set_global_winbindd_state_online(void)
3064 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3066 if (!lp_winbind_offline_logon()) {
3067 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3071 if (!global_winbindd_offline_state
) {
3072 /* Already online. */
3075 global_winbindd_offline_state
= false;
3081 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3082 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3085 bool get_global_winbindd_state_offline(void)
3087 return global_winbindd_offline_state
;
3090 /***********************************************************************
3091 Validate functions for all possible cache tdb keys.
3092 ***********************************************************************/
3094 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3095 struct tdb_validation_status
*state
)
3097 struct cache_entry
*centry
;
3099 centry
= SMB_XMALLOC_P(struct cache_entry
);
3100 centry
->data
= (unsigned char *)memdup(data
.dptr
, data
.dsize
);
3101 if (!centry
->data
) {
3105 centry
->len
= data
.dsize
;
3108 if (centry
->len
< 8) {
3109 /* huh? corrupt cache? */
3110 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr
));
3111 centry_free(centry
);
3112 state
->bad_entry
= true;
3113 state
->success
= false;
3117 centry
->status
= NT_STATUS(centry_uint32(centry
));
3118 centry
->sequence_number
= centry_uint32(centry
);
3122 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3123 struct tdb_validation_status
*state
)
3125 if (dbuf
.dsize
!= 8) {
3126 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3127 keystr
, (unsigned int)dbuf
.dsize
));
3128 state
->bad_entry
= true;
3134 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3135 struct tdb_validation_status
*state
)
3137 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3142 (void)centry_uint32(centry
);
3143 if (NT_STATUS_IS_OK(centry
->status
)) {
3145 (void)centry_sid(centry
, mem_ctx
, &sid
);
3148 centry_free(centry
);
3150 if (!(state
->success
)) {
3153 DEBUG(10,("validate_ns: %s ok\n", keystr
));
3157 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3158 struct tdb_validation_status
*state
)
3160 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3165 if (NT_STATUS_IS_OK(centry
->status
)) {
3166 (void)centry_uint32(centry
);
3167 (void)centry_string(centry
, mem_ctx
);
3168 (void)centry_string(centry
, mem_ctx
);
3171 centry_free(centry
);
3173 if (!(state
->success
)) {
3176 DEBUG(10,("validate_sn: %s ok\n", keystr
));
3180 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3181 struct tdb_validation_status
*state
)
3183 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3190 (void)centry_string(centry
, mem_ctx
);
3191 (void)centry_string(centry
, mem_ctx
);
3192 (void)centry_string(centry
, mem_ctx
);
3193 (void)centry_string(centry
, mem_ctx
);
3194 (void)centry_uint32(centry
);
3195 (void)centry_sid(centry
, mem_ctx
, &sid
);
3196 (void)centry_sid(centry
, mem_ctx
, &sid
);
3198 centry_free(centry
);
3200 if (!(state
->success
)) {
3203 DEBUG(10,("validate_u: %s ok\n", keystr
));
3207 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3208 struct tdb_validation_status
*state
)
3210 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3216 (void)centry_nttime(centry
);
3217 (void)centry_nttime(centry
);
3218 (void)centry_uint16(centry
);
3220 centry_free(centry
);
3222 if (!(state
->success
)) {
3225 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3229 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3230 struct tdb_validation_status
*state
)
3232 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3238 (void)centry_uint16(centry
);
3239 (void)centry_uint16(centry
);
3240 (void)centry_uint32(centry
);
3241 (void)centry_nttime(centry
);
3242 (void)centry_nttime(centry
);
3244 centry_free(centry
);
3246 if (!(state
->success
)) {
3249 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3253 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3254 struct tdb_validation_status
*state
)
3256 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3262 (void)centry_time(centry
);
3263 (void)centry_hash16(centry
, mem_ctx
);
3265 /* We only have 17 bytes more data in the salted cred case. */
3266 if (centry
->len
- centry
->ofs
== 17) {
3267 (void)centry_hash16(centry
, mem_ctx
);
3270 centry_free(centry
);
3272 if (!(state
->success
)) {
3275 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3279 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3280 struct tdb_validation_status
*state
)
3282 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3283 int32 num_entries
, i
;
3289 num_entries
= (int32
)centry_uint32(centry
);
3291 for (i
=0; i
< num_entries
; i
++) {
3293 (void)centry_string(centry
, mem_ctx
);
3294 (void)centry_string(centry
, mem_ctx
);
3295 (void)centry_string(centry
, mem_ctx
);
3296 (void)centry_string(centry
, mem_ctx
);
3297 (void)centry_sid(centry
, mem_ctx
, &sid
);
3298 (void)centry_sid(centry
, mem_ctx
, &sid
);
3301 centry_free(centry
);
3303 if (!(state
->success
)) {
3306 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3310 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3311 struct tdb_validation_status
*state
)
3313 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3314 int32 num_entries
, i
;
3320 num_entries
= centry_uint32(centry
);
3322 for (i
=0; i
< num_entries
; i
++) {
3323 (void)centry_string(centry
, mem_ctx
);
3324 (void)centry_string(centry
, mem_ctx
);
3325 (void)centry_uint32(centry
);
3328 centry_free(centry
);
3330 if (!(state
->success
)) {
3333 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3337 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3338 struct tdb_validation_status
*state
)
3340 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3341 int32 num_groups
, i
;
3347 num_groups
= centry_uint32(centry
);
3349 for (i
=0; i
< num_groups
; i
++) {
3351 centry_sid(centry
, mem_ctx
, &sid
);
3354 centry_free(centry
);
3356 if (!(state
->success
)) {
3359 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3363 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3364 struct tdb_validation_status
*state
)
3366 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3367 int32 num_aliases
, i
;
3373 num_aliases
= centry_uint32(centry
);
3375 for (i
=0; i
< num_aliases
; i
++) {
3376 (void)centry_uint32(centry
);
3379 centry_free(centry
);
3381 if (!(state
->success
)) {
3384 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3388 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3389 struct tdb_validation_status
*state
)
3391 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3398 num_names
= centry_uint32(centry
);
3400 for (i
=0; i
< num_names
; i
++) {
3402 centry_sid(centry
, mem_ctx
, &sid
);
3403 (void)centry_string(centry
, mem_ctx
);
3404 (void)centry_uint32(centry
);
3407 centry_free(centry
);
3409 if (!(state
->success
)) {
3412 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3416 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3417 struct tdb_validation_status
*state
)
3419 /* Can't say anything about this other than must be nonzero. */
3420 if (dbuf
.dsize
== 0) {
3421 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3423 state
->bad_entry
= true;
3424 state
->success
= false;
3428 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3432 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3433 struct tdb_validation_status
*state
)
3435 /* Can't say anything about this other than must be nonzero. */
3436 if (dbuf
.dsize
== 0) {
3437 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3439 state
->bad_entry
= true;
3440 state
->success
= false;
3444 DEBUG(10,("validate_de: %s ok\n", keystr
));
3448 static int validate_pwinfo(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3449 TDB_DATA dbuf
, struct tdb_validation_status
*state
)
3451 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3457 (void)centry_string(centry
, mem_ctx
);
3458 (void)centry_string(centry
, mem_ctx
);
3459 (void)centry_string(centry
, mem_ctx
);
3460 (void)centry_uint32(centry
);
3462 centry_free(centry
);
3464 if (!(state
->success
)) {
3467 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3471 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3473 struct tdb_validation_status
*state
)
3475 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3481 (void)centry_string( centry
, mem_ctx
);
3483 centry_free(centry
);
3485 if (!(state
->success
)) {
3488 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3492 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3494 struct tdb_validation_status
*state
)
3496 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3502 (void)centry_string( centry
, mem_ctx
);
3504 centry_free(centry
);
3506 if (!(state
->success
)) {
3509 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3513 static int validate_trustdoms(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3514 struct tdb_validation_status
*state
)
3516 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3517 int32 num_domains
, i
;
3523 num_domains
= centry_uint32(centry
);
3525 for (i
=0; i
< num_domains
; i
++) {
3527 (void)centry_string(centry
, mem_ctx
);
3528 (void)centry_string(centry
, mem_ctx
);
3529 (void)centry_sid(centry
, mem_ctx
, &sid
);
3532 centry_free(centry
);
3534 if (!(state
->success
)) {
3537 DEBUG(10,("validate_trustdoms: %s ok\n", keystr
));
3541 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3543 struct tdb_validation_status
*state
)
3545 if (dbuf
.dsize
== 0) {
3546 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3547 "key %s (len ==0) ?\n", keystr
));
3548 state
->bad_entry
= true;
3549 state
->success
= false;
3553 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3554 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3558 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3559 struct tdb_validation_status
*state
)
3561 if (dbuf
.dsize
!= 4) {
3562 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3563 keystr
, (unsigned int)dbuf
.dsize
));
3564 state
->bad_entry
= true;
3565 state
->success
= false;
3568 DEBUG(10,("validate_offline: %s ok\n", keystr
));
3572 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3573 struct tdb_validation_status
*state
)
3575 if (dbuf
.dsize
!= 4) {
3576 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3577 "key %s (len %u != 4) ?\n",
3578 keystr
, (unsigned int)dbuf
.dsize
));
3579 state
->bad_entry
= true;
3580 state
->success
= false;
3584 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
3588 /***********************************************************************
3589 A list of all possible cache tdb keys with associated validation
3591 ***********************************************************************/
3593 struct key_val_struct
{
3594 const char *keyname
;
3595 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
3597 {"SEQNUM/", validate_seqnum
},
3598 {"NS/", validate_ns
},
3599 {"SN/", validate_sn
},
3601 {"LOC_POL/", validate_loc_pol
},
3602 {"PWD_POL/", validate_pwd_pol
},
3603 {"CRED/", validate_cred
},
3604 {"UL/", validate_ul
},
3605 {"GL/", validate_gl
},
3606 {"UG/", validate_ug
},
3607 {"UA", validate_ua
},
3608 {"GM/", validate_gm
},
3609 {"DR/", validate_dr
},
3610 {"DE/", validate_de
},
3611 {"NSS/PWINFO/", validate_pwinfo
},
3612 {"TRUSTDOMS/", validate_trustdoms
},
3613 {"TRUSTDOMCACHE/", validate_trustdomcache
},
3614 {"NSS/NA/", validate_nss_na
},
3615 {"NSS/AN/", validate_nss_an
},
3616 {"WINBINDD_OFFLINE", validate_offline
},
3617 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
3621 /***********************************************************************
3622 Function to look at every entry in the tdb and validate it as far as
3624 ***********************************************************************/
3626 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
3629 unsigned int max_key_len
= 1024;
3630 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
3632 /* Paranoia check. */
3633 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0) {
3634 max_key_len
= 1024 * 1024;
3636 if (kbuf
.dsize
> max_key_len
) {
3637 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
3639 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
3643 for (i
= 0; key_val
[i
].keyname
; i
++) {
3644 size_t namelen
= strlen(key_val
[i
].keyname
);
3645 if (kbuf
.dsize
>= namelen
&& (
3646 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
3647 TALLOC_CTX
*mem_ctx
;
3651 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
3655 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
3656 keystr
[kbuf
.dsize
] = '\0';
3658 mem_ctx
= talloc_init("validate_ctx");
3664 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
3668 talloc_destroy(mem_ctx
);
3673 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
3674 dump_data(0, (uint8
*)kbuf
.dptr
, kbuf
.dsize
);
3675 DEBUG(0,("data :\n"));
3676 dump_data(0, (uint8
*)dbuf
.dptr
, dbuf
.dsize
);
3677 v_state
->unknown_key
= true;
3678 v_state
->success
= false;
3679 return 1; /* terminate. */
3682 static void validate_panic(const char *const why
)
3684 DEBUG(0,("validating cache: would panic %s\n", why
));
3685 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
3689 /***********************************************************************
3690 Try and validate every entry in the winbindd cache. If we fail here,
3691 delete the cache tdb and return non-zero.
3692 ***********************************************************************/
3694 int winbindd_validate_cache(void)
3697 const char *tdb_path
= cache_path("winbindd_cache.tdb");
3698 TDB_CONTEXT
*tdb
= NULL
;
3700 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3701 smb_panic_fn
= validate_panic
;
3704 tdb
= tdb_open_log(tdb_path
,
3705 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3706 ( lp_winbind_offline_logon()
3708 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
3712 DEBUG(0, ("winbindd_validate_cache: "
3713 "error opening/initializing tdb\n"));
3718 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
3721 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
3722 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
3727 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
3728 smb_panic_fn
= smb_panic
;
3732 /***********************************************************************
3733 Try and validate every entry in the winbindd cache.
3734 ***********************************************************************/
3736 int winbindd_validate_cache_nobackup(void)
3739 const char *tdb_path
= cache_path("winbindd_cache.tdb");
3741 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3742 smb_panic_fn
= validate_panic
;
3745 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3746 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
3748 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
3752 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
3756 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
3758 smb_panic_fn
= smb_panic
;
3762 bool winbindd_cache_validate_and_initialize(void)
3764 close_winbindd_cache();
3766 if (lp_winbind_offline_logon()) {
3767 if (winbindd_validate_cache() < 0) {
3768 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
3769 "could be restored.\n"));
3773 return initialize_winbindd_cache();
3776 /*********************************************************************
3777 ********************************************************************/
3779 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
3780 struct winbindd_tdc_domain
**domains
,
3781 size_t *num_domains
)
3783 struct winbindd_tdc_domain
*list
= NULL
;
3786 bool set_only
= false;
3788 /* don't allow duplicates */
3793 for ( i
=0; i
< (*num_domains
); i
++ ) {
3794 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
3795 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
3806 list
= TALLOC_ARRAY( NULL
, struct winbindd_tdc_domain
, 1 );
3809 list
= TALLOC_REALLOC_ARRAY( *domains
, *domains
,
3810 struct winbindd_tdc_domain
,
3815 ZERO_STRUCT( list
[idx
] );
3821 list
[idx
].domain_name
= talloc_strdup( list
, new_dom
->name
);
3822 list
[idx
].dns_name
= talloc_strdup( list
, new_dom
->alt_name
);
3824 if ( !is_null_sid( &new_dom
->sid
) ) {
3825 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
3827 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
3830 if ( new_dom
->domain_flags
!= 0x0 )
3831 list
[idx
].trust_flags
= new_dom
->domain_flags
;
3833 if ( new_dom
->domain_type
!= 0x0 )
3834 list
[idx
].trust_type
= new_dom
->domain_type
;
3836 if ( new_dom
->domain_trust_attribs
!= 0x0 )
3837 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
3841 *num_domains
= idx
+ 1;
3847 /*********************************************************************
3848 ********************************************************************/
3850 static TDB_DATA
make_tdc_key( const char *domain_name
)
3852 char *keystr
= NULL
;
3853 TDB_DATA key
= { NULL
, 0 };
3855 if ( !domain_name
) {
3856 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
3861 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
3864 key
= string_term_tdb_data(keystr
);
3869 /*********************************************************************
3870 ********************************************************************/
3872 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
3874 unsigned char **buf
)
3876 unsigned char *buffer
= NULL
;
3881 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
3889 /* Store the number of array items first */
3890 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
3893 /* now pack each domain trust record */
3894 for ( i
=0; i
<num_domains
; i
++ ) {
3899 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
3900 domains
[i
].domain_name
,
3901 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
3904 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
3905 domains
[i
].domain_name
,
3906 domains
[i
].dns_name
,
3907 sid_to_fstring(tmp
, &domains
[i
].sid
),
3908 domains
[i
].trust_flags
,
3909 domains
[i
].trust_attribs
,
3910 domains
[i
].trust_type
);
3913 if ( buflen
< len
) {
3915 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
3916 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
3930 /*********************************************************************
3931 ********************************************************************/
3933 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
3934 struct winbindd_tdc_domain
**domains
)
3936 fstring domain_name
, dns_name
, sid_string
;
3937 uint32 type
, attribs
, flags
;
3941 struct winbindd_tdc_domain
*list
= NULL
;
3943 /* get the number of domains */
3944 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
3946 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3950 list
= TALLOC_ARRAY( NULL
, struct winbindd_tdc_domain
, num_domains
);
3952 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
3956 for ( i
=0; i
<num_domains
; i
++ ) {
3957 len
+= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
3966 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3967 TALLOC_FREE( list
);
3971 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
3972 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
3973 domain_name
, dns_name
, sid_string
,
3974 flags
, attribs
, type
));
3976 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
3977 list
[i
].dns_name
= talloc_strdup( list
, dns_name
);
3978 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
3979 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
3982 list
[i
].trust_flags
= flags
;
3983 list
[i
].trust_attribs
= attribs
;
3984 list
[i
].trust_type
= type
;
3992 /*********************************************************************
3993 ********************************************************************/
3995 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
3997 TDB_DATA key
= make_tdc_key( lp_workgroup() );
3998 TDB_DATA data
= { NULL
, 0 };
4004 /* See if we were asked to delete the cache entry */
4007 ret
= tdb_delete( wcache
->tdb
, key
);
4011 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4018 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4021 SAFE_FREE( data
.dptr
);
4022 SAFE_FREE( key
.dptr
);
4024 return ( ret
!= -1 );
4027 /*********************************************************************
4028 ********************************************************************/
4030 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4032 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4033 TDB_DATA data
= { NULL
, 0 };
4041 data
= tdb_fetch( wcache
->tdb
, key
);
4043 SAFE_FREE( key
.dptr
);
4048 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4050 SAFE_FREE( data
.dptr
);
4058 /*********************************************************************
4059 ********************************************************************/
4061 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4063 struct winbindd_tdc_domain
*dom_list
= NULL
;
4064 size_t num_domains
= 0;
4067 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4068 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4069 domain
->name
, domain
->alt_name
,
4070 sid_string_dbg(&domain
->sid
),
4071 domain
->domain_flags
,
4072 domain
->domain_trust_attribs
,
4073 domain
->domain_type
));
4075 if ( !init_wcache() ) {
4079 /* fetch the list */
4081 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4083 /* add the new domain */
4085 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4089 /* pack the domain */
4091 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4099 TALLOC_FREE( dom_list
);
4104 /*********************************************************************
4105 ********************************************************************/
4107 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4109 struct winbindd_tdc_domain
*dom_list
= NULL
;
4110 size_t num_domains
= 0;
4112 struct winbindd_tdc_domain
*d
= NULL
;
4114 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4116 if ( !init_wcache() ) {
4120 /* fetch the list */
4122 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4124 for ( i
=0; i
<num_domains
; i
++ ) {
4125 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4126 strequal(name
, dom_list
[i
].dns_name
) )
4128 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4131 d
= TALLOC_P( ctx
, struct winbindd_tdc_domain
);
4135 d
->domain_name
= talloc_strdup( d
, dom_list
[i
].domain_name
);
4136 d
->dns_name
= talloc_strdup( d
, dom_list
[i
].dns_name
);
4137 sid_copy( &d
->sid
, &dom_list
[i
].sid
);
4138 d
->trust_flags
= dom_list
[i
].trust_flags
;
4139 d
->trust_type
= dom_list
[i
].trust_type
;
4140 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
4146 TALLOC_FREE( dom_list
);
4152 /*********************************************************************
4153 ********************************************************************/
4155 void wcache_tdc_clear( void )
4157 if ( !init_wcache() )
4160 wcache_tdc_store_list( NULL
, 0 );
4166 /*********************************************************************
4167 ********************************************************************/
4169 static void wcache_save_user_pwinfo(struct winbindd_domain
*domain
,
4171 const DOM_SID
*user_sid
,
4172 const char *homedir
,
4177 struct cache_entry
*centry
;
4180 if ( (centry
= centry_start(domain
, status
)) == NULL
)
4183 centry_put_string( centry
, homedir
);
4184 centry_put_string( centry
, shell
);
4185 centry_put_string( centry
, gecos
);
4186 centry_put_uint32( centry
, gid
);
4188 centry_end(centry
, "NSS/PWINFO/%s", sid_to_fstring(tmp
, user_sid
) );
4190 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid
) ));
4192 centry_free(centry
);
4195 NTSTATUS
nss_get_info_cached( struct winbindd_domain
*domain
,
4196 const DOM_SID
*user_sid
,
4198 ADS_STRUCT
*ads
, LDAPMessage
*msg
,
4199 char **homedir
, char **shell
, char **gecos
,
4202 struct winbind_cache
*cache
= get_cache(domain
);
4203 struct cache_entry
*centry
= NULL
;
4210 centry
= wcache_fetch(cache
, domain
, "NSS/PWINFO/%s",
4211 sid_to_fstring(tmp
, user_sid
));
4216 *homedir
= centry_string( centry
, ctx
);
4217 *shell
= centry_string( centry
, ctx
);
4218 *gecos
= centry_string( centry
, ctx
);
4219 *p_gid
= centry_uint32( centry
);
4221 centry_free(centry
);
4223 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4224 sid_string_dbg(user_sid
)));
4226 return NT_STATUS_OK
;
4230 nt_status
= nss_get_info( domain
->name
, user_sid
, ctx
, ads
, msg
,
4231 homedir
, shell
, gecos
, p_gid
);
4233 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status
)));
4235 if ( NT_STATUS_IS_OK(nt_status
) ) {
4236 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir
));
4237 DEBUGADD(10, ("\tshell = '%s'\n", *shell
));
4238 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos
));
4239 DEBUGADD(10, ("\tgid = '%u'\n", *p_gid
));
4241 wcache_save_user_pwinfo( domain
, nt_status
, user_sid
,
4242 *homedir
, *shell
, *gecos
, *p_gid
);
4245 if ( NT_STATUS_EQUAL( nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
4246 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4248 set_domain_offline( domain
);
4255 /* the cache backend methods are exposed via this structure */
4256 struct winbindd_methods cache_methods
= {