2 Unix SMB/CIFS implementation.
4 Winbind cache backend functions
6 Copyright (C) Andrew Tridgell 2001
7 Copyright (C) Gerald Carter 2003
8 Copyright (C) Volker Lendecke 2005
9 Copyright (C) Guenther Deschner 2005
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30 #define DBGC_CLASS DBGC_WINBIND
32 #define WINBINDD_CACHE_VERSION 1
33 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
35 extern struct winbindd_methods reconnect_methods
;
36 extern BOOL opt_nocache
;
38 extern struct winbindd_methods ads_methods
;
42 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
43 * Here are the list of entry types that are *not* stored
44 * as form struct cache_entry in the cache.
47 static const char *non_centry_keys
[] = {
52 WINBINDD_CACHE_VERSION_KEYSTR
,
56 /************************************************************************
57 Is this key a non-centry type ?
58 ************************************************************************/
60 static BOOL
is_non_centry_key(TDB_DATA kbuf
)
64 if (kbuf
.dptr
== NULL
|| kbuf
.dsize
== 0) {
67 for (i
= 0; non_centry_keys
[i
] != NULL
; i
++) {
68 size_t namelen
= strlen(non_centry_keys
[i
]);
69 if (kbuf
.dsize
<= namelen
) {
72 if (strncmp(non_centry_keys
[i
], (const char *)kbuf
.dptr
, namelen
) == 0) {
79 /* Global online/offline state - False when online. winbindd starts up online
80 and sets this to true if the first query fails and there's an entry in
81 the cache tdb telling us to stay offline. */
83 static BOOL global_winbindd_offline_state
;
85 struct winbind_cache
{
91 uint32 sequence_number
;
96 void (*smb_panic_fn
)(const char *const why
) = smb_panic
;
98 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
100 static struct winbind_cache
*wcache
;
102 void winbindd_check_cache_size(time_t t
)
104 static time_t last_check_time
;
107 if (last_check_time
== (time_t)0)
110 if (t
- last_check_time
< 60 && t
- last_check_time
> 0)
113 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
114 DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
118 if (fstat(tdb_fd(wcache
->tdb
), &st
) == -1) {
119 DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno
) ));
123 if (st
.st_size
> WINBINDD_MAX_CACHE_SIZE
) {
124 DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
125 (unsigned long)st
.st_size
,
126 (unsigned long)WINBINDD_MAX_CACHE_SIZE
));
127 wcache_flush_cache();
131 /* get the winbind_cache structure */
132 static struct winbind_cache
*get_cache(struct winbindd_domain
*domain
)
134 struct winbind_cache
*ret
= wcache
;
136 struct winbindd_domain
*our_domain
= domain
;
139 /* We have to know what type of domain we are dealing with first. */
141 if ( !domain
->initialized
) {
142 init_dc_connection( domain
);
146 OK. listen up becasue I'm only going to say this once.
147 We have the following scenarios to consider
148 (a) trusted AD domains on a Samba DC,
149 (b) trusted AD domains and we are joined to a non-kerberos domain
150 (c) trusted AD domains and we are joined to a kerberos (AD) domain
152 For (a) we can always contact the trusted domain using krb5
153 since we have the domain trust account password
155 For (b) we can only use RPC since we have no way of
156 getting a krb5 ticket in our own domain
158 For (c) we can always use krb5 since we have a kerberos trust
163 if (!domain
->backend
) {
165 /* find our domain first so we can figure out if we
166 are joined to a kerberized domain */
168 if ( !domain
->primary
)
169 our_domain
= find_our_domain();
171 if ( (our_domain
->active_directory
|| IS_DC
) && domain
->active_directory
) {
172 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain
->name
));
173 domain
->backend
= &ads_methods
;
175 #endif /* HAVE_ADS */
176 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain
->name
));
177 domain
->backend
= &reconnect_methods
;
180 #endif /* HAVE_ADS */
186 ret
= SMB_XMALLOC_P(struct winbind_cache
);
190 wcache_flush_cache();
196 free a centry structure
198 static void centry_free(struct cache_entry
*centry
)
202 SAFE_FREE(centry
->data
);
206 static BOOL
centry_check_bytes(struct cache_entry
*centry
, size_t nbytes
)
208 if (centry
->len
- centry
->ofs
< nbytes
) {
209 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
210 (unsigned int)nbytes
,
211 centry
->len
- centry
->ofs
));
218 pull a uint32 from a cache entry
220 static uint32
centry_uint32(struct cache_entry
*centry
)
224 if (centry_check_bytes(centry
, 4)) {
225 smb_panic_fn("centry_uint32");
228 ret
= IVAL(centry
->data
, centry
->ofs
);
234 pull a uint16 from a cache entry
236 static uint16
centry_uint16(struct cache_entry
*centry
)
239 if (centry_check_bytes(centry
, 2)) {
240 smb_panic_fn("centry_uint16");
243 ret
= CVAL(centry
->data
, centry
->ofs
);
249 pull a uint8 from a cache entry
251 static uint8
centry_uint8(struct cache_entry
*centry
)
254 if (centry_check_bytes(centry
, 1)) {
255 smb_panic_fn("centry_uint8");
258 ret
= CVAL(centry
->data
, centry
->ofs
);
264 pull a NTTIME from a cache entry
266 static NTTIME
centry_nttime(struct cache_entry
*centry
)
269 if (centry_check_bytes(centry
, 8)) {
270 smb_panic_fn("centry_nttime");
273 ret
= IVAL(centry
->data
, centry
->ofs
);
275 ret
+= (uint64_t)IVAL(centry
->data
, centry
->ofs
) << 32;
281 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
283 static time_t centry_time(struct cache_entry
*centry
)
285 return (time_t)centry_nttime(centry
);
288 /* pull a string from a cache entry, using the supplied
291 static char *centry_string(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
296 len
= centry_uint8(centry
);
299 /* a deliberate NULL string */
303 if (centry_check_bytes(centry
, (size_t)len
)) {
304 smb_panic_fn("centry_string");
308 ret
= TALLOC_ARRAY(mem_ctx
, char, len
+1);
310 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");
344 memcpy(ret
,centry
->data
+ centry
->ofs
, 16);
349 /* pull a sid from a cache entry, using the supplied
352 static BOOL
centry_sid(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
, DOM_SID
*sid
)
355 sid_string
= centry_string(centry
, mem_ctx
);
356 if ((sid_string
== NULL
) || (!string_to_sid(sid
, sid_string
))) {
362 /* the server is considered down if it can't give us a sequence number */
363 static BOOL
wcache_server_down(struct winbindd_domain
*domain
)
370 ret
= (domain
->sequence_number
== DOM_SEQUENCE_NONE
);
373 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
378 static NTSTATUS
fetch_cache_seqnum( struct winbindd_domain
*domain
, time_t now
)
385 DEBUG(10,("fetch_cache_seqnum: tdb == NULL\n"));
386 return NT_STATUS_UNSUCCESSFUL
;
389 fstr_sprintf( key
, "SEQNUM/%s", domain
->name
);
391 data
= tdb_fetch_bystring( wcache
->tdb
, key
);
392 if ( !data
.dptr
|| data
.dsize
!=8 ) {
393 DEBUG(10,("fetch_cache_seqnum: invalid data size key [%s]\n", key
));
394 return NT_STATUS_UNSUCCESSFUL
;
397 domain
->sequence_number
= IVAL(data
.dptr
, 0);
398 domain
->last_seq_check
= IVAL(data
.dptr
, 4);
400 SAFE_FREE(data
.dptr
);
402 /* have we expired? */
404 time_diff
= now
- domain
->last_seq_check
;
405 if ( time_diff
> lp_winbind_cache_time() ) {
406 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
407 domain
->name
, domain
->sequence_number
,
408 (uint32
)domain
->last_seq_check
));
409 return NT_STATUS_UNSUCCESSFUL
;
412 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
413 domain
->name
, domain
->sequence_number
,
414 (uint32
)domain
->last_seq_check
));
419 static NTSTATUS
store_cache_seqnum( struct winbindd_domain
*domain
)
426 DEBUG(10,("store_cache_seqnum: tdb == NULL\n"));
427 return NT_STATUS_UNSUCCESSFUL
;
430 fstr_sprintf( key_str
, "SEQNUM/%s", domain
->name
);
432 SIVAL(buf
, 0, domain
->sequence_number
);
433 SIVAL(buf
, 4, domain
->last_seq_check
);
437 if ( tdb_store_bystring( wcache
->tdb
, key_str
, data
, TDB_REPLACE
) == -1 ) {
438 DEBUG(10,("store_cache_seqnum: tdb_store fail key [%s]\n", key_str
));
439 return NT_STATUS_UNSUCCESSFUL
;
442 DEBUG(10,("store_cache_seqnum: success [%s][%u @ %u]\n",
443 domain
->name
, domain
->sequence_number
,
444 (uint32
)domain
->last_seq_check
));
450 refresh the domain sequence number. If force is True
451 then always refresh it, no matter how recently we fetched it
454 static void refresh_sequence_number(struct winbindd_domain
*domain
, BOOL force
)
458 time_t t
= time(NULL
);
459 unsigned cache_time
= lp_winbind_cache_time();
463 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
464 /* trying to reconnect is expensive, don't do it too often */
465 if (domain
->sequence_number
== DOM_SEQUENCE_NONE
) {
470 time_diff
= t
- domain
->last_seq_check
;
472 /* see if we have to refetch the domain sequence number */
473 if (!force
&& (time_diff
< cache_time
)) {
474 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain
->name
));
478 /* try to get the sequence number from the tdb cache first */
479 /* this will update the timestamp as well */
481 status
= fetch_cache_seqnum( domain
, t
);
482 if ( NT_STATUS_IS_OK(status
) )
485 /* important! make sure that we know if this is a native
486 mode domain or not */
488 status
= domain
->backend
->sequence_number(domain
, &domain
->sequence_number
);
490 /* the above call could have set our domain->backend to NULL when
491 * coming from offline to online mode, make sure to reinitialize the
492 * backend - Guenther */
495 if (!NT_STATUS_IS_OK(status
)) {
496 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status
)));
497 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
500 domain
->last_status
= status
;
501 domain
->last_seq_check
= time(NULL
);
503 /* save the new sequence number ni the cache */
504 store_cache_seqnum( domain
);
507 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
508 domain
->name
, domain
->sequence_number
));
514 decide if a cache entry has expired
516 static BOOL
centry_expired(struct winbindd_domain
*domain
, const char *keystr
, struct cache_entry
*centry
)
518 /* If we've been told to be offline - stay in that state... */
519 if (lp_winbind_offline_logon() && global_winbindd_offline_state
) {
520 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
521 keystr
, domain
->name
));
525 /* when the domain is offline return the cached entry.
526 * This deals with transient offline states... */
528 if (!domain
->online
) {
529 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
530 keystr
, domain
->name
));
534 /* if the server is OK and our cache entry came from when it was down then
535 the entry is invalid */
536 if ((domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
537 (centry
->sequence_number
== DOM_SEQUENCE_NONE
)) {
538 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
539 keystr
, domain
->name
));
543 /* if the server is down or the cache entry is not older than the
544 current sequence number then it is OK */
545 if (wcache_server_down(domain
) ||
546 centry
->sequence_number
== domain
->sequence_number
) {
547 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
548 keystr
, domain
->name
));
552 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
553 keystr
, domain
->name
));
559 static struct cache_entry
*wcache_fetch_raw(char *kstr
)
562 struct cache_entry
*centry
;
565 key
= string_tdb_data(kstr
);
566 data
= tdb_fetch(wcache
->tdb
, key
);
572 centry
= SMB_XMALLOC_P(struct cache_entry
);
573 centry
->data
= (unsigned char *)data
.dptr
;
574 centry
->len
= data
.dsize
;
577 if (centry
->len
< 8) {
578 /* huh? corrupt cache? */
579 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr
));
584 centry
->status
= NT_STATUS(centry_uint32(centry
));
585 centry
->sequence_number
= centry_uint32(centry
);
591 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
592 number and return status
594 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
595 struct winbindd_domain
*domain
,
596 const char *format
, ...) PRINTF_ATTRIBUTE(3,4);
597 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
598 struct winbindd_domain
*domain
,
599 const char *format
, ...)
603 struct cache_entry
*centry
;
609 refresh_sequence_number(domain
, False
);
611 va_start(ap
, format
);
612 smb_xvasprintf(&kstr
, format
, ap
);
615 centry
= wcache_fetch_raw(kstr
);
616 if (centry
== NULL
) {
621 if (centry_expired(domain
, kstr
, centry
)) {
623 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
624 kstr
, domain
->name
));
631 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
632 kstr
, domain
->name
));
638 static void wcache_delete(const char *format
, ...) PRINTF_ATTRIBUTE(1,2);
639 static void wcache_delete(const char *format
, ...)
645 va_start(ap
, format
);
646 smb_xvasprintf(&kstr
, format
, ap
);
649 key
= string_tdb_data(kstr
);
651 tdb_delete(wcache
->tdb
, key
);
656 make sure we have at least len bytes available in a centry
658 static void centry_expand(struct cache_entry
*centry
, uint32 len
)
660 if (centry
->len
- centry
->ofs
>= len
)
663 centry
->data
= SMB_REALLOC_ARRAY(centry
->data
, unsigned char,
666 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry
->len
));
667 smb_panic_fn("out of memory in centry_expand");
672 push a uint32 into a centry
674 static void centry_put_uint32(struct cache_entry
*centry
, uint32 v
)
676 centry_expand(centry
, 4);
677 SIVAL(centry
->data
, centry
->ofs
, v
);
682 push a uint16 into a centry
684 static void centry_put_uint16(struct cache_entry
*centry
, uint16 v
)
686 centry_expand(centry
, 2);
687 SIVAL(centry
->data
, centry
->ofs
, v
);
692 push a uint8 into a centry
694 static void centry_put_uint8(struct cache_entry
*centry
, uint8 v
)
696 centry_expand(centry
, 1);
697 SCVAL(centry
->data
, centry
->ofs
, v
);
702 push a string into a centry
704 static void centry_put_string(struct cache_entry
*centry
, const char *s
)
709 /* null strings are marked as len 0xFFFF */
710 centry_put_uint8(centry
, 0xFF);
715 /* can't handle more than 254 char strings. Truncating is probably best */
717 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len
));
720 centry_put_uint8(centry
, len
);
721 centry_expand(centry
, len
);
722 memcpy(centry
->data
+ centry
->ofs
, s
, len
);
727 push a 16 byte hash into a centry - treat as 16 byte string.
729 static void centry_put_hash16(struct cache_entry
*centry
, const uint8 val
[16])
731 centry_put_uint8(centry
, 16);
732 centry_expand(centry
, 16);
733 memcpy(centry
->data
+ centry
->ofs
, val
, 16);
737 static void centry_put_sid(struct cache_entry
*centry
, const DOM_SID
*sid
)
740 centry_put_string(centry
, sid_to_string(sid_string
, sid
));
744 push a NTTIME into a centry
746 static void centry_put_nttime(struct cache_entry
*centry
, NTTIME nt
)
748 centry_expand(centry
, 8);
749 SIVAL(centry
->data
, centry
->ofs
, nt
& 0xFFFFFFFF);
751 SIVAL(centry
->data
, centry
->ofs
, nt
>> 32);
756 push a time_t into a centry - use a 64 bit size.
757 NTTIME here is being used as a convenient 64-bit size.
759 static void centry_put_time(struct cache_entry
*centry
, time_t t
)
761 NTTIME nt
= (NTTIME
)t
;
762 return centry_put_nttime(centry
, nt
);
766 start a centry for output. When finished, call centry_end()
768 struct cache_entry
*centry_start(struct winbindd_domain
*domain
, NTSTATUS status
)
770 struct cache_entry
*centry
;
775 centry
= SMB_XMALLOC_P(struct cache_entry
);
777 centry
->len
= 8192; /* reasonable default */
778 centry
->data
= SMB_XMALLOC_ARRAY(uint8
, centry
->len
);
780 centry
->sequence_number
= domain
->sequence_number
;
781 centry_put_uint32(centry
, NT_STATUS_V(status
));
782 centry_put_uint32(centry
, centry
->sequence_number
);
787 finish a centry and write it to the tdb
789 static void centry_end(struct cache_entry
*centry
, const char *format
, ...) PRINTF_ATTRIBUTE(2,3);
790 static void centry_end(struct cache_entry
*centry
, const char *format
, ...)
796 va_start(ap
, format
);
797 smb_xvasprintf(&kstr
, format
, ap
);
800 key
= string_tdb_data(kstr
);
801 data
.dptr
= centry
->data
;
802 data
.dsize
= centry
->ofs
;
804 tdb_store(wcache
->tdb
, key
, data
, TDB_REPLACE
);
808 static void wcache_save_name_to_sid(struct winbindd_domain
*domain
,
809 NTSTATUS status
, const char *domain_name
,
810 const char *name
, const DOM_SID
*sid
,
811 enum lsa_SidType type
)
813 struct cache_entry
*centry
;
816 centry
= centry_start(domain
, status
);
819 centry_put_uint32(centry
, type
);
820 centry_put_sid(centry
, sid
);
821 fstrcpy(uname
, name
);
823 centry_end(centry
, "NS/%s/%s", domain_name
, uname
);
824 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s\n", domain_name
, uname
,
825 sid_string_static(sid
)));
829 static void wcache_save_sid_to_name(struct winbindd_domain
*domain
, NTSTATUS status
,
830 const DOM_SID
*sid
, const char *domain_name
, const char *name
, enum lsa_SidType type
)
832 struct cache_entry
*centry
;
835 if (is_null_sid(sid
)) {
839 centry
= centry_start(domain
, status
);
842 if (NT_STATUS_IS_OK(status
)) {
843 centry_put_uint32(centry
, type
);
844 centry_put_string(centry
, domain_name
);
845 centry_put_string(centry
, name
);
847 centry_end(centry
, "SN/%s", sid_to_string(sid_string
, sid
));
848 DEBUG(10,("wcache_save_sid_to_name: %s -> %s\n", sid_string
, name
));
853 static void wcache_save_user(struct winbindd_domain
*domain
, NTSTATUS status
, WINBIND_USERINFO
*info
)
855 struct cache_entry
*centry
;
858 if (is_null_sid(&info
->user_sid
)) {
862 centry
= centry_start(domain
, status
);
865 centry_put_string(centry
, info
->acct_name
);
866 centry_put_string(centry
, info
->full_name
);
867 centry_put_string(centry
, info
->homedir
);
868 centry_put_string(centry
, info
->shell
);
869 centry_put_uint32(centry
, info
->primary_gid
);
870 centry_put_sid(centry
, &info
->user_sid
);
871 centry_put_sid(centry
, &info
->group_sid
);
872 centry_end(centry
, "U/%s", sid_to_string(sid_string
, &info
->user_sid
));
873 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string
, info
->acct_name
));
877 static void wcache_save_lockout_policy(struct winbindd_domain
*domain
, NTSTATUS status
, SAM_UNK_INFO_12
*lockout_policy
)
879 struct cache_entry
*centry
;
881 centry
= centry_start(domain
, status
);
885 centry_put_nttime(centry
, lockout_policy
->duration
);
886 centry_put_nttime(centry
, lockout_policy
->reset_count
);
887 centry_put_uint16(centry
, lockout_policy
->bad_attempt_lockout
);
889 centry_end(centry
, "LOC_POL/%s", domain
->name
);
891 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain
->name
));
896 static void wcache_save_password_policy(struct winbindd_domain
*domain
, NTSTATUS status
, SAM_UNK_INFO_1
*policy
)
898 struct cache_entry
*centry
;
900 centry
= centry_start(domain
, status
);
904 centry_put_uint16(centry
, policy
->min_length_password
);
905 centry_put_uint16(centry
, policy
->password_history
);
906 centry_put_uint32(centry
, policy
->password_properties
);
907 centry_put_nttime(centry
, policy
->expire
);
908 centry_put_nttime(centry
, policy
->min_passwordage
);
910 centry_end(centry
, "PWD_POL/%s", domain
->name
);
912 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
917 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const DOM_SID
*sid
)
919 struct winbind_cache
*cache
= get_cache(domain
);
925 return NT_STATUS_INTERNAL_DB_ERROR
;
928 if (is_null_sid(sid
)) {
929 return NT_STATUS_INVALID_SID
;
932 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
933 return NT_STATUS_INVALID_SID
;
936 fstr_sprintf(key_str
, "CRED/%s", sid_string_static(sid
));
938 data
= tdb_fetch(cache
->tdb
, string_tdb_data(key_str
));
940 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
943 SAFE_FREE(data
.dptr
);
947 /* Lookup creds for a SID - copes with old (unsalted) creds as well
948 as new salted ones. */
950 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
953 const uint8
**cached_nt_pass
,
954 const uint8
**cached_salt
)
956 struct winbind_cache
*cache
= get_cache(domain
);
957 struct cache_entry
*centry
= NULL
;
963 return NT_STATUS_INTERNAL_DB_ERROR
;
966 if (is_null_sid(sid
)) {
967 return NT_STATUS_INVALID_SID
;
970 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
971 return NT_STATUS_INVALID_SID
;
974 /* Try and get a salted cred first. If we can't
975 fall back to an unsalted cred. */
977 centry
= wcache_fetch(cache
, domain
, "CRED/%s", sid_string_static(sid
));
979 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
980 sid_string_static(sid
)));
981 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
984 t
= centry_time(centry
);
986 /* In the salted case this isn't actually the nt_hash itself,
987 but the MD5 of the salt + nt_hash. Let the caller
988 sort this out. It can tell as we only return the cached_salt
989 if we are returning a salted cred. */
991 *cached_nt_pass
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
992 if (*cached_nt_pass
== NULL
) {
993 const char *sidstr
= sid_string_static(sid
);
995 /* Bad (old) cred cache. Delete and pretend we
997 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
999 wcache_delete("CRED/%s", sidstr
);
1000 centry_free(centry
);
1001 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1004 /* We only have 17 bytes more data in the salted cred case. */
1005 if (centry
->len
- centry
->ofs
== 17) {
1006 *cached_salt
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1008 *cached_salt
= NULL
;
1012 dump_data(100, *cached_nt_pass
, NT_HASH_LEN
);
1014 dump_data(100, *cached_salt
, NT_HASH_LEN
);
1017 status
= centry
->status
;
1019 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1020 sid_string_static(sid
), nt_errstr(status
) ));
1022 centry_free(centry
);
1026 /* Store creds for a SID - only writes out new salted ones. */
1028 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1029 TALLOC_CTX
*mem_ctx
,
1031 const uint8 nt_pass
[NT_HASH_LEN
])
1033 struct cache_entry
*centry
;
1036 uint8 cred_salt
[NT_HASH_LEN
];
1037 uint8 salted_hash
[NT_HASH_LEN
];
1039 if (is_null_sid(sid
)) {
1040 return NT_STATUS_INVALID_SID
;
1043 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1044 return NT_STATUS_INVALID_SID
;
1047 centry
= centry_start(domain
, NT_STATUS_OK
);
1049 return NT_STATUS_INTERNAL_DB_ERROR
;
1053 dump_data(100, nt_pass
, NT_HASH_LEN
);
1056 centry_put_time(centry
, time(NULL
));
1058 /* Create a salt and then salt the hash. */
1059 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1060 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1062 centry_put_hash16(centry
, salted_hash
);
1063 centry_put_hash16(centry
, cred_salt
);
1064 centry_end(centry
, "CRED/%s", sid_to_string(sid_string
, sid
));
1066 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1068 centry_free(centry
);
1070 return NT_STATUS_OK
;
1074 /* Query display info. This is the basic user list fn */
1075 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
1076 TALLOC_CTX
*mem_ctx
,
1077 uint32
*num_entries
,
1078 WINBIND_USERINFO
**info
)
1080 struct winbind_cache
*cache
= get_cache(domain
);
1081 struct cache_entry
*centry
= NULL
;
1083 unsigned int i
, retry
;
1088 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1092 *num_entries
= centry_uint32(centry
);
1094 if (*num_entries
== 0)
1097 (*info
) = TALLOC_ARRAY(mem_ctx
, WINBIND_USERINFO
, *num_entries
);
1099 smb_panic_fn("query_user_list out of memory");
1100 centry_free(centry
);
1101 return NT_STATUS_NO_MEMORY
;
1103 for (i
=0; i
<(*num_entries
); i
++) {
1104 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
1105 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
1106 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
1107 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
1108 centry_sid(centry
, mem_ctx
, &(*info
)[i
].user_sid
);
1109 centry_sid(centry
, mem_ctx
, &(*info
)[i
].group_sid
);
1113 status
= centry
->status
;
1115 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1116 domain
->name
, nt_errstr(status
) ));
1118 centry_free(centry
);
1125 /* Return status value returned by seq number check */
1127 if (!NT_STATUS_IS_OK(domain
->last_status
))
1128 return domain
->last_status
;
1130 /* Put the query_user_list() in a retry loop. There appears to be
1131 * some bug either with Windows 2000 or Samba's handling of large
1132 * rpc replies. This manifests itself as sudden disconnection
1133 * at a random point in the enumeration of a large (60k) user list.
1134 * The retry loop simply tries the operation again. )-: It's not
1135 * pretty but an acceptable workaround until we work out what the
1136 * real problem is. */
1141 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1144 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
1145 if (!NT_STATUS_IS_OK(status
))
1146 DEBUG(3, ("query_user_list: returned 0x%08x, "
1147 "retrying\n", NT_STATUS_V(status
)));
1148 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1149 DEBUG(3, ("query_user_list: flushing "
1150 "connection cache\n"));
1151 invalidate_cm_connection(&domain
->conn
);
1154 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1158 refresh_sequence_number(domain
, False
);
1159 centry
= centry_start(domain
, status
);
1162 centry_put_uint32(centry
, *num_entries
);
1163 for (i
=0; i
<(*num_entries
); i
++) {
1164 centry_put_string(centry
, (*info
)[i
].acct_name
);
1165 centry_put_string(centry
, (*info
)[i
].full_name
);
1166 centry_put_string(centry
, (*info
)[i
].homedir
);
1167 centry_put_string(centry
, (*info
)[i
].shell
);
1168 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1169 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1170 if (domain
->backend
&& domain
->backend
->consistent
) {
1171 /* when the backend is consistent we can pre-prime some mappings */
1172 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1174 (*info
)[i
].acct_name
,
1175 &(*info
)[i
].user_sid
,
1177 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1178 &(*info
)[i
].user_sid
,
1180 (*info
)[i
].acct_name
,
1182 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1185 centry_end(centry
, "UL/%s", domain
->name
);
1186 centry_free(centry
);
1192 /* list all domain groups */
1193 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
1194 TALLOC_CTX
*mem_ctx
,
1195 uint32
*num_entries
,
1196 struct acct_info
**info
)
1198 struct winbind_cache
*cache
= get_cache(domain
);
1199 struct cache_entry
*centry
= NULL
;
1206 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1210 *num_entries
= centry_uint32(centry
);
1212 if (*num_entries
== 0)
1215 (*info
) = TALLOC_ARRAY(mem_ctx
, struct acct_info
, *num_entries
);
1217 smb_panic_fn("enum_dom_groups out of memory");
1218 centry_free(centry
);
1219 return NT_STATUS_NO_MEMORY
;
1221 for (i
=0; i
<(*num_entries
); i
++) {
1222 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1223 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1224 (*info
)[i
].rid
= centry_uint32(centry
);
1228 status
= centry
->status
;
1230 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1231 domain
->name
, nt_errstr(status
) ));
1233 centry_free(centry
);
1240 /* Return status value returned by seq number check */
1242 if (!NT_STATUS_IS_OK(domain
->last_status
))
1243 return domain
->last_status
;
1245 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1248 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1251 refresh_sequence_number(domain
, False
);
1252 centry
= centry_start(domain
, status
);
1255 centry_put_uint32(centry
, *num_entries
);
1256 for (i
=0; i
<(*num_entries
); i
++) {
1257 centry_put_string(centry
, (*info
)[i
].acct_name
);
1258 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1259 centry_put_uint32(centry
, (*info
)[i
].rid
);
1261 centry_end(centry
, "GL/%s/domain", domain
->name
);
1262 centry_free(centry
);
1268 /* list all domain groups */
1269 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
1270 TALLOC_CTX
*mem_ctx
,
1271 uint32
*num_entries
,
1272 struct acct_info
**info
)
1274 struct winbind_cache
*cache
= get_cache(domain
);
1275 struct cache_entry
*centry
= NULL
;
1282 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1286 *num_entries
= centry_uint32(centry
);
1288 if (*num_entries
== 0)
1291 (*info
) = TALLOC_ARRAY(mem_ctx
, struct acct_info
, *num_entries
);
1293 smb_panic_fn("enum_dom_groups out of memory");
1294 centry_free(centry
);
1295 return NT_STATUS_NO_MEMORY
;
1297 for (i
=0; i
<(*num_entries
); i
++) {
1298 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1299 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1300 (*info
)[i
].rid
= centry_uint32(centry
);
1305 /* If we are returning cached data and the domain controller
1306 is down then we don't know whether the data is up to date
1307 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1310 if (wcache_server_down(domain
)) {
1311 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1312 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1314 status
= centry
->status
;
1316 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1317 domain
->name
, nt_errstr(status
) ));
1319 centry_free(centry
);
1326 /* Return status value returned by seq number check */
1328 if (!NT_STATUS_IS_OK(domain
->last_status
))
1329 return domain
->last_status
;
1331 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1334 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1337 refresh_sequence_number(domain
, False
);
1338 centry
= centry_start(domain
, status
);
1341 centry_put_uint32(centry
, *num_entries
);
1342 for (i
=0; i
<(*num_entries
); i
++) {
1343 centry_put_string(centry
, (*info
)[i
].acct_name
);
1344 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1345 centry_put_uint32(centry
, (*info
)[i
].rid
);
1347 centry_end(centry
, "GL/%s/local", domain
->name
);
1348 centry_free(centry
);
1354 /* convert a single name to a sid in a domain */
1355 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
1356 TALLOC_CTX
*mem_ctx
,
1357 const char *domain_name
,
1360 enum lsa_SidType
*type
)
1362 struct winbind_cache
*cache
= get_cache(domain
);
1363 struct cache_entry
*centry
= NULL
;
1370 fstrcpy(uname
, name
);
1372 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1375 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1376 status
= centry
->status
;
1377 if (NT_STATUS_IS_OK(status
)) {
1378 centry_sid(centry
, mem_ctx
, sid
);
1381 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: %s\n",
1382 domain
->name
, nt_errstr(status
) ));
1384 centry_free(centry
);
1390 /* If the seq number check indicated that there is a problem
1391 * with this DC, then return that status... except for
1392 * access_denied. This is special because the dc may be in
1393 * "restrict anonymous = 1" mode, in which case it will deny
1394 * most unauthenticated operations, but *will* allow the LSA
1395 * name-to-sid that we try as a fallback. */
1397 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1398 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1399 return domain
->last_status
;
1401 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1404 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
, name
, sid
, type
);
1407 refresh_sequence_number(domain
, False
);
1409 if (domain
->online
&& !is_null_sid(sid
)) {
1410 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1413 if (NT_STATUS_IS_OK(status
)) {
1414 strupper_m(CONST_DISCARD(char *,domain_name
));
1415 strlower_m(CONST_DISCARD(char *,name
));
1416 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1422 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1424 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1425 TALLOC_CTX
*mem_ctx
,
1429 enum lsa_SidType
*type
)
1431 struct winbind_cache
*cache
= get_cache(domain
);
1432 struct cache_entry
*centry
= NULL
;
1439 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_to_string(sid_string
, sid
));
1442 if (NT_STATUS_IS_OK(centry
->status
)) {
1443 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1444 *domain_name
= centry_string(centry
, mem_ctx
);
1445 *name
= centry_string(centry
, mem_ctx
);
1447 status
= centry
->status
;
1449 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: %s\n",
1450 domain
->name
, nt_errstr(status
) ));
1452 centry_free(centry
);
1457 *domain_name
= NULL
;
1459 /* If the seq number check indicated that there is a problem
1460 * with this DC, then return that status... except for
1461 * access_denied. This is special because the dc may be in
1462 * "restrict anonymous = 1" mode, in which case it will deny
1463 * most unauthenticated operations, but *will* allow the LSA
1464 * sid-to-name that we try as a fallback. */
1466 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1467 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1468 return domain
->last_status
;
1470 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1473 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1476 refresh_sequence_number(domain
, False
);
1477 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
1479 /* We can't save the name to sid mapping here, as with sid history a
1480 * later name2sid would give the wrong sid. */
1485 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
1486 TALLOC_CTX
*mem_ctx
,
1487 const DOM_SID
*domain_sid
,
1492 enum lsa_SidType
**types
)
1494 struct winbind_cache
*cache
= get_cache(domain
);
1496 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1500 *domain_name
= NULL
;
1508 if (num_rids
== 0) {
1509 return NT_STATUS_OK
;
1512 *names
= TALLOC_ARRAY(mem_ctx
, char *, num_rids
);
1513 *types
= TALLOC_ARRAY(mem_ctx
, enum lsa_SidType
, num_rids
);
1515 if ((*names
== NULL
) || (*types
== NULL
)) {
1516 result
= NT_STATUS_NO_MEMORY
;
1520 have_mapped
= have_unmapped
= False
;
1522 for (i
=0; i
<num_rids
; i
++) {
1524 struct cache_entry
*centry
;
1526 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
1527 result
= NT_STATUS_INTERNAL_ERROR
;
1531 centry
= wcache_fetch(cache
, domain
, "SN/%s",
1532 sid_string_static(&sid
));
1537 (*types
)[i
] = SID_NAME_UNKNOWN
;
1538 (*names
)[i
] = talloc_strdup(*names
, "");
1540 if (NT_STATUS_IS_OK(centry
->status
)) {
1543 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
1544 dom
= centry_string(centry
, mem_ctx
);
1545 if (*domain_name
== NULL
) {
1550 (*names
)[i
] = centry_string(centry
, *names
);
1552 have_unmapped
= True
;
1555 centry_free(centry
);
1559 return NT_STATUS_NONE_MAPPED
;
1561 if (!have_unmapped
) {
1562 return NT_STATUS_OK
;
1564 return STATUS_SOME_UNMAPPED
;
1568 TALLOC_FREE(*names
);
1569 TALLOC_FREE(*types
);
1571 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
1572 rids
, num_rids
, domain_name
,
1575 if (!NT_STATUS_IS_OK(result
) &&
1576 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
1580 refresh_sequence_number(domain
, False
);
1582 for (i
=0; i
<num_rids
; i
++) {
1586 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
1587 result
= NT_STATUS_INTERNAL_ERROR
;
1591 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
1592 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
1594 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
1595 (*names
)[i
], (*types
)[i
]);
1602 TALLOC_FREE(*names
);
1603 TALLOC_FREE(*types
);
1607 /* Lookup user information from a rid */
1608 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
1609 TALLOC_CTX
*mem_ctx
,
1610 const DOM_SID
*user_sid
,
1611 WINBIND_USERINFO
*info
)
1613 struct winbind_cache
*cache
= get_cache(domain
);
1614 struct cache_entry
*centry
= NULL
;
1620 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string_static(user_sid
));
1622 /* If we have an access denied cache entry and a cached info3 in the
1623 samlogon cache then do a query. This will force the rpc back end
1624 to return the info3 data. */
1626 if (NT_STATUS_V(domain
->last_status
) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED
) &&
1627 netsamlogon_cache_have(user_sid
)) {
1628 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1629 domain
->last_status
= NT_STATUS_OK
;
1630 centry_free(centry
);
1637 info
->acct_name
= centry_string(centry
, mem_ctx
);
1638 info
->full_name
= centry_string(centry
, mem_ctx
);
1639 info
->homedir
= centry_string(centry
, mem_ctx
);
1640 info
->shell
= centry_string(centry
, mem_ctx
);
1641 info
->primary_gid
= centry_uint32(centry
);
1642 centry_sid(centry
, mem_ctx
, &info
->user_sid
);
1643 centry_sid(centry
, mem_ctx
, &info
->group_sid
);
1644 status
= centry
->status
;
1646 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: %s\n",
1647 domain
->name
, nt_errstr(status
) ));
1649 centry_free(centry
);
1655 /* Return status value returned by seq number check */
1657 if (!NT_STATUS_IS_OK(domain
->last_status
))
1658 return domain
->last_status
;
1660 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
1663 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
1666 refresh_sequence_number(domain
, False
);
1667 wcache_save_user(domain
, status
, info
);
1673 /* Lookup groups a user is a member of. */
1674 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
1675 TALLOC_CTX
*mem_ctx
,
1676 const DOM_SID
*user_sid
,
1677 uint32
*num_groups
, DOM_SID
**user_gids
)
1679 struct winbind_cache
*cache
= get_cache(domain
);
1680 struct cache_entry
*centry
= NULL
;
1688 centry
= wcache_fetch(cache
, domain
, "UG/%s", sid_to_string(sid_string
, user_sid
));
1690 /* If we have an access denied cache entry and a cached info3 in the
1691 samlogon cache then do a query. This will force the rpc back end
1692 to return the info3 data. */
1694 if (NT_STATUS_V(domain
->last_status
) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED
) &&
1695 netsamlogon_cache_have(user_sid
)) {
1696 DEBUG(10, ("lookup_usergroups: cached access denied and have cached info3\n"));
1697 domain
->last_status
= NT_STATUS_OK
;
1698 centry_free(centry
);
1705 *num_groups
= centry_uint32(centry
);
1707 if (*num_groups
== 0)
1710 (*user_gids
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_groups
);
1711 if (! (*user_gids
)) {
1712 smb_panic_fn("lookup_usergroups out of memory");
1713 centry_free(centry
);
1714 return NT_STATUS_NO_MEMORY
;
1716 for (i
=0; i
<(*num_groups
); i
++) {
1717 centry_sid(centry
, mem_ctx
, &(*user_gids
)[i
]);
1721 status
= centry
->status
;
1723 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status: %s\n",
1724 domain
->name
, nt_errstr(status
) ));
1726 centry_free(centry
);
1731 (*user_gids
) = NULL
;
1733 /* Return status value returned by seq number check */
1735 if (!NT_STATUS_IS_OK(domain
->last_status
))
1736 return domain
->last_status
;
1738 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
1741 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
1744 refresh_sequence_number(domain
, False
);
1745 centry
= centry_start(domain
, status
);
1748 centry_put_uint32(centry
, *num_groups
);
1749 for (i
=0; i
<(*num_groups
); i
++) {
1750 centry_put_sid(centry
, &(*user_gids
)[i
]);
1752 centry_end(centry
, "UG/%s", sid_to_string(sid_string
, user_sid
));
1753 centry_free(centry
);
1759 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
1760 TALLOC_CTX
*mem_ctx
,
1761 uint32 num_sids
, const DOM_SID
*sids
,
1762 uint32
*num_aliases
, uint32
**alias_rids
)
1764 struct winbind_cache
*cache
= get_cache(domain
);
1765 struct cache_entry
*centry
= NULL
;
1767 char *sidlist
= talloc_strdup(mem_ctx
, "");
1773 if (num_sids
== 0) {
1776 return NT_STATUS_OK
;
1779 /* We need to cache indexed by the whole list of SIDs, the aliases
1780 * resulting might come from any of the SIDs. */
1782 for (i
=0; i
<num_sids
; i
++) {
1783 sidlist
= talloc_asprintf(mem_ctx
, "%s/%s", sidlist
,
1784 sid_string_static(&sids
[i
]));
1785 if (sidlist
== NULL
)
1786 return NT_STATUS_NO_MEMORY
;
1789 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
1794 *num_aliases
= centry_uint32(centry
);
1797 (*alias_rids
) = TALLOC_ARRAY(mem_ctx
, uint32
, *num_aliases
);
1799 if ((*num_aliases
!= 0) && ((*alias_rids
) == NULL
)) {
1800 centry_free(centry
);
1801 return NT_STATUS_NO_MEMORY
;
1804 for (i
=0; i
<(*num_aliases
); i
++)
1805 (*alias_rids
)[i
] = centry_uint32(centry
);
1807 status
= centry
->status
;
1809 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
1810 "status %s\n", domain
->name
, nt_errstr(status
)));
1812 centry_free(centry
);
1817 (*alias_rids
) = NULL
;
1819 if (!NT_STATUS_IS_OK(domain
->last_status
))
1820 return domain
->last_status
;
1822 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
1823 "for domain %s\n", domain
->name
));
1825 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
1827 num_aliases
, alias_rids
);
1830 refresh_sequence_number(domain
, False
);
1831 centry
= centry_start(domain
, status
);
1834 centry_put_uint32(centry
, *num_aliases
);
1835 for (i
=0; i
<(*num_aliases
); i
++)
1836 centry_put_uint32(centry
, (*alias_rids
)[i
]);
1837 centry_end(centry
, "UA%s", sidlist
);
1838 centry_free(centry
);
1845 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
1846 TALLOC_CTX
*mem_ctx
,
1847 const DOM_SID
*group_sid
, uint32
*num_names
,
1848 DOM_SID
**sid_mem
, char ***names
,
1849 uint32
**name_types
)
1851 struct winbind_cache
*cache
= get_cache(domain
);
1852 struct cache_entry
*centry
= NULL
;
1860 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_to_string(sid_string
, group_sid
));
1864 *num_names
= centry_uint32(centry
);
1866 if (*num_names
== 0)
1869 (*sid_mem
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_names
);
1870 (*names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_names
);
1871 (*name_types
) = TALLOC_ARRAY(mem_ctx
, uint32
, *num_names
);
1873 if (! (*sid_mem
) || ! (*names
) || ! (*name_types
)) {
1874 smb_panic_fn("lookup_groupmem out of memory");
1875 centry_free(centry
);
1876 return NT_STATUS_NO_MEMORY
;
1879 for (i
=0; i
<(*num_names
); i
++) {
1880 centry_sid(centry
, mem_ctx
, &(*sid_mem
)[i
]);
1881 (*names
)[i
] = centry_string(centry
, mem_ctx
);
1882 (*name_types
)[i
] = centry_uint32(centry
);
1886 status
= centry
->status
;
1888 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status: %s\n",
1889 domain
->name
, nt_errstr(status
)));
1891 centry_free(centry
);
1898 (*name_types
) = NULL
;
1900 /* Return status value returned by seq number check */
1902 if (!NT_STATUS_IS_OK(domain
->last_status
))
1903 return domain
->last_status
;
1905 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
1908 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
1909 sid_mem
, names
, name_types
);
1912 refresh_sequence_number(domain
, False
);
1913 centry
= centry_start(domain
, status
);
1916 centry_put_uint32(centry
, *num_names
);
1917 for (i
=0; i
<(*num_names
); i
++) {
1918 centry_put_sid(centry
, &(*sid_mem
)[i
]);
1919 centry_put_string(centry
, (*names
)[i
]);
1920 centry_put_uint32(centry
, (*name_types
)[i
]);
1922 centry_end(centry
, "GM/%s", sid_to_string(sid_string
, group_sid
));
1923 centry_free(centry
);
1929 /* find the sequence number for a domain */
1930 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
1932 refresh_sequence_number(domain
, False
);
1934 *seq
= domain
->sequence_number
;
1936 return NT_STATUS_OK
;
1939 /* enumerate trusted domains
1940 * (we need to have the list of trustdoms in the cache when we go offline) -
1942 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
1943 TALLOC_CTX
*mem_ctx
,
1944 uint32
*num_domains
,
1949 struct winbind_cache
*cache
= get_cache(domain
);
1950 struct cache_entry
*centry
= NULL
;
1957 centry
= wcache_fetch(cache
, domain
, "TRUSTDOMS/%s", domain
->name
);
1963 *num_domains
= centry_uint32(centry
);
1965 (*names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
1966 (*alt_names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
1967 (*dom_sids
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_domains
);
1969 if (! (*dom_sids
) || ! (*names
) || ! (*alt_names
)) {
1970 smb_panic_fn("trusted_domains out of memory");
1971 centry_free(centry
);
1972 return NT_STATUS_NO_MEMORY
;
1975 for (i
=0; i
<(*num_domains
); i
++) {
1976 (*names
)[i
] = centry_string(centry
, mem_ctx
);
1977 (*alt_names
)[i
] = centry_string(centry
, mem_ctx
);
1978 centry_sid(centry
, mem_ctx
, &(*dom_sids
)[i
]);
1981 status
= centry
->status
;
1983 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
1984 domain
->name
, *num_domains
, nt_errstr(status
) ));
1986 centry_free(centry
);
1993 (*alt_names
) = NULL
;
1995 /* Return status value returned by seq number check */
1997 if (!NT_STATUS_IS_OK(domain
->last_status
))
1998 return domain
->last_status
;
2000 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2003 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, num_domains
,
2004 names
, alt_names
, dom_sids
);
2006 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2007 * so that the generic centry handling still applies correctly -
2010 if (!NT_STATUS_IS_ERR(status
)) {
2011 status
= NT_STATUS_OK
;
2015 refresh_sequence_number(domain
, False
);
2017 centry
= centry_start(domain
, status
);
2021 centry_put_uint32(centry
, *num_domains
);
2023 for (i
=0; i
<(*num_domains
); i
++) {
2024 centry_put_string(centry
, (*names
)[i
]);
2025 centry_put_string(centry
, (*alt_names
)[i
]);
2026 centry_put_sid(centry
, &(*dom_sids
)[i
]);
2029 centry_end(centry
, "TRUSTDOMS/%s", domain
->name
);
2031 centry_free(centry
);
2037 /* get lockout policy */
2038 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
2039 TALLOC_CTX
*mem_ctx
,
2040 SAM_UNK_INFO_12
*policy
){
2041 struct winbind_cache
*cache
= get_cache(domain
);
2042 struct cache_entry
*centry
= NULL
;
2048 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2053 policy
->duration
= centry_nttime(centry
);
2054 policy
->reset_count
= centry_nttime(centry
);
2055 policy
->bad_attempt_lockout
= centry_uint16(centry
);
2057 status
= centry
->status
;
2059 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2060 domain
->name
, nt_errstr(status
) ));
2062 centry_free(centry
);
2066 ZERO_STRUCTP(policy
);
2068 /* Return status value returned by seq number check */
2070 if (!NT_STATUS_IS_OK(domain
->last_status
))
2071 return domain
->last_status
;
2073 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2076 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2079 refresh_sequence_number(domain
, False
);
2080 wcache_save_lockout_policy(domain
, status
, policy
);
2085 /* get password policy */
2086 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
2087 TALLOC_CTX
*mem_ctx
,
2088 SAM_UNK_INFO_1
*policy
)
2090 struct winbind_cache
*cache
= get_cache(domain
);
2091 struct cache_entry
*centry
= NULL
;
2097 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2102 policy
->min_length_password
= centry_uint16(centry
);
2103 policy
->password_history
= centry_uint16(centry
);
2104 policy
->password_properties
= centry_uint32(centry
);
2105 policy
->expire
= centry_nttime(centry
);
2106 policy
->min_passwordage
= centry_nttime(centry
);
2108 status
= centry
->status
;
2110 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2111 domain
->name
, nt_errstr(status
) ));
2113 centry_free(centry
);
2117 ZERO_STRUCTP(policy
);
2119 /* Return status value returned by seq number check */
2121 if (!NT_STATUS_IS_OK(domain
->last_status
))
2122 return domain
->last_status
;
2124 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2127 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
2130 refresh_sequence_number(domain
, False
);
2131 wcache_save_password_policy(domain
, status
, policy
);
2137 /* Invalidate cached user and group lists coherently */
2139 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2142 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
2143 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
2144 tdb_delete(the_tdb
, kbuf
);
2149 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2151 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
2152 NET_USER_INFO_3
*info3
)
2154 struct winbind_cache
*cache
;
2159 cache
= get_cache(domain
);
2160 netsamlogon_clear_cached_user(cache
->tdb
, info3
);
2163 void wcache_invalidate_cache(void)
2165 struct winbindd_domain
*domain
;
2167 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
2168 struct winbind_cache
*cache
= get_cache(domain
);
2170 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2171 "entries for %s\n", domain
->name
));
2173 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
2177 static BOOL
init_wcache(void)
2179 if (wcache
== NULL
) {
2180 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
2181 ZERO_STRUCTP(wcache
);
2184 if (wcache
->tdb
!= NULL
)
2187 /* when working offline we must not clear the cache on restart */
2188 wcache
->tdb
= tdb_open_log(lock_path("winbindd_cache.tdb"),
2189 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
2190 lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
2191 O_RDWR
|O_CREAT
, 0600);
2193 if (wcache
->tdb
== NULL
) {
2194 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2201 /************************************************************************
2202 This is called by the parent to initialize the cache file.
2203 We don't need sophisticated locking here as we know we're the
2205 ************************************************************************/
2207 BOOL
initialize_winbindd_cache(void)
2209 BOOL cache_bad
= True
;
2212 if (!init_wcache()) {
2213 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
2217 /* Check version number. */
2218 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
2219 vers
== WINBINDD_CACHE_VERSION
) {
2224 DEBUG(0,("initialize_winbindd_cache: clearing cache "
2225 "and re-creating with version number %d\n",
2226 WINBINDD_CACHE_VERSION
));
2228 tdb_close(wcache
->tdb
);
2231 if (unlink(lock_path("winbindd_cache.tdb")) == -1) {
2232 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
2233 lock_path("winbindd_cache.tdb"),
2237 if (!init_wcache()) {
2238 DEBUG(0,("initialize_winbindd_cache: re-initialization "
2239 "init_wcache failed.\n"));
2243 /* Write the version. */
2244 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
2245 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
2246 tdb_errorstr(wcache
->tdb
) ));
2251 tdb_close(wcache
->tdb
);
2256 void cache_store_response(pid_t pid
, struct winbindd_response
*response
)
2263 DEBUG(10, ("Storing response for pid %d, len %d\n",
2264 pid
, response
->length
));
2266 fstr_sprintf(key_str
, "DR/%d", pid
);
2267 if (tdb_store(wcache
->tdb
, string_tdb_data(key_str
),
2268 make_tdb_data((uint8
*)response
, sizeof(*response
)),
2272 if (response
->length
== sizeof(*response
))
2275 /* There's extra data */
2277 DEBUG(10, ("Storing extra data: len=%d\n",
2278 (int)(response
->length
- sizeof(*response
))));
2280 fstr_sprintf(key_str
, "DE/%d", pid
);
2281 if (tdb_store(wcache
->tdb
, string_tdb_data(key_str
),
2282 make_tdb_data(response
->extra_data
.data
,
2283 response
->length
- sizeof(*response
)),
2287 /* We could not store the extra data, make sure the tdb does not
2288 * contain a main record with wrong dangling extra data */
2290 fstr_sprintf(key_str
, "DR/%d", pid
);
2291 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2296 BOOL
cache_retrieve_response(pid_t pid
, struct winbindd_response
* response
)
2304 DEBUG(10, ("Retrieving response for pid %d\n", pid
));
2306 fstr_sprintf(key_str
, "DR/%d", pid
);
2307 data
= tdb_fetch(wcache
->tdb
, string_tdb_data(key_str
));
2309 if (data
.dptr
== NULL
)
2312 if (data
.dsize
!= sizeof(*response
))
2315 memcpy(response
, data
.dptr
, data
.dsize
);
2316 SAFE_FREE(data
.dptr
);
2318 if (response
->length
== sizeof(*response
)) {
2319 response
->extra_data
.data
= NULL
;
2323 /* There's extra data */
2325 DEBUG(10, ("Retrieving extra data length=%d\n",
2326 (int)(response
->length
- sizeof(*response
))));
2328 fstr_sprintf(key_str
, "DE/%d", pid
);
2329 data
= tdb_fetch(wcache
->tdb
, string_tdb_data(key_str
));
2331 if (data
.dptr
== NULL
) {
2332 DEBUG(0, ("Did not find extra data\n"));
2336 if (data
.dsize
!= (response
->length
- sizeof(*response
))) {
2337 DEBUG(0, ("Invalid extra data length: %d\n", (int)data
.dsize
));
2338 SAFE_FREE(data
.dptr
);
2342 dump_data(11, (uint8
*)data
.dptr
, data
.dsize
);
2344 response
->extra_data
.data
= data
.dptr
;
2348 void cache_cleanup_response(pid_t pid
)
2355 fstr_sprintf(key_str
, "DR/%d", pid
);
2356 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2358 fstr_sprintf(key_str
, "DE/%d", pid
);
2359 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2365 BOOL
lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const DOM_SID
*sid
,
2366 const char **domain_name
, const char **name
,
2367 enum lsa_SidType
*type
)
2369 struct winbindd_domain
*domain
;
2370 struct winbind_cache
*cache
;
2371 struct cache_entry
*centry
= NULL
;
2374 domain
= find_lookup_domain_from_sid(sid
);
2375 if (domain
== NULL
) {
2379 cache
= get_cache(domain
);
2381 if (cache
->tdb
== NULL
) {
2385 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_string_static(sid
));
2386 if (centry
== NULL
) {
2390 if (NT_STATUS_IS_OK(centry
->status
)) {
2391 *type
= (enum lsa_SidType
)centry_uint32(centry
);
2392 *domain_name
= centry_string(centry
, mem_ctx
);
2393 *name
= centry_string(centry
, mem_ctx
);
2396 status
= centry
->status
;
2397 centry_free(centry
);
2398 return NT_STATUS_IS_OK(status
);
2401 BOOL
lookup_cached_name(TALLOC_CTX
*mem_ctx
,
2402 const char *domain_name
,
2405 enum lsa_SidType
*type
)
2407 struct winbindd_domain
*domain
;
2408 struct winbind_cache
*cache
;
2409 struct cache_entry
*centry
= NULL
;
2413 domain
= find_lookup_domain_from_name(domain_name
);
2414 if (domain
== NULL
) {
2418 cache
= get_cache(domain
);
2420 if (cache
->tdb
== NULL
) {
2424 fstrcpy(uname
, name
);
2427 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
2428 if (centry
== NULL
) {
2432 if (NT_STATUS_IS_OK(centry
->status
)) {
2433 *type
= (enum lsa_SidType
)centry_uint32(centry
);
2434 centry_sid(centry
, mem_ctx
, sid
);
2437 status
= centry
->status
;
2438 centry_free(centry
);
2440 return NT_STATUS_IS_OK(status
);
2443 void cache_name2sid(struct winbindd_domain
*domain
,
2444 const char *domain_name
, const char *name
,
2445 enum lsa_SidType type
, const DOM_SID
*sid
)
2447 refresh_sequence_number(domain
, False
);
2448 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
2453 * The original idea that this cache only contains centries has
2454 * been blurred - now other stuff gets put in here. Ensure we
2455 * ignore these things on cleanup.
2458 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
2459 TDB_DATA dbuf
, void *state
)
2461 struct cache_entry
*centry
;
2463 if (is_non_centry_key(kbuf
)) {
2467 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
2472 if (!NT_STATUS_IS_OK(centry
->status
)) {
2473 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
2474 tdb_delete(the_tdb
, kbuf
);
2477 centry_free(centry
);
2481 /* flush the cache */
2482 void wcache_flush_cache(void)
2487 tdb_close(wcache
->tdb
);
2493 /* when working offline we must not clear the cache on restart */
2494 wcache
->tdb
= tdb_open_log(lock_path("winbindd_cache.tdb"),
2495 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
2496 lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
2497 O_RDWR
|O_CREAT
, 0600);
2500 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2504 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
2506 DEBUG(10,("wcache_flush_cache success\n"));
2509 /* Count cached creds */
2511 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2514 int *cred_count
= (int*)state
;
2516 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
2522 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
2524 struct winbind_cache
*cache
= get_cache(domain
);
2529 return NT_STATUS_INTERNAL_DB_ERROR
;
2532 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
2534 return NT_STATUS_OK
;
2538 struct cred_list
*prev
, *next
;
2543 static struct cred_list
*wcache_cred_list
;
2545 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2548 struct cred_list
*cred
;
2550 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
2552 cred
= SMB_MALLOC_P(struct cred_list
);
2554 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2560 /* save a copy of the key */
2562 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
2563 DLIST_ADD(wcache_cred_list
, cred
);
2569 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const DOM_SID
*sid
)
2571 struct winbind_cache
*cache
= get_cache(domain
);
2574 struct cred_list
*cred
, *oldest
= NULL
;
2577 return NT_STATUS_INTERNAL_DB_ERROR
;
2580 /* we possibly already have an entry */
2581 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
2585 DEBUG(11,("we already have an entry, deleting that\n"));
2587 fstr_sprintf(key_str
, "CRED/%s", sid_string_static(sid
));
2589 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
2591 return NT_STATUS_OK
;
2594 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
2596 return NT_STATUS_OK
;
2597 } else if ((ret
== -1) || (wcache_cred_list
== NULL
)) {
2598 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2601 ZERO_STRUCTP(oldest
);
2603 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
2608 data
= tdb_fetch(cache
->tdb
, string_tdb_data(cred
->name
));
2610 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
2612 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2616 t
= IVAL(data
.dptr
, 0);
2617 SAFE_FREE(data
.dptr
);
2620 oldest
= SMB_MALLOC_P(struct cred_list
);
2621 if (oldest
== NULL
) {
2622 status
= NT_STATUS_NO_MEMORY
;
2626 fstrcpy(oldest
->name
, cred
->name
);
2627 oldest
->created
= t
;
2631 if (t
< oldest
->created
) {
2632 fstrcpy(oldest
->name
, cred
->name
);
2633 oldest
->created
= t
;
2637 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
2638 status
= NT_STATUS_OK
;
2640 status
= NT_STATUS_UNSUCCESSFUL
;
2643 SAFE_FREE(wcache_cred_list
);
2649 /* Change the global online/offline state. */
2650 BOOL
set_global_winbindd_state_offline(void)
2654 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
2656 /* Only go offline if someone has created
2657 the key "WINBINDD_OFFLINE" in the cache tdb. */
2659 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
2660 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
2664 if (!lp_winbind_offline_logon()) {
2665 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
2669 if (global_winbindd_offline_state
) {
2670 /* Already offline. */
2674 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
2676 if (!data
.dptr
|| data
.dsize
!= 4) {
2677 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
2678 SAFE_FREE(data
.dptr
);
2681 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
2682 global_winbindd_offline_state
= True
;
2683 SAFE_FREE(data
.dptr
);
2688 void set_global_winbindd_state_online(void)
2690 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
2692 if (!lp_winbind_offline_logon()) {
2693 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
2697 if (!global_winbindd_offline_state
) {
2698 /* Already online. */
2701 global_winbindd_offline_state
= False
;
2707 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
2708 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
2711 BOOL
get_global_winbindd_state_offline(void)
2713 return global_winbindd_offline_state
;
2716 /***********************************************************************
2717 Validate functions for all possible cache tdb keys.
2718 ***********************************************************************/
2720 static BOOL bad_cache_entry
;
2722 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
)
2724 struct cache_entry
*centry
;
2726 centry
= SMB_XMALLOC_P(struct cache_entry
);
2727 centry
->data
= (unsigned char *)memdup(data
.dptr
, data
.dsize
);
2728 if (!centry
->data
) {
2732 centry
->len
= data
.dsize
;
2735 if (centry
->len
< 8) {
2736 /* huh? corrupt cache? */
2737 DEBUG(0,("validate_create_centry: Corrupt cache for key %s (len < 8) ?\n", kstr
));
2738 centry_free(centry
);
2739 bad_cache_entry
= True
;
2743 centry
->status
= NT_STATUS(centry_uint32(centry
));
2744 centry
->sequence_number
= centry_uint32(centry
);
2748 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
)
2750 if (dbuf
.dsize
!= 8) {
2751 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
2752 keystr
, (unsigned int)dbuf
.dsize
));
2753 bad_cache_entry
= True
;
2759 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
)
2761 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
);
2766 (void)centry_uint32(centry
);
2767 if (NT_STATUS_IS_OK(centry
->status
)) {
2769 (void)centry_sid(centry
, mem_ctx
, &sid
);
2772 centry_free(centry
);
2774 if (bad_cache_entry
) {
2777 DEBUG(10,("validate_ns: %s ok\n", keystr
));
2781 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
)
2783 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
);
2788 if (NT_STATUS_IS_OK(centry
->status
)) {
2789 (void)centry_uint32(centry
);
2790 (void)centry_string(centry
, mem_ctx
);
2791 (void)centry_string(centry
, mem_ctx
);
2794 centry_free(centry
);
2796 if (bad_cache_entry
) {
2799 DEBUG(10,("validate_sn: %s ok\n", keystr
));
2803 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
)
2805 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
);
2812 (void)centry_string(centry
, mem_ctx
);
2813 (void)centry_string(centry
, mem_ctx
);
2814 (void)centry_string(centry
, mem_ctx
);
2815 (void)centry_string(centry
, mem_ctx
);
2816 (void)centry_uint32(centry
);
2817 (void)centry_sid(centry
, mem_ctx
, &sid
);
2818 (void)centry_sid(centry
, mem_ctx
, &sid
);
2820 centry_free(centry
);
2822 if (bad_cache_entry
) {
2825 DEBUG(10,("validate_u: %s ok\n", keystr
));
2829 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
)
2831 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
);
2837 (void)centry_nttime(centry
);
2838 (void)centry_nttime(centry
);
2839 (void)centry_uint16(centry
);
2841 centry_free(centry
);
2843 if (bad_cache_entry
) {
2846 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
2850 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
)
2852 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
);
2858 (void)centry_uint16(centry
);
2859 (void)centry_uint16(centry
);
2860 (void)centry_uint32(centry
);
2861 (void)centry_nttime(centry
);
2862 (void)centry_nttime(centry
);
2864 centry_free(centry
);
2866 if (bad_cache_entry
) {
2869 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
2873 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
)
2875 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
);
2881 (void)centry_time(centry
);
2882 (void)centry_hash16(centry
, mem_ctx
);
2884 /* We only have 17 bytes more data in the salted cred case. */
2885 if (centry
->len
- centry
->ofs
== 17) {
2886 (void)centry_hash16(centry
, mem_ctx
);
2889 centry_free(centry
);
2891 if (bad_cache_entry
) {
2894 DEBUG(10,("validate_cred: %s ok\n", keystr
));
2898 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
)
2900 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
);
2901 int32 num_entries
, i
;
2907 num_entries
= (int32
)centry_uint32(centry
);
2909 for (i
=0; i
< num_entries
; i
++) {
2911 (void)centry_string(centry
, mem_ctx
);
2912 (void)centry_string(centry
, mem_ctx
);
2913 (void)centry_string(centry
, mem_ctx
);
2914 (void)centry_string(centry
, mem_ctx
);
2915 (void)centry_sid(centry
, mem_ctx
, &sid
);
2916 (void)centry_sid(centry
, mem_ctx
, &sid
);
2919 centry_free(centry
);
2921 if (bad_cache_entry
) {
2924 DEBUG(10,("validate_ul: %s ok\n", keystr
));
2928 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
)
2930 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
);
2931 int32 num_entries
, i
;
2937 num_entries
= centry_uint32(centry
);
2939 for (i
=0; i
< num_entries
; i
++) {
2940 (void)centry_string(centry
, mem_ctx
);
2941 (void)centry_string(centry
, mem_ctx
);
2942 (void)centry_uint32(centry
);
2945 centry_free(centry
);
2947 if (bad_cache_entry
) {
2950 DEBUG(10,("validate_gl: %s ok\n", keystr
));
2954 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
)
2956 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
);
2957 int32 num_groups
, i
;
2963 num_groups
= centry_uint32(centry
);
2965 for (i
=0; i
< num_groups
; i
++) {
2967 centry_sid(centry
, mem_ctx
, &sid
);
2970 centry_free(centry
);
2972 if (bad_cache_entry
) {
2975 DEBUG(10,("validate_ug: %s ok\n", keystr
));
2979 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
)
2981 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
);
2982 int32 num_aliases
, i
;
2988 num_aliases
= centry_uint32(centry
);
2990 for (i
=0; i
< num_aliases
; i
++) {
2991 (void)centry_uint32(centry
);
2994 centry_free(centry
);
2996 if (bad_cache_entry
) {
2999 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3003 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
)
3005 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
);
3012 num_names
= centry_uint32(centry
);
3014 for (i
=0; i
< num_names
; i
++) {
3016 centry_sid(centry
, mem_ctx
, &sid
);
3017 (void)centry_string(centry
, mem_ctx
);
3018 (void)centry_uint32(centry
);
3021 centry_free(centry
);
3023 if (bad_cache_entry
) {
3026 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3030 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
)
3032 /* Can't say anything about this other than must be nonzero. */
3033 if (dbuf
.dsize
== 0) {
3034 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3036 bad_cache_entry
= True
;
3040 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3044 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
)
3046 /* Can't say anything about this other than must be nonzero. */
3047 if (dbuf
.dsize
== 0) {
3048 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3050 bad_cache_entry
= True
;
3054 DEBUG(10,("validate_de: %s ok\n", keystr
));
3058 static int validate_trustdoms(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
)
3060 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
);
3061 int32 num_domains
, i
;
3067 num_domains
= centry_uint32(centry
);
3069 for (i
=0; i
< num_domains
; i
++) {
3071 (void)centry_string(centry
, mem_ctx
);
3072 (void)centry_string(centry
, mem_ctx
);
3073 (void)centry_sid(centry
, mem_ctx
, &sid
);
3076 centry_free(centry
);
3078 if (bad_cache_entry
) {
3081 DEBUG(10,("validate_trustdoms: %s ok\n", keystr
));
3085 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
)
3087 if (dbuf
.dsize
!= 4) {
3088 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3089 keystr
, (unsigned int)dbuf
.dsize
));
3090 bad_cache_entry
= True
;
3093 DEBUG(10,("validate_offline: %s ok\n", keystr
));
3097 /***********************************************************************
3098 A list of all possible cache tdb keys with associated validation
3100 ***********************************************************************/
3102 struct key_val_struct
{
3103 const char *keyname
;
3104 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
);
3106 {"SEQNUM/", validate_seqnum
},
3107 {"NS/", validate_ns
},
3108 {"SN/", validate_sn
},
3110 {"LOC_POL/", validate_loc_pol
},
3111 {"PWD_POL/", validate_pwd_pol
},
3112 {"CRED/", validate_cred
},
3113 {"UL/", validate_ul
},
3114 {"GL/", validate_gl
},
3115 {"UG/", validate_ug
},
3116 {"UA", validate_ua
},
3117 {"GM/", validate_gm
},
3118 {"DR/", validate_dr
},
3119 {"DE/", validate_de
},
3120 {"TRUSTDOMS/", validate_trustdoms
},
3121 {"WINBINDD_OFFLINE", validate_offline
},
3125 /***********************************************************************
3126 Function to look at every entry in the tdb and validate it as far as
3128 ***********************************************************************/
3130 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
3134 /* Paranoia check. */
3135 if (kbuf
.dsize
> 1024) {
3136 DEBUG(0,("cache_traverse_validate_fn: key length too large (%u) > 1024\n\n",
3137 (unsigned int)kbuf
.dsize
));
3141 for (i
= 0; key_val
[i
].keyname
; i
++) {
3142 size_t namelen
= strlen(key_val
[i
].keyname
);
3143 if (kbuf
.dsize
>= namelen
&& (
3144 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
3145 TALLOC_CTX
*mem_ctx
;
3149 keystr
= SMB_MALLOC(kbuf
.dsize
+1);
3153 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
3154 keystr
[kbuf
.dsize
] = '\0';
3156 mem_ctx
= talloc_init("validate_ctx");
3162 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
);
3165 talloc_destroy(mem_ctx
);
3170 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
3171 dump_data(0, (uint8
*)kbuf
.dptr
, kbuf
.dsize
);
3172 DEBUG(0,("data :\n"));
3173 dump_data(0, (uint8
*)dbuf
.dptr
, dbuf
.dsize
);
3174 return 1; /* terminate. */
3177 static void validate_panic(const char *const why
)
3179 DEBUG(0,("validating cache: would panic %s\n", why
));
3180 bad_cache_entry
= True
;
3183 /* Handle any signals generated when validating a possibly
3186 static jmp_buf jmpbuf
;
3189 static void sig_segv(int sig
)
3191 longjmp(jmpbuf
, SIGSEGV
);
3196 static void sig_bus(int sig
)
3198 longjmp(jmpbuf
, SIGBUS
);
3203 static void sig_abrt(int sig
)
3205 longjmp(jmpbuf
, SIGABRT
);
3209 /***********************************************************************
3210 Try and validate every entry in the winbindd cache. If we fail here,
3211 delete the cache tdb and return non-zero - the caller (main winbindd
3212 function) will restart us as we don't know if we crashed or not.
3213 ***********************************************************************/
3215 int winbindd_validate_cache(void)
3219 int num_entries
= 0;
3220 TDB_CONTEXT
*tdb
= NULL
;
3221 const char *cache_path
= lock_path("winbindd_cache.tdb");
3224 void (*old_segv_handler
)(int) = CatchSignal(SIGSEGV
,SIGNAL_CAST sig_segv
);
3227 void (*old_bus_handler
)(int) = CatchSignal(SIGBUS
,SIGNAL_CAST sig_bus
);
3230 void (*old_abrt_handler
)(int) = CatchSignal(SIGABRT
,SIGNAL_CAST sig_abrt
);
3233 switch((ret
= setjmp(jmpbuf
))) {
3244 /* Doh ! Volker is very smart :-). Use TDB_NOMMAP to prevent
3245 * any wild pointer references when reading a corrupt tdb file. */
3247 tdb
= tdb_open_log(cache_path
,
3248 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3249 lp_winbind_offline_logon() ? TDB_NOMMAP
: (TDB_NOMMAP
| TDB_CLEAR_IF_FIRST
),
3250 O_RDWR
|O_CREAT
, 0600);
3257 /* Check the cache freelist is good. */
3258 if (tdb_validate_freelist(tdb
, &num_entries
) == -1) {
3259 DEBUG(0,("winbindd_validate_cache: bad freelist in cache %s\n",
3264 DEBUG(10,("winbindd_validate_cache: cache %s freelist has %d entries\n",
3265 cache_path
, num_entries
));
3267 smb_panic_fn
= validate_panic
;
3269 /* Now traverse the cache to validate it. */
3270 num_entries
= tdb_traverse(tdb
, cache_traverse_validate_fn
, NULL
);
3271 if (num_entries
== -1 || bad_cache_entry
) {
3272 DEBUG(0,("winbindd_validate_cache: cache %s traverse failed\n",
3277 DEBUG(10,("winbindd_validate_cache: cache %s is good "
3278 "with %d entries\n", cache_path
, num_entries
));
3279 ret
= 0; /* Cache is good. */
3283 bad_cache_entry
= False
;
3284 smb_panic_fn
= smb_panic
;
3286 /* Ensure if we segv on exit we use the original
3287 handlers to avoid a loop. */
3290 CatchSignal(SIGSEGV
,SIGNAL_CAST old_segv_handler
);
3293 CatchSignal(SIGBUS
,SIGNAL_CAST old_bus_handler
);
3296 CatchSignal(SIGABRT
,SIGNAL_CAST old_abrt_handler
);
3302 } else if (fd
!= -1) {
3314 /* the cache backend methods are exposed via this structure */
3315 struct winbindd_methods cache_methods
= {