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 2 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, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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
;
37 extern BOOL opt_nocache
;
39 extern struct winbindd_methods ads_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 struct winbindd_domain
*our_domain
= domain
;
140 /* We have to know what type of domain we are dealing with first. */
142 if ( !domain
->initialized
) {
143 init_dc_connection( domain
);
147 OK. listen up becasue I'm only going to say this once.
148 We have the following scenarios to consider
149 (a) trusted AD domains on a Samba DC,
150 (b) trusted AD domains and we are joined to a non-kerberos domain
151 (c) trusted AD domains and we are joined to a kerberos (AD) domain
153 For (a) we can always contact the trusted domain using krb5
154 since we have the domain trust account password
156 For (b) we can only use RPC since we have no way of
157 getting a krb5 ticket in our own domain
159 For (c) we can always use krb5 since we have a kerberos trust
164 if (!domain
->backend
) {
166 /* find our domain first so we can figure out if we
167 are joined to a kerberized domain */
169 if ( !domain
->primary
)
170 our_domain
= find_our_domain();
172 if ( (our_domain
->active_directory
|| IS_DC
) && domain
->active_directory
) {
173 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain
->name
));
174 domain
->backend
= &ads_methods
;
176 #endif /* HAVE_ADS */
177 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain
->name
));
178 domain
->backend
= &reconnect_methods
;
181 #endif /* HAVE_ADS */
187 ret
= SMB_XMALLOC_P(struct winbind_cache
);
191 wcache_flush_cache();
197 free a centry structure
199 static void centry_free(struct cache_entry
*centry
)
203 SAFE_FREE(centry
->data
);
207 static BOOL
centry_check_bytes(struct cache_entry
*centry
, size_t nbytes
)
209 if (centry
->len
- centry
->ofs
< nbytes
) {
210 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
211 (unsigned int)nbytes
,
212 centry
->len
- centry
->ofs
));
219 pull a uint32 from a cache entry
221 static uint32
centry_uint32(struct cache_entry
*centry
)
225 if (!centry_check_bytes(centry
, 4)) {
226 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");
242 ret
= CVAL(centry
->data
, centry
->ofs
);
248 pull a uint8 from a cache entry
250 static uint8
centry_uint8(struct cache_entry
*centry
)
253 if (!centry_check_bytes(centry
, 1)) {
254 smb_panic_fn("centry_uint8");
256 ret
= CVAL(centry
->data
, centry
->ofs
);
262 pull a NTTIME from a cache entry
264 static NTTIME
centry_nttime(struct cache_entry
*centry
)
267 if (!centry_check_bytes(centry
, 8)) {
268 smb_panic_fn("centry_nttime");
270 ret
= IVAL(centry
->data
, centry
->ofs
);
272 ret
+= (uint64_t)IVAL(centry
->data
, centry
->ofs
) << 32;
278 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
280 static time_t centry_time(struct cache_entry
*centry
)
282 return (time_t)centry_nttime(centry
);
285 /* pull a string from a cache entry, using the supplied
288 static char *centry_string(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
293 len
= centry_uint8(centry
);
296 /* a deliberate NULL string */
300 if (!centry_check_bytes(centry
, (size_t)len
)) {
301 smb_panic_fn("centry_string");
304 ret
= TALLOC_ARRAY(mem_ctx
, char, len
+1);
306 smb_panic_fn("centry_string out of memory\n");
308 memcpy(ret
,centry
->data
+ centry
->ofs
, len
);
314 /* pull a hash16 from a cache entry, using the supplied
317 static char *centry_hash16(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
322 len
= centry_uint8(centry
);
325 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
330 if (!centry_check_bytes(centry
, 16)) {
334 ret
= TALLOC_ARRAY(mem_ctx
, char, 16);
336 smb_panic_fn("centry_hash out of memory\n");
338 memcpy(ret
,centry
->data
+ centry
->ofs
, 16);
343 /* pull a sid from a cache entry, using the supplied
346 static BOOL
centry_sid(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
, DOM_SID
*sid
)
349 sid_string
= centry_string(centry
, mem_ctx
);
350 if ((sid_string
== NULL
) || (!string_to_sid(sid
, sid_string
))) {
356 /* the server is considered down if it can't give us a sequence number */
357 static BOOL
wcache_server_down(struct winbindd_domain
*domain
)
364 ret
= (domain
->sequence_number
== DOM_SEQUENCE_NONE
);
367 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
372 static NTSTATUS
fetch_cache_seqnum( struct winbindd_domain
*domain
, time_t now
)
379 DEBUG(10,("fetch_cache_seqnum: tdb == NULL\n"));
380 return NT_STATUS_UNSUCCESSFUL
;
383 fstr_sprintf( key
, "SEQNUM/%s", domain
->name
);
385 data
= tdb_fetch_bystring( wcache
->tdb
, key
);
386 if ( !data
.dptr
|| data
.dsize
!=8 ) {
387 DEBUG(10,("fetch_cache_seqnum: invalid data size key [%s]\n", key
));
388 return NT_STATUS_UNSUCCESSFUL
;
391 domain
->sequence_number
= IVAL(data
.dptr
, 0);
392 domain
->last_seq_check
= IVAL(data
.dptr
, 4);
394 SAFE_FREE(data
.dptr
);
396 /* have we expired? */
398 time_diff
= now
- domain
->last_seq_check
;
399 if ( time_diff
> lp_winbind_cache_time() ) {
400 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
401 domain
->name
, domain
->sequence_number
,
402 (uint32
)domain
->last_seq_check
));
403 return NT_STATUS_UNSUCCESSFUL
;
406 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
407 domain
->name
, domain
->sequence_number
,
408 (uint32
)domain
->last_seq_check
));
413 static NTSTATUS
store_cache_seqnum( struct winbindd_domain
*domain
)
420 DEBUG(10,("store_cache_seqnum: tdb == NULL\n"));
421 return NT_STATUS_UNSUCCESSFUL
;
424 fstr_sprintf( key_str
, "SEQNUM/%s", domain
->name
);
426 SIVAL(buf
, 0, domain
->sequence_number
);
427 SIVAL(buf
, 4, domain
->last_seq_check
);
431 if ( tdb_store_bystring( wcache
->tdb
, key_str
, data
, TDB_REPLACE
) == -1 ) {
432 DEBUG(10,("store_cache_seqnum: tdb_store fail key [%s]\n", key_str
));
433 return NT_STATUS_UNSUCCESSFUL
;
436 DEBUG(10,("store_cache_seqnum: success [%s][%u @ %u]\n",
437 domain
->name
, domain
->sequence_number
,
438 (uint32
)domain
->last_seq_check
));
444 refresh the domain sequence number. If force is True
445 then always refresh it, no matter how recently we fetched it
448 static void refresh_sequence_number(struct winbindd_domain
*domain
, BOOL force
)
452 time_t t
= time(NULL
);
453 unsigned cache_time
= lp_winbind_cache_time();
455 if ( IS_DOMAIN_OFFLINE(domain
) ) {
461 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
462 /* trying to reconnect is expensive, don't do it too often */
463 if (domain
->sequence_number
== DOM_SEQUENCE_NONE
) {
468 time_diff
= t
- domain
->last_seq_check
;
470 /* see if we have to refetch the domain sequence number */
471 if (!force
&& (time_diff
< cache_time
)) {
472 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain
->name
));
476 /* try to get the sequence number from the tdb cache first */
477 /* this will update the timestamp as well */
479 status
= fetch_cache_seqnum( domain
, t
);
480 if ( NT_STATUS_IS_OK(status
) )
483 /* important! make sure that we know if this is a native
484 mode domain or not. And that we can contact it. */
486 if ( winbindd_can_contact_domain( domain
) ) {
487 status
= domain
->backend
->sequence_number(domain
,
488 &domain
->sequence_number
);
490 /* just use the current time */
491 status
= NT_STATUS_OK
;
492 domain
->sequence_number
= time(NULL
);
496 /* the above call could have set our domain->backend to NULL when
497 * coming from offline to online mode, make sure to reinitialize the
498 * backend - Guenther */
501 if (!NT_STATUS_IS_OK(status
)) {
502 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status
)));
503 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
506 domain
->last_status
= status
;
507 domain
->last_seq_check
= time(NULL
);
509 /* save the new sequence number ni the cache */
510 store_cache_seqnum( domain
);
513 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
514 domain
->name
, domain
->sequence_number
));
520 decide if a cache entry has expired
522 static BOOL
centry_expired(struct winbindd_domain
*domain
, const char *keystr
, struct cache_entry
*centry
)
524 /* If we've been told to be offline - stay in that state... */
525 if (lp_winbind_offline_logon() && global_winbindd_offline_state
) {
526 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
527 keystr
, domain
->name
));
531 /* when the domain is offline return the cached entry.
532 * This deals with transient offline states... */
534 if (!domain
->online
) {
535 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
536 keystr
, domain
->name
));
540 /* if the server is OK and our cache entry came from when it was down then
541 the entry is invalid */
542 if ((domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
543 (centry
->sequence_number
== DOM_SEQUENCE_NONE
)) {
544 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
545 keystr
, domain
->name
));
549 /* if the server is down or the cache entry is not older than the
550 current sequence number then it is OK */
551 if (wcache_server_down(domain
) ||
552 centry
->sequence_number
== domain
->sequence_number
) {
553 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
554 keystr
, domain
->name
));
558 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
559 keystr
, domain
->name
));
565 static struct cache_entry
*wcache_fetch_raw(char *kstr
)
568 struct cache_entry
*centry
;
571 key
= string_tdb_data(kstr
);
572 data
= tdb_fetch(wcache
->tdb
, key
);
578 centry
= SMB_XMALLOC_P(struct cache_entry
);
579 centry
->data
= (unsigned char *)data
.dptr
;
580 centry
->len
= data
.dsize
;
583 if (centry
->len
< 8) {
584 /* huh? corrupt cache? */
585 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr
));
590 centry
->status
= NT_STATUS(centry_uint32(centry
));
591 centry
->sequence_number
= centry_uint32(centry
);
597 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
598 number and return status
600 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
601 struct winbindd_domain
*domain
,
602 const char *format
, ...) PRINTF_ATTRIBUTE(3,4);
603 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
604 struct winbindd_domain
*domain
,
605 const char *format
, ...)
609 struct cache_entry
*centry
;
615 refresh_sequence_number(domain
, False
);
617 va_start(ap
, format
);
618 smb_xvasprintf(&kstr
, format
, ap
);
621 centry
= wcache_fetch_raw(kstr
);
622 if (centry
== NULL
) {
627 if (centry_expired(domain
, kstr
, centry
)) {
629 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
630 kstr
, domain
->name
));
637 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
638 kstr
, domain
->name
));
644 static void wcache_delete(const char *format
, ...) PRINTF_ATTRIBUTE(1,2);
645 static void wcache_delete(const char *format
, ...)
651 va_start(ap
, format
);
652 smb_xvasprintf(&kstr
, format
, ap
);
655 key
= string_tdb_data(kstr
);
657 tdb_delete(wcache
->tdb
, key
);
662 make sure we have at least len bytes available in a centry
664 static void centry_expand(struct cache_entry
*centry
, uint32 len
)
666 if (centry
->len
- centry
->ofs
>= len
)
669 centry
->data
= SMB_REALLOC_ARRAY(centry
->data
, unsigned char,
672 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry
->len
));
673 smb_panic_fn("out of memory in centry_expand");
678 push a uint32 into a centry
680 static void centry_put_uint32(struct cache_entry
*centry
, uint32 v
)
682 centry_expand(centry
, 4);
683 SIVAL(centry
->data
, centry
->ofs
, v
);
688 push a uint16 into a centry
690 static void centry_put_uint16(struct cache_entry
*centry
, uint16 v
)
692 centry_expand(centry
, 2);
693 SIVAL(centry
->data
, centry
->ofs
, v
);
698 push a uint8 into a centry
700 static void centry_put_uint8(struct cache_entry
*centry
, uint8 v
)
702 centry_expand(centry
, 1);
703 SCVAL(centry
->data
, centry
->ofs
, v
);
708 push a string into a centry
710 static void centry_put_string(struct cache_entry
*centry
, const char *s
)
715 /* null strings are marked as len 0xFFFF */
716 centry_put_uint8(centry
, 0xFF);
721 /* can't handle more than 254 char strings. Truncating is probably best */
723 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len
));
726 centry_put_uint8(centry
, len
);
727 centry_expand(centry
, len
);
728 memcpy(centry
->data
+ centry
->ofs
, s
, len
);
733 push a 16 byte hash into a centry - treat as 16 byte string.
735 static void centry_put_hash16(struct cache_entry
*centry
, const uint8 val
[16])
737 centry_put_uint8(centry
, 16);
738 centry_expand(centry
, 16);
739 memcpy(centry
->data
+ centry
->ofs
, val
, 16);
743 static void centry_put_sid(struct cache_entry
*centry
, const DOM_SID
*sid
)
746 centry_put_string(centry
, sid_to_string(sid_string
, sid
));
750 push a NTTIME into a centry
752 static void centry_put_nttime(struct cache_entry
*centry
, NTTIME nt
)
754 centry_expand(centry
, 8);
755 SIVAL(centry
->data
, centry
->ofs
, nt
& 0xFFFFFFFF);
757 SIVAL(centry
->data
, centry
->ofs
, nt
>> 32);
762 push a time_t into a centry - use a 64 bit size.
763 NTTIME here is being used as a convenient 64-bit size.
765 static void centry_put_time(struct cache_entry
*centry
, time_t t
)
767 NTTIME nt
= (NTTIME
)t
;
768 centry_put_nttime(centry
, nt
);
772 start a centry for output. When finished, call centry_end()
774 struct cache_entry
*centry_start(struct winbindd_domain
*domain
, NTSTATUS status
)
776 struct cache_entry
*centry
;
781 centry
= SMB_XMALLOC_P(struct cache_entry
);
783 centry
->len
= 8192; /* reasonable default */
784 centry
->data
= SMB_XMALLOC_ARRAY(uint8
, centry
->len
);
786 centry
->sequence_number
= domain
->sequence_number
;
787 centry_put_uint32(centry
, NT_STATUS_V(status
));
788 centry_put_uint32(centry
, centry
->sequence_number
);
793 finish a centry and write it to the tdb
795 static void centry_end(struct cache_entry
*centry
, const char *format
, ...) PRINTF_ATTRIBUTE(2,3);
796 static void centry_end(struct cache_entry
*centry
, const char *format
, ...)
802 va_start(ap
, format
);
803 smb_xvasprintf(&kstr
, format
, ap
);
806 key
= string_tdb_data(kstr
);
807 data
.dptr
= centry
->data
;
808 data
.dsize
= centry
->ofs
;
810 tdb_store(wcache
->tdb
, key
, data
, TDB_REPLACE
);
814 static void wcache_save_name_to_sid(struct winbindd_domain
*domain
,
815 NTSTATUS status
, const char *domain_name
,
816 const char *name
, const DOM_SID
*sid
,
817 enum lsa_SidType type
)
819 struct cache_entry
*centry
;
822 centry
= centry_start(domain
, status
);
825 centry_put_uint32(centry
, type
);
826 centry_put_sid(centry
, sid
);
827 fstrcpy(uname
, name
);
829 centry_end(centry
, "NS/%s/%s", domain_name
, uname
);
830 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name
, uname
,
831 sid_string_static(sid
), nt_errstr(status
)));
835 static void wcache_save_sid_to_name(struct winbindd_domain
*domain
, NTSTATUS status
,
836 const DOM_SID
*sid
, const char *domain_name
, const char *name
, enum lsa_SidType type
)
838 struct cache_entry
*centry
;
841 if (is_null_sid(sid
)) {
845 centry
= centry_start(domain
, status
);
848 if (NT_STATUS_IS_OK(status
)) {
849 centry_put_uint32(centry
, type
);
850 centry_put_string(centry
, domain_name
);
851 centry_put_string(centry
, name
);
853 centry_end(centry
, "SN/%s", sid_to_string(sid_string
, sid
));
854 DEBUG(10,("wcache_save_sid_to_name: %s -> %s (%s)\n", sid_string
,
855 name
, nt_errstr(status
)));
860 static void wcache_save_user(struct winbindd_domain
*domain
, NTSTATUS status
, WINBIND_USERINFO
*info
)
862 struct cache_entry
*centry
;
865 if (is_null_sid(&info
->user_sid
)) {
869 centry
= centry_start(domain
, status
);
872 centry_put_string(centry
, info
->acct_name
);
873 centry_put_string(centry
, info
->full_name
);
874 centry_put_string(centry
, info
->homedir
);
875 centry_put_string(centry
, info
->shell
);
876 centry_put_uint32(centry
, info
->primary_gid
);
877 centry_put_sid(centry
, &info
->user_sid
);
878 centry_put_sid(centry
, &info
->group_sid
);
879 centry_end(centry
, "U/%s", sid_to_string(sid_string
, &info
->user_sid
));
880 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string
, info
->acct_name
));
884 static void wcache_save_lockout_policy(struct winbindd_domain
*domain
, NTSTATUS status
, SAM_UNK_INFO_12
*lockout_policy
)
886 struct cache_entry
*centry
;
888 centry
= centry_start(domain
, status
);
892 centry_put_nttime(centry
, lockout_policy
->duration
);
893 centry_put_nttime(centry
, lockout_policy
->reset_count
);
894 centry_put_uint16(centry
, lockout_policy
->bad_attempt_lockout
);
896 centry_end(centry
, "LOC_POL/%s", domain
->name
);
898 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain
->name
));
903 static void wcache_save_password_policy(struct winbindd_domain
*domain
, NTSTATUS status
, SAM_UNK_INFO_1
*policy
)
905 struct cache_entry
*centry
;
907 centry
= centry_start(domain
, status
);
911 centry_put_uint16(centry
, policy
->min_length_password
);
912 centry_put_uint16(centry
, policy
->password_history
);
913 centry_put_uint32(centry
, policy
->password_properties
);
914 centry_put_nttime(centry
, policy
->expire
);
915 centry_put_nttime(centry
, policy
->min_passwordage
);
917 centry_end(centry
, "PWD_POL/%s", domain
->name
);
919 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
924 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const DOM_SID
*sid
)
926 struct winbind_cache
*cache
= get_cache(domain
);
932 return NT_STATUS_INTERNAL_DB_ERROR
;
935 if (is_null_sid(sid
)) {
936 return NT_STATUS_INVALID_SID
;
939 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
940 return NT_STATUS_INVALID_SID
;
943 fstr_sprintf(key_str
, "CRED/%s", sid_string_static(sid
));
945 data
= tdb_fetch(cache
->tdb
, string_tdb_data(key_str
));
947 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
950 SAFE_FREE(data
.dptr
);
954 /* Lookup creds for a SID - copes with old (unsalted) creds as well
955 as new salted ones. */
957 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
960 const uint8
**cached_nt_pass
,
961 const uint8
**cached_salt
)
963 struct winbind_cache
*cache
= get_cache(domain
);
964 struct cache_entry
*centry
= NULL
;
970 return NT_STATUS_INTERNAL_DB_ERROR
;
973 if (is_null_sid(sid
)) {
974 return NT_STATUS_INVALID_SID
;
977 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
978 return NT_STATUS_INVALID_SID
;
981 /* Try and get a salted cred first. If we can't
982 fall back to an unsalted cred. */
984 centry
= wcache_fetch(cache
, domain
, "CRED/%s", sid_string_static(sid
));
986 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
987 sid_string_static(sid
)));
988 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
991 t
= centry_time(centry
);
993 /* In the salted case this isn't actually the nt_hash itself,
994 but the MD5 of the salt + nt_hash. Let the caller
995 sort this out. It can tell as we only return the cached_salt
996 if we are returning a salted cred. */
998 *cached_nt_pass
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
999 if (*cached_nt_pass
== NULL
) {
1000 const char *sidstr
= sid_string_static(sid
);
1002 /* Bad (old) cred cache. Delete and pretend we
1004 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1006 wcache_delete("CRED/%s", sidstr
);
1007 centry_free(centry
);
1008 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1011 /* We only have 17 bytes more data in the salted cred case. */
1012 if (centry
->len
- centry
->ofs
== 17) {
1013 *cached_salt
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1015 *cached_salt
= NULL
;
1019 dump_data(100, *cached_nt_pass
, NT_HASH_LEN
);
1021 dump_data(100, *cached_salt
, NT_HASH_LEN
);
1024 status
= centry
->status
;
1026 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1027 sid_string_static(sid
), nt_errstr(status
) ));
1029 centry_free(centry
);
1033 /* Store creds for a SID - only writes out new salted ones. */
1035 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1036 TALLOC_CTX
*mem_ctx
,
1038 const uint8 nt_pass
[NT_HASH_LEN
])
1040 struct cache_entry
*centry
;
1043 uint8 cred_salt
[NT_HASH_LEN
];
1044 uint8 salted_hash
[NT_HASH_LEN
];
1046 if (is_null_sid(sid
)) {
1047 return NT_STATUS_INVALID_SID
;
1050 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1051 return NT_STATUS_INVALID_SID
;
1054 centry
= centry_start(domain
, NT_STATUS_OK
);
1056 return NT_STATUS_INTERNAL_DB_ERROR
;
1060 dump_data(100, nt_pass
, NT_HASH_LEN
);
1063 centry_put_time(centry
, time(NULL
));
1065 /* Create a salt and then salt the hash. */
1066 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1067 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1069 centry_put_hash16(centry
, salted_hash
);
1070 centry_put_hash16(centry
, cred_salt
);
1071 centry_end(centry
, "CRED/%s", sid_to_string(sid_string
, sid
));
1073 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1075 centry_free(centry
);
1077 return NT_STATUS_OK
;
1081 /* Query display info. This is the basic user list fn */
1082 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
1083 TALLOC_CTX
*mem_ctx
,
1084 uint32
*num_entries
,
1085 WINBIND_USERINFO
**info
)
1087 struct winbind_cache
*cache
= get_cache(domain
);
1088 struct cache_entry
*centry
= NULL
;
1090 unsigned int i
, retry
;
1095 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1099 *num_entries
= centry_uint32(centry
);
1101 if (*num_entries
== 0)
1104 (*info
) = TALLOC_ARRAY(mem_ctx
, WINBIND_USERINFO
, *num_entries
);
1106 smb_panic_fn("query_user_list out of memory");
1108 for (i
=0; i
<(*num_entries
); i
++) {
1109 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
1110 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
1111 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
1112 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
1113 centry_sid(centry
, mem_ctx
, &(*info
)[i
].user_sid
);
1114 centry_sid(centry
, mem_ctx
, &(*info
)[i
].group_sid
);
1118 status
= centry
->status
;
1120 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1121 domain
->name
, nt_errstr(status
) ));
1123 centry_free(centry
);
1130 /* Return status value returned by seq number check */
1132 if (!NT_STATUS_IS_OK(domain
->last_status
))
1133 return domain
->last_status
;
1135 /* Put the query_user_list() in a retry loop. There appears to be
1136 * some bug either with Windows 2000 or Samba's handling of large
1137 * rpc replies. This manifests itself as sudden disconnection
1138 * at a random point in the enumeration of a large (60k) user list.
1139 * The retry loop simply tries the operation again. )-: It's not
1140 * pretty but an acceptable workaround until we work out what the
1141 * real problem is. */
1146 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1149 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
1150 if (!NT_STATUS_IS_OK(status
))
1151 DEBUG(3, ("query_user_list: returned 0x%08x, "
1152 "retrying\n", NT_STATUS_V(status
)));
1153 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1154 DEBUG(3, ("query_user_list: flushing "
1155 "connection cache\n"));
1156 invalidate_cm_connection(&domain
->conn
);
1159 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1163 refresh_sequence_number(domain
, False
);
1164 centry
= centry_start(domain
, status
);
1167 centry_put_uint32(centry
, *num_entries
);
1168 for (i
=0; i
<(*num_entries
); i
++) {
1169 centry_put_string(centry
, (*info
)[i
].acct_name
);
1170 centry_put_string(centry
, (*info
)[i
].full_name
);
1171 centry_put_string(centry
, (*info
)[i
].homedir
);
1172 centry_put_string(centry
, (*info
)[i
].shell
);
1173 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1174 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1175 if (domain
->backend
&& domain
->backend
->consistent
) {
1176 /* when the backend is consistent we can pre-prime some mappings */
1177 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1179 (*info
)[i
].acct_name
,
1180 &(*info
)[i
].user_sid
,
1182 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1183 &(*info
)[i
].user_sid
,
1185 (*info
)[i
].acct_name
,
1187 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1190 centry_end(centry
, "UL/%s", domain
->name
);
1191 centry_free(centry
);
1197 /* list all domain groups */
1198 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
1199 TALLOC_CTX
*mem_ctx
,
1200 uint32
*num_entries
,
1201 struct acct_info
**info
)
1203 struct winbind_cache
*cache
= get_cache(domain
);
1204 struct cache_entry
*centry
= NULL
;
1211 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1215 *num_entries
= centry_uint32(centry
);
1217 if (*num_entries
== 0)
1220 (*info
) = TALLOC_ARRAY(mem_ctx
, struct acct_info
, *num_entries
);
1222 smb_panic_fn("enum_dom_groups out of memory");
1224 for (i
=0; i
<(*num_entries
); i
++) {
1225 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1226 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1227 (*info
)[i
].rid
= centry_uint32(centry
);
1231 status
= centry
->status
;
1233 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1234 domain
->name
, nt_errstr(status
) ));
1236 centry_free(centry
);
1243 /* Return status value returned by seq number check */
1245 if (!NT_STATUS_IS_OK(domain
->last_status
))
1246 return domain
->last_status
;
1248 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1251 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1254 refresh_sequence_number(domain
, False
);
1255 centry
= centry_start(domain
, status
);
1258 centry_put_uint32(centry
, *num_entries
);
1259 for (i
=0; i
<(*num_entries
); i
++) {
1260 centry_put_string(centry
, (*info
)[i
].acct_name
);
1261 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1262 centry_put_uint32(centry
, (*info
)[i
].rid
);
1264 centry_end(centry
, "GL/%s/domain", domain
->name
);
1265 centry_free(centry
);
1271 /* list all domain groups */
1272 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
1273 TALLOC_CTX
*mem_ctx
,
1274 uint32
*num_entries
,
1275 struct acct_info
**info
)
1277 struct winbind_cache
*cache
= get_cache(domain
);
1278 struct cache_entry
*centry
= NULL
;
1285 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1289 *num_entries
= centry_uint32(centry
);
1291 if (*num_entries
== 0)
1294 (*info
) = TALLOC_ARRAY(mem_ctx
, struct acct_info
, *num_entries
);
1296 smb_panic_fn("enum_dom_groups out of memory");
1298 for (i
=0; i
<(*num_entries
); i
++) {
1299 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1300 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1301 (*info
)[i
].rid
= centry_uint32(centry
);
1306 /* If we are returning cached data and the domain controller
1307 is down then we don't know whether the data is up to date
1308 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1311 if (wcache_server_down(domain
)) {
1312 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1313 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1315 status
= centry
->status
;
1317 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1318 domain
->name
, nt_errstr(status
) ));
1320 centry_free(centry
);
1327 /* Return status value returned by seq number check */
1329 if (!NT_STATUS_IS_OK(domain
->last_status
))
1330 return domain
->last_status
;
1332 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1335 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1338 refresh_sequence_number(domain
, False
);
1339 centry
= centry_start(domain
, status
);
1342 centry_put_uint32(centry
, *num_entries
);
1343 for (i
=0; i
<(*num_entries
); i
++) {
1344 centry_put_string(centry
, (*info
)[i
].acct_name
);
1345 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1346 centry_put_uint32(centry
, (*info
)[i
].rid
);
1348 centry_end(centry
, "GL/%s/local", domain
->name
);
1349 centry_free(centry
);
1355 /* convert a single name to a sid in a domain */
1356 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
1357 TALLOC_CTX
*mem_ctx
,
1358 const char *domain_name
,
1361 enum lsa_SidType
*type
)
1363 struct winbind_cache
*cache
= get_cache(domain
);
1364 struct cache_entry
*centry
= NULL
;
1371 fstrcpy(uname
, name
);
1373 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1376 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1377 status
= centry
->status
;
1378 if (NT_STATUS_IS_OK(status
)) {
1379 centry_sid(centry
, mem_ctx
, sid
);
1382 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: %s\n",
1383 domain
->name
, nt_errstr(status
) ));
1385 centry_free(centry
);
1391 /* If the seq number check indicated that there is a problem
1392 * with this DC, then return that status... except for
1393 * access_denied. This is special because the dc may be in
1394 * "restrict anonymous = 1" mode, in which case it will deny
1395 * most unauthenticated operations, but *will* allow the LSA
1396 * name-to-sid that we try as a fallback. */
1398 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1399 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1400 return domain
->last_status
;
1402 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1405 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
, name
, sid
, type
);
1408 refresh_sequence_number(domain
, False
);
1410 if (domain
->online
&& !is_null_sid(sid
)) {
1411 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1414 if (NT_STATUS_IS_OK(status
)) {
1415 strupper_m(CONST_DISCARD(char *,domain_name
));
1416 strlower_m(CONST_DISCARD(char *,name
));
1417 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1423 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1425 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1426 TALLOC_CTX
*mem_ctx
,
1430 enum lsa_SidType
*type
)
1432 struct winbind_cache
*cache
= get_cache(domain
);
1433 struct cache_entry
*centry
= NULL
;
1440 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_to_string(sid_string
, sid
));
1443 if (NT_STATUS_IS_OK(centry
->status
)) {
1444 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1445 *domain_name
= centry_string(centry
, mem_ctx
);
1446 *name
= centry_string(centry
, mem_ctx
);
1448 status
= centry
->status
;
1450 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: %s\n",
1451 domain
->name
, nt_errstr(status
) ));
1453 centry_free(centry
);
1458 *domain_name
= NULL
;
1460 /* If the seq number check indicated that there is a problem
1461 * with this DC, then return that status... except for
1462 * access_denied. This is special because the dc may be in
1463 * "restrict anonymous = 1" mode, in which case it will deny
1464 * most unauthenticated operations, but *will* allow the LSA
1465 * sid-to-name that we try as a fallback. */
1467 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1468 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1469 return domain
->last_status
;
1471 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1474 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1477 refresh_sequence_number(domain
, False
);
1478 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
1480 /* We can't save the name to sid mapping here, as with sid history a
1481 * later name2sid would give the wrong sid. */
1486 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
1487 TALLOC_CTX
*mem_ctx
,
1488 const DOM_SID
*domain_sid
,
1493 enum lsa_SidType
**types
)
1495 struct winbind_cache
*cache
= get_cache(domain
);
1497 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1501 *domain_name
= NULL
;
1509 if (num_rids
== 0) {
1510 return NT_STATUS_OK
;
1513 *names
= TALLOC_ARRAY(mem_ctx
, char *, num_rids
);
1514 *types
= TALLOC_ARRAY(mem_ctx
, enum lsa_SidType
, num_rids
);
1516 if ((*names
== NULL
) || (*types
== NULL
)) {
1517 result
= NT_STATUS_NO_MEMORY
;
1521 have_mapped
= have_unmapped
= False
;
1523 for (i
=0; i
<num_rids
; i
++) {
1525 struct cache_entry
*centry
;
1527 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
1528 result
= NT_STATUS_INTERNAL_ERROR
;
1532 centry
= wcache_fetch(cache
, domain
, "SN/%s",
1533 sid_string_static(&sid
));
1538 (*types
)[i
] = SID_NAME_UNKNOWN
;
1539 (*names
)[i
] = talloc_strdup(*names
, "");
1541 if (NT_STATUS_IS_OK(centry
->status
)) {
1544 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
1545 dom
= centry_string(centry
, mem_ctx
);
1546 if (*domain_name
== NULL
) {
1551 (*names
)[i
] = centry_string(centry
, *names
);
1553 have_unmapped
= True
;
1556 centry_free(centry
);
1560 return NT_STATUS_NONE_MAPPED
;
1562 if (!have_unmapped
) {
1563 return NT_STATUS_OK
;
1565 return STATUS_SOME_UNMAPPED
;
1569 TALLOC_FREE(*names
);
1570 TALLOC_FREE(*types
);
1572 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
1573 rids
, num_rids
, domain_name
,
1576 if (!NT_STATUS_IS_OK(result
) &&
1577 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
1581 refresh_sequence_number(domain
, False
);
1583 for (i
=0; i
<num_rids
; i
++) {
1587 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
1588 result
= NT_STATUS_INTERNAL_ERROR
;
1592 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
1593 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
1595 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
1596 (*names
)[i
], (*types
)[i
]);
1603 TALLOC_FREE(*names
);
1604 TALLOC_FREE(*types
);
1608 /* Lookup user information from a rid */
1609 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
1610 TALLOC_CTX
*mem_ctx
,
1611 const DOM_SID
*user_sid
,
1612 WINBIND_USERINFO
*info
)
1614 struct winbind_cache
*cache
= get_cache(domain
);
1615 struct cache_entry
*centry
= NULL
;
1621 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string_static(user_sid
));
1623 /* If we have an access denied cache entry and a cached info3 in the
1624 samlogon cache then do a query. This will force the rpc back end
1625 to return the info3 data. */
1627 if (NT_STATUS_V(domain
->last_status
) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED
) &&
1628 netsamlogon_cache_have(user_sid
)) {
1629 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1630 domain
->last_status
= NT_STATUS_OK
;
1631 centry_free(centry
);
1638 info
->acct_name
= centry_string(centry
, mem_ctx
);
1639 info
->full_name
= centry_string(centry
, mem_ctx
);
1640 info
->homedir
= centry_string(centry
, mem_ctx
);
1641 info
->shell
= centry_string(centry
, mem_ctx
);
1642 info
->primary_gid
= centry_uint32(centry
);
1643 centry_sid(centry
, mem_ctx
, &info
->user_sid
);
1644 centry_sid(centry
, mem_ctx
, &info
->group_sid
);
1645 status
= centry
->status
;
1647 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: %s\n",
1648 domain
->name
, nt_errstr(status
) ));
1650 centry_free(centry
);
1656 /* Return status value returned by seq number check */
1658 if (!NT_STATUS_IS_OK(domain
->last_status
))
1659 return domain
->last_status
;
1661 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
1664 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
1667 refresh_sequence_number(domain
, False
);
1668 wcache_save_user(domain
, status
, info
);
1674 /* Lookup groups a user is a member of. */
1675 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
1676 TALLOC_CTX
*mem_ctx
,
1677 const DOM_SID
*user_sid
,
1678 uint32
*num_groups
, DOM_SID
**user_gids
)
1680 struct winbind_cache
*cache
= get_cache(domain
);
1681 struct cache_entry
*centry
= NULL
;
1689 centry
= wcache_fetch(cache
, domain
, "UG/%s", sid_to_string(sid_string
, user_sid
));
1691 /* If we have an access denied cache entry and a cached info3 in the
1692 samlogon cache then do a query. This will force the rpc back end
1693 to return the info3 data. */
1695 if (NT_STATUS_V(domain
->last_status
) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED
) &&
1696 netsamlogon_cache_have(user_sid
)) {
1697 DEBUG(10, ("lookup_usergroups: cached access denied and have cached info3\n"));
1698 domain
->last_status
= NT_STATUS_OK
;
1699 centry_free(centry
);
1706 *num_groups
= centry_uint32(centry
);
1708 if (*num_groups
== 0)
1711 (*user_gids
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_groups
);
1712 if (! (*user_gids
)) {
1713 smb_panic_fn("lookup_usergroups out of memory");
1715 for (i
=0; i
<(*num_groups
); i
++) {
1716 centry_sid(centry
, mem_ctx
, &(*user_gids
)[i
]);
1720 status
= centry
->status
;
1722 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status: %s\n",
1723 domain
->name
, nt_errstr(status
) ));
1725 centry_free(centry
);
1730 (*user_gids
) = NULL
;
1732 /* Return status value returned by seq number check */
1734 if (!NT_STATUS_IS_OK(domain
->last_status
))
1735 return domain
->last_status
;
1737 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
1740 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
1742 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
1746 refresh_sequence_number(domain
, False
);
1747 centry
= centry_start(domain
, status
);
1750 centry_put_uint32(centry
, *num_groups
);
1751 for (i
=0; i
<(*num_groups
); i
++) {
1752 centry_put_sid(centry
, &(*user_gids
)[i
]);
1754 centry_end(centry
, "UG/%s", sid_to_string(sid_string
, user_sid
));
1755 centry_free(centry
);
1761 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
1762 TALLOC_CTX
*mem_ctx
,
1763 uint32 num_sids
, const DOM_SID
*sids
,
1764 uint32
*num_aliases
, uint32
**alias_rids
)
1766 struct winbind_cache
*cache
= get_cache(domain
);
1767 struct cache_entry
*centry
= NULL
;
1769 char *sidlist
= talloc_strdup(mem_ctx
, "");
1775 if (num_sids
== 0) {
1778 return NT_STATUS_OK
;
1781 /* We need to cache indexed by the whole list of SIDs, the aliases
1782 * resulting might come from any of the SIDs. */
1784 for (i
=0; i
<num_sids
; i
++) {
1785 sidlist
= talloc_asprintf(mem_ctx
, "%s/%s", sidlist
,
1786 sid_string_static(&sids
[i
]));
1787 if (sidlist
== NULL
)
1788 return NT_STATUS_NO_MEMORY
;
1791 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
1796 *num_aliases
= centry_uint32(centry
);
1800 (*alias_rids
) = TALLOC_ARRAY(mem_ctx
, uint32
, *num_aliases
);
1802 if ((*alias_rids
) == NULL
) {
1803 centry_free(centry
);
1804 return NT_STATUS_NO_MEMORY
;
1807 (*alias_rids
) = NULL
;
1810 for (i
=0; i
<(*num_aliases
); i
++)
1811 (*alias_rids
)[i
] = centry_uint32(centry
);
1813 status
= centry
->status
;
1815 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
1816 "status %s\n", domain
->name
, nt_errstr(status
)));
1818 centry_free(centry
);
1823 (*alias_rids
) = NULL
;
1825 if (!NT_STATUS_IS_OK(domain
->last_status
))
1826 return domain
->last_status
;
1828 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
1829 "for domain %s\n", domain
->name
));
1831 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
1833 num_aliases
, alias_rids
);
1836 refresh_sequence_number(domain
, False
);
1837 centry
= centry_start(domain
, status
);
1840 centry_put_uint32(centry
, *num_aliases
);
1841 for (i
=0; i
<(*num_aliases
); i
++)
1842 centry_put_uint32(centry
, (*alias_rids
)[i
]);
1843 centry_end(centry
, "UA%s", sidlist
);
1844 centry_free(centry
);
1851 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
1852 TALLOC_CTX
*mem_ctx
,
1853 const DOM_SID
*group_sid
, uint32
*num_names
,
1854 DOM_SID
**sid_mem
, char ***names
,
1855 uint32
**name_types
)
1857 struct winbind_cache
*cache
= get_cache(domain
);
1858 struct cache_entry
*centry
= NULL
;
1866 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_to_string(sid_string
, group_sid
));
1870 *num_names
= centry_uint32(centry
);
1872 if (*num_names
== 0)
1875 (*sid_mem
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_names
);
1876 (*names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_names
);
1877 (*name_types
) = TALLOC_ARRAY(mem_ctx
, uint32
, *num_names
);
1879 if (! (*sid_mem
) || ! (*names
) || ! (*name_types
)) {
1880 smb_panic_fn("lookup_groupmem out of memory");
1883 for (i
=0; i
<(*num_names
); i
++) {
1884 centry_sid(centry
, mem_ctx
, &(*sid_mem
)[i
]);
1885 (*names
)[i
] = centry_string(centry
, mem_ctx
);
1886 (*name_types
)[i
] = centry_uint32(centry
);
1890 status
= centry
->status
;
1892 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status: %s\n",
1893 domain
->name
, nt_errstr(status
)));
1895 centry_free(centry
);
1902 (*name_types
) = NULL
;
1904 /* Return status value returned by seq number check */
1906 if (!NT_STATUS_IS_OK(domain
->last_status
))
1907 return domain
->last_status
;
1909 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
1912 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
1913 sid_mem
, names
, name_types
);
1916 refresh_sequence_number(domain
, False
);
1917 centry
= centry_start(domain
, status
);
1920 centry_put_uint32(centry
, *num_names
);
1921 for (i
=0; i
<(*num_names
); i
++) {
1922 centry_put_sid(centry
, &(*sid_mem
)[i
]);
1923 centry_put_string(centry
, (*names
)[i
]);
1924 centry_put_uint32(centry
, (*name_types
)[i
]);
1926 centry_end(centry
, "GM/%s", sid_to_string(sid_string
, group_sid
));
1927 centry_free(centry
);
1933 /* find the sequence number for a domain */
1934 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
1936 refresh_sequence_number(domain
, False
);
1938 *seq
= domain
->sequence_number
;
1940 return NT_STATUS_OK
;
1943 /* enumerate trusted domains
1944 * (we need to have the list of trustdoms in the cache when we go offline) -
1946 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
1947 TALLOC_CTX
*mem_ctx
,
1948 uint32
*num_domains
,
1953 struct winbind_cache
*cache
= get_cache(domain
);
1954 struct cache_entry
*centry
= NULL
;
1961 centry
= wcache_fetch(cache
, domain
, "TRUSTDOMS/%s", domain
->name
);
1967 *num_domains
= centry_uint32(centry
);
1970 (*names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
1971 (*alt_names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
1972 (*dom_sids
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_domains
);
1974 if (! (*dom_sids
) || ! (*names
) || ! (*alt_names
)) {
1975 smb_panic_fn("trusted_domains out of memory");
1979 (*alt_names
) = NULL
;
1983 for (i
=0; i
<(*num_domains
); i
++) {
1984 (*names
)[i
] = centry_string(centry
, mem_ctx
);
1985 (*alt_names
)[i
] = centry_string(centry
, mem_ctx
);
1986 centry_sid(centry
, mem_ctx
, &(*dom_sids
)[i
]);
1989 status
= centry
->status
;
1991 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
1992 domain
->name
, *num_domains
, nt_errstr(status
) ));
1994 centry_free(centry
);
2001 (*alt_names
) = NULL
;
2003 /* Return status value returned by seq number check */
2005 if (!NT_STATUS_IS_OK(domain
->last_status
))
2006 return domain
->last_status
;
2008 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2011 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, num_domains
,
2012 names
, alt_names
, dom_sids
);
2014 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2015 * so that the generic centry handling still applies correctly -
2018 if (!NT_STATUS_IS_ERR(status
)) {
2019 status
= NT_STATUS_OK
;
2023 #if 0 /* Disabled as we want the trust dom list to be managed by
2024 the main parent and always to make the query. --jerry */
2027 refresh_sequence_number(domain
, False
);
2029 centry
= centry_start(domain
, status
);
2033 centry_put_uint32(centry
, *num_domains
);
2035 for (i
=0; i
<(*num_domains
); i
++) {
2036 centry_put_string(centry
, (*names
)[i
]);
2037 centry_put_string(centry
, (*alt_names
)[i
]);
2038 centry_put_sid(centry
, &(*dom_sids
)[i
]);
2041 centry_end(centry
, "TRUSTDOMS/%s", domain
->name
);
2043 centry_free(centry
);
2051 /* get lockout policy */
2052 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
2053 TALLOC_CTX
*mem_ctx
,
2054 SAM_UNK_INFO_12
*policy
){
2055 struct winbind_cache
*cache
= get_cache(domain
);
2056 struct cache_entry
*centry
= NULL
;
2062 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2067 policy
->duration
= centry_nttime(centry
);
2068 policy
->reset_count
= centry_nttime(centry
);
2069 policy
->bad_attempt_lockout
= centry_uint16(centry
);
2071 status
= centry
->status
;
2073 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2074 domain
->name
, nt_errstr(status
) ));
2076 centry_free(centry
);
2080 ZERO_STRUCTP(policy
);
2082 /* Return status value returned by seq number check */
2084 if (!NT_STATUS_IS_OK(domain
->last_status
))
2085 return domain
->last_status
;
2087 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2090 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2093 refresh_sequence_number(domain
, False
);
2094 wcache_save_lockout_policy(domain
, status
, policy
);
2099 /* get password policy */
2100 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
2101 TALLOC_CTX
*mem_ctx
,
2102 SAM_UNK_INFO_1
*policy
)
2104 struct winbind_cache
*cache
= get_cache(domain
);
2105 struct cache_entry
*centry
= NULL
;
2111 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2116 policy
->min_length_password
= centry_uint16(centry
);
2117 policy
->password_history
= centry_uint16(centry
);
2118 policy
->password_properties
= centry_uint32(centry
);
2119 policy
->expire
= centry_nttime(centry
);
2120 policy
->min_passwordage
= centry_nttime(centry
);
2122 status
= centry
->status
;
2124 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2125 domain
->name
, nt_errstr(status
) ));
2127 centry_free(centry
);
2131 ZERO_STRUCTP(policy
);
2133 /* Return status value returned by seq number check */
2135 if (!NT_STATUS_IS_OK(domain
->last_status
))
2136 return domain
->last_status
;
2138 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2141 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
2144 refresh_sequence_number(domain
, False
);
2145 wcache_save_password_policy(domain
, status
, policy
);
2151 /* Invalidate cached user and group lists coherently */
2153 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2156 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
2157 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
2158 tdb_delete(the_tdb
, kbuf
);
2163 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2165 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
2166 NET_USER_INFO_3
*info3
)
2168 struct winbind_cache
*cache
;
2170 /* dont clear cached U/SID and UG/SID entries when we want to logon
2173 if (lp_winbind_offline_logon()) {
2180 cache
= get_cache(domain
);
2181 netsamlogon_clear_cached_user(cache
->tdb
, info3
);
2184 void wcache_invalidate_cache(void)
2186 struct winbindd_domain
*domain
;
2188 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
2189 struct winbind_cache
*cache
= get_cache(domain
);
2191 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2192 "entries for %s\n", domain
->name
));
2194 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
2198 BOOL
init_wcache(void)
2200 if (wcache
== NULL
) {
2201 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
2202 ZERO_STRUCTP(wcache
);
2205 if (wcache
->tdb
!= NULL
)
2208 /* when working offline we must not clear the cache on restart */
2209 wcache
->tdb
= tdb_open_log(lock_path("winbindd_cache.tdb"),
2210 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
2211 lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
2212 O_RDWR
|O_CREAT
, 0600);
2214 if (wcache
->tdb
== NULL
) {
2215 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2222 /************************************************************************
2223 This is called by the parent to initialize the cache file.
2224 We don't need sophisticated locking here as we know we're the
2226 ************************************************************************/
2228 BOOL
initialize_winbindd_cache(void)
2230 BOOL cache_bad
= True
;
2233 if (!init_wcache()) {
2234 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
2238 /* Check version number. */
2239 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
2240 vers
== WINBINDD_CACHE_VERSION
) {
2245 DEBUG(0,("initialize_winbindd_cache: clearing cache "
2246 "and re-creating with version number %d\n",
2247 WINBINDD_CACHE_VERSION
));
2249 tdb_close(wcache
->tdb
);
2252 if (unlink(lock_path("winbindd_cache.tdb")) == -1) {
2253 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
2254 lock_path("winbindd_cache.tdb"),
2258 if (!init_wcache()) {
2259 DEBUG(0,("initialize_winbindd_cache: re-initialization "
2260 "init_wcache failed.\n"));
2264 /* Write the version. */
2265 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
2266 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
2267 tdb_errorstr(wcache
->tdb
) ));
2272 tdb_close(wcache
->tdb
);
2277 void cache_store_response(pid_t pid
, struct winbindd_response
*response
)
2284 DEBUG(10, ("Storing response for pid %d, len %d\n",
2285 pid
, response
->length
));
2287 fstr_sprintf(key_str
, "DR/%d", pid
);
2288 if (tdb_store(wcache
->tdb
, string_tdb_data(key_str
),
2289 make_tdb_data((uint8
*)response
, sizeof(*response
)),
2293 if (response
->length
== sizeof(*response
))
2296 /* There's extra data */
2298 DEBUG(10, ("Storing extra data: len=%d\n",
2299 (int)(response
->length
- sizeof(*response
))));
2301 fstr_sprintf(key_str
, "DE/%d", pid
);
2302 if (tdb_store(wcache
->tdb
, string_tdb_data(key_str
),
2303 make_tdb_data((uint8
*)response
->extra_data
.data
,
2304 response
->length
- sizeof(*response
)),
2308 /* We could not store the extra data, make sure the tdb does not
2309 * contain a main record with wrong dangling extra data */
2311 fstr_sprintf(key_str
, "DR/%d", pid
);
2312 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2317 BOOL
cache_retrieve_response(pid_t pid
, struct winbindd_response
* response
)
2325 DEBUG(10, ("Retrieving response for pid %d\n", pid
));
2327 fstr_sprintf(key_str
, "DR/%d", pid
);
2328 data
= tdb_fetch(wcache
->tdb
, string_tdb_data(key_str
));
2330 if (data
.dptr
== NULL
)
2333 if (data
.dsize
!= sizeof(*response
))
2336 memcpy(response
, data
.dptr
, data
.dsize
);
2337 SAFE_FREE(data
.dptr
);
2339 if (response
->length
== sizeof(*response
)) {
2340 response
->extra_data
.data
= NULL
;
2344 /* There's extra data */
2346 DEBUG(10, ("Retrieving extra data length=%d\n",
2347 (int)(response
->length
- sizeof(*response
))));
2349 fstr_sprintf(key_str
, "DE/%d", pid
);
2350 data
= tdb_fetch(wcache
->tdb
, string_tdb_data(key_str
));
2352 if (data
.dptr
== NULL
) {
2353 DEBUG(0, ("Did not find extra data\n"));
2357 if (data
.dsize
!= (response
->length
- sizeof(*response
))) {
2358 DEBUG(0, ("Invalid extra data length: %d\n", (int)data
.dsize
));
2359 SAFE_FREE(data
.dptr
);
2363 dump_data(11, (uint8
*)data
.dptr
, data
.dsize
);
2365 response
->extra_data
.data
= data
.dptr
;
2369 void cache_cleanup_response(pid_t pid
)
2376 fstr_sprintf(key_str
, "DR/%d", pid
);
2377 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2379 fstr_sprintf(key_str
, "DE/%d", pid
);
2380 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2386 BOOL
lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const DOM_SID
*sid
,
2387 char **domain_name
, char **name
,
2388 enum lsa_SidType
*type
)
2390 struct winbindd_domain
*domain
;
2391 struct winbind_cache
*cache
;
2392 struct cache_entry
*centry
= NULL
;
2395 domain
= find_lookup_domain_from_sid(sid
);
2396 if (domain
== NULL
) {
2400 cache
= get_cache(domain
);
2402 if (cache
->tdb
== NULL
) {
2406 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_string_static(sid
));
2407 if (centry
== NULL
) {
2411 if (NT_STATUS_IS_OK(centry
->status
)) {
2412 *type
= (enum lsa_SidType
)centry_uint32(centry
);
2413 *domain_name
= centry_string(centry
, mem_ctx
);
2414 *name
= centry_string(centry
, mem_ctx
);
2417 status
= centry
->status
;
2418 centry_free(centry
);
2419 return NT_STATUS_IS_OK(status
);
2422 BOOL
lookup_cached_name(TALLOC_CTX
*mem_ctx
,
2423 const char *domain_name
,
2426 enum lsa_SidType
*type
)
2428 struct winbindd_domain
*domain
;
2429 struct winbind_cache
*cache
;
2430 struct cache_entry
*centry
= NULL
;
2433 BOOL original_online_state
;
2435 domain
= find_lookup_domain_from_name(domain_name
);
2436 if (domain
== NULL
) {
2440 cache
= get_cache(domain
);
2442 if (cache
->tdb
== NULL
) {
2446 fstrcpy(uname
, name
);
2449 /* If we are doing a cached logon, temporarily set the domain
2450 offline so the cache won't expire the entry */
2452 original_online_state
= domain
->online
;
2453 domain
->online
= False
;
2454 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
2455 domain
->online
= original_online_state
;
2457 if (centry
== NULL
) {
2461 if (NT_STATUS_IS_OK(centry
->status
)) {
2462 *type
= (enum lsa_SidType
)centry_uint32(centry
);
2463 centry_sid(centry
, mem_ctx
, sid
);
2466 status
= centry
->status
;
2467 centry_free(centry
);
2469 return NT_STATUS_IS_OK(status
);
2472 void cache_name2sid(struct winbindd_domain
*domain
,
2473 const char *domain_name
, const char *name
,
2474 enum lsa_SidType type
, const DOM_SID
*sid
)
2476 refresh_sequence_number(domain
, False
);
2477 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
2482 * The original idea that this cache only contains centries has
2483 * been blurred - now other stuff gets put in here. Ensure we
2484 * ignore these things on cleanup.
2487 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
2488 TDB_DATA dbuf
, void *state
)
2490 struct cache_entry
*centry
;
2492 if (is_non_centry_key(kbuf
)) {
2496 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
2501 if (!NT_STATUS_IS_OK(centry
->status
)) {
2502 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
2503 tdb_delete(the_tdb
, kbuf
);
2506 centry_free(centry
);
2510 /* flush the cache */
2511 void wcache_flush_cache(void)
2516 tdb_close(wcache
->tdb
);
2522 /* when working offline we must not clear the cache on restart */
2523 wcache
->tdb
= tdb_open_log(lock_path("winbindd_cache.tdb"),
2524 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
2525 lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
2526 O_RDWR
|O_CREAT
, 0600);
2529 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2533 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
2535 DEBUG(10,("wcache_flush_cache success\n"));
2538 /* Count cached creds */
2540 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2543 int *cred_count
= (int*)state
;
2545 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
2551 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
2553 struct winbind_cache
*cache
= get_cache(domain
);
2558 return NT_STATUS_INTERNAL_DB_ERROR
;
2561 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
2563 return NT_STATUS_OK
;
2567 struct cred_list
*prev
, *next
;
2572 static struct cred_list
*wcache_cred_list
;
2574 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2577 struct cred_list
*cred
;
2579 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
2581 cred
= SMB_MALLOC_P(struct cred_list
);
2583 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2589 /* save a copy of the key */
2591 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
2592 DLIST_ADD(wcache_cred_list
, cred
);
2598 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const DOM_SID
*sid
)
2600 struct winbind_cache
*cache
= get_cache(domain
);
2603 struct cred_list
*cred
, *oldest
= NULL
;
2606 return NT_STATUS_INTERNAL_DB_ERROR
;
2609 /* we possibly already have an entry */
2610 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
2614 DEBUG(11,("we already have an entry, deleting that\n"));
2616 fstr_sprintf(key_str
, "CRED/%s", sid_string_static(sid
));
2618 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
2620 return NT_STATUS_OK
;
2623 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
2625 return NT_STATUS_OK
;
2626 } else if ((ret
== -1) || (wcache_cred_list
== NULL
)) {
2627 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2630 ZERO_STRUCTP(oldest
);
2632 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
2637 data
= tdb_fetch(cache
->tdb
, string_tdb_data(cred
->name
));
2639 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
2641 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2645 t
= IVAL(data
.dptr
, 0);
2646 SAFE_FREE(data
.dptr
);
2649 oldest
= SMB_MALLOC_P(struct cred_list
);
2650 if (oldest
== NULL
) {
2651 status
= NT_STATUS_NO_MEMORY
;
2655 fstrcpy(oldest
->name
, cred
->name
);
2656 oldest
->created
= t
;
2660 if (t
< oldest
->created
) {
2661 fstrcpy(oldest
->name
, cred
->name
);
2662 oldest
->created
= t
;
2666 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
2667 status
= NT_STATUS_OK
;
2669 status
= NT_STATUS_UNSUCCESSFUL
;
2672 SAFE_FREE(wcache_cred_list
);
2678 /* Change the global online/offline state. */
2679 BOOL
set_global_winbindd_state_offline(void)
2683 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
2685 /* Only go offline if someone has created
2686 the key "WINBINDD_OFFLINE" in the cache tdb. */
2688 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
2689 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
2693 if (!lp_winbind_offline_logon()) {
2694 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
2698 if (global_winbindd_offline_state
) {
2699 /* Already offline. */
2703 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
2705 if (!data
.dptr
|| data
.dsize
!= 4) {
2706 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
2707 SAFE_FREE(data
.dptr
);
2710 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
2711 global_winbindd_offline_state
= True
;
2712 SAFE_FREE(data
.dptr
);
2717 void set_global_winbindd_state_online(void)
2719 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
2721 if (!lp_winbind_offline_logon()) {
2722 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
2726 if (!global_winbindd_offline_state
) {
2727 /* Already online. */
2730 global_winbindd_offline_state
= False
;
2736 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
2737 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
2740 BOOL
get_global_winbindd_state_offline(void)
2742 return global_winbindd_offline_state
;
2745 /***********************************************************************
2746 Validate functions for all possible cache tdb keys.
2747 ***********************************************************************/
2749 struct validation_status
{
2757 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
2758 struct validation_status
*state
)
2760 struct cache_entry
*centry
;
2762 centry
= SMB_XMALLOC_P(struct cache_entry
);
2763 centry
->data
= (unsigned char *)memdup(data
.dptr
, data
.dsize
);
2764 if (!centry
->data
) {
2768 centry
->len
= data
.dsize
;
2771 if (centry
->len
< 8) {
2772 /* huh? corrupt cache? */
2773 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr
));
2774 centry_free(centry
);
2775 state
->bad_entry
= True
;
2776 state
->success
= False
;
2780 centry
->status
= NT_STATUS(centry_uint32(centry
));
2781 centry
->sequence_number
= centry_uint32(centry
);
2785 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2786 struct validation_status
*state
)
2788 if (dbuf
.dsize
!= 8) {
2789 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
2790 keystr
, (unsigned int)dbuf
.dsize
));
2791 state
->bad_entry
= True
;
2797 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2798 struct validation_status
*state
)
2800 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
2805 (void)centry_uint32(centry
);
2806 if (NT_STATUS_IS_OK(centry
->status
)) {
2808 (void)centry_sid(centry
, mem_ctx
, &sid
);
2811 centry_free(centry
);
2813 if (!(state
->success
)) {
2816 DEBUG(10,("validate_ns: %s ok\n", keystr
));
2820 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2821 struct validation_status
*state
)
2823 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
2828 if (NT_STATUS_IS_OK(centry
->status
)) {
2829 (void)centry_uint32(centry
);
2830 (void)centry_string(centry
, mem_ctx
);
2831 (void)centry_string(centry
, mem_ctx
);
2834 centry_free(centry
);
2836 if (!(state
->success
)) {
2839 DEBUG(10,("validate_sn: %s ok\n", keystr
));
2843 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2844 struct validation_status
*state
)
2846 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
2853 (void)centry_string(centry
, mem_ctx
);
2854 (void)centry_string(centry
, mem_ctx
);
2855 (void)centry_string(centry
, mem_ctx
);
2856 (void)centry_string(centry
, mem_ctx
);
2857 (void)centry_uint32(centry
);
2858 (void)centry_sid(centry
, mem_ctx
, &sid
);
2859 (void)centry_sid(centry
, mem_ctx
, &sid
);
2861 centry_free(centry
);
2863 if (!(state
->success
)) {
2866 DEBUG(10,("validate_u: %s ok\n", keystr
));
2870 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2871 struct validation_status
*state
)
2873 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
2879 (void)centry_nttime(centry
);
2880 (void)centry_nttime(centry
);
2881 (void)centry_uint16(centry
);
2883 centry_free(centry
);
2885 if (!(state
->success
)) {
2888 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
2892 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2893 struct validation_status
*state
)
2895 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
2901 (void)centry_uint16(centry
);
2902 (void)centry_uint16(centry
);
2903 (void)centry_uint32(centry
);
2904 (void)centry_nttime(centry
);
2905 (void)centry_nttime(centry
);
2907 centry_free(centry
);
2909 if (!(state
->success
)) {
2912 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
2916 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2917 struct validation_status
*state
)
2919 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
2925 (void)centry_time(centry
);
2926 (void)centry_hash16(centry
, mem_ctx
);
2928 /* We only have 17 bytes more data in the salted cred case. */
2929 if (centry
->len
- centry
->ofs
== 17) {
2930 (void)centry_hash16(centry
, mem_ctx
);
2933 centry_free(centry
);
2935 if (!(state
->success
)) {
2938 DEBUG(10,("validate_cred: %s ok\n", keystr
));
2942 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2943 struct validation_status
*state
)
2945 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
2946 int32 num_entries
, i
;
2952 num_entries
= (int32
)centry_uint32(centry
);
2954 for (i
=0; i
< num_entries
; i
++) {
2956 (void)centry_string(centry
, mem_ctx
);
2957 (void)centry_string(centry
, mem_ctx
);
2958 (void)centry_string(centry
, mem_ctx
);
2959 (void)centry_string(centry
, mem_ctx
);
2960 (void)centry_sid(centry
, mem_ctx
, &sid
);
2961 (void)centry_sid(centry
, mem_ctx
, &sid
);
2964 centry_free(centry
);
2966 if (!(state
->success
)) {
2969 DEBUG(10,("validate_ul: %s ok\n", keystr
));
2973 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2974 struct validation_status
*state
)
2976 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
2977 int32 num_entries
, i
;
2983 num_entries
= centry_uint32(centry
);
2985 for (i
=0; i
< num_entries
; i
++) {
2986 (void)centry_string(centry
, mem_ctx
);
2987 (void)centry_string(centry
, mem_ctx
);
2988 (void)centry_uint32(centry
);
2991 centry_free(centry
);
2993 if (!(state
->success
)) {
2996 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3000 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3001 struct validation_status
*state
)
3003 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3004 int32 num_groups
, i
;
3010 num_groups
= centry_uint32(centry
);
3012 for (i
=0; i
< num_groups
; i
++) {
3014 centry_sid(centry
, mem_ctx
, &sid
);
3017 centry_free(centry
);
3019 if (!(state
->success
)) {
3022 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3026 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3027 struct validation_status
*state
)
3029 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3030 int32 num_aliases
, i
;
3036 num_aliases
= centry_uint32(centry
);
3038 for (i
=0; i
< num_aliases
; i
++) {
3039 (void)centry_uint32(centry
);
3042 centry_free(centry
);
3044 if (!(state
->success
)) {
3047 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3051 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3052 struct validation_status
*state
)
3054 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3061 num_names
= centry_uint32(centry
);
3063 for (i
=0; i
< num_names
; i
++) {
3065 centry_sid(centry
, mem_ctx
, &sid
);
3066 (void)centry_string(centry
, mem_ctx
);
3067 (void)centry_uint32(centry
);
3070 centry_free(centry
);
3072 if (!(state
->success
)) {
3075 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3079 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3080 struct validation_status
*state
)
3082 /* Can't say anything about this other than must be nonzero. */
3083 if (dbuf
.dsize
== 0) {
3084 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3086 state
->bad_entry
= True
;
3087 state
->success
= False
;
3091 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3095 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3096 struct validation_status
*state
)
3098 /* Can't say anything about this other than must be nonzero. */
3099 if (dbuf
.dsize
== 0) {
3100 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3102 state
->bad_entry
= True
;
3103 state
->success
= False
;
3107 DEBUG(10,("validate_de: %s ok\n", keystr
));
3111 static int validate_trustdoms(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3112 struct validation_status
*state
)
3114 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3115 int32 num_domains
, i
;
3121 num_domains
= centry_uint32(centry
);
3123 for (i
=0; i
< num_domains
; i
++) {
3125 (void)centry_string(centry
, mem_ctx
);
3126 (void)centry_string(centry
, mem_ctx
);
3127 (void)centry_sid(centry
, mem_ctx
, &sid
);
3130 centry_free(centry
);
3132 if (!(state
->success
)) {
3135 DEBUG(10,("validate_trustdoms: %s ok\n", keystr
));
3139 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3141 struct validation_status
*state
)
3143 if (dbuf
.dsize
== 0) {
3144 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3145 "key %s (len ==0) ?\n", keystr
));
3146 state
->bad_entry
= True
;
3147 state
->success
= False
;
3151 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3152 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3156 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3157 struct validation_status
*state
)
3159 if (dbuf
.dsize
!= 4) {
3160 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3161 keystr
, (unsigned int)dbuf
.dsize
));
3162 state
->bad_entry
= True
;
3163 state
->success
= False
;
3166 DEBUG(10,("validate_offline: %s ok\n", keystr
));
3170 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3171 struct validation_status
*state
)
3173 if (dbuf
.dsize
!= 4) {
3174 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3175 "key %s (len %u != 4) ?\n",
3176 keystr
, (unsigned int)dbuf
.dsize
));
3177 state
->bad_entry
= True
;
3178 state
->success
= False
;
3182 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
3186 /***********************************************************************
3187 A list of all possible cache tdb keys with associated validation
3189 ***********************************************************************/
3191 struct key_val_struct
{
3192 const char *keyname
;
3193 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct validation_status
* state
);
3195 {"SEQNUM/", validate_seqnum
},
3196 {"NS/", validate_ns
},
3197 {"SN/", validate_sn
},
3199 {"LOC_POL/", validate_loc_pol
},
3200 {"PWD_POL/", validate_pwd_pol
},
3201 {"CRED/", validate_cred
},
3202 {"UL/", validate_ul
},
3203 {"GL/", validate_gl
},
3204 {"UG/", validate_ug
},
3205 {"UA", validate_ua
},
3206 {"GM/", validate_gm
},
3207 {"DR/", validate_dr
},
3208 {"DE/", validate_de
},
3209 {"TRUSTDOMS/", validate_trustdoms
},
3210 {"TRUSTDOMCACHE/", validate_trustdomcache
},
3211 {"WINBINDD_OFFLINE", validate_offline
},
3212 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
3216 /***********************************************************************
3217 Function to look at every entry in the tdb and validate it as far as
3219 ***********************************************************************/
3221 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
3224 struct validation_status
*v_state
= (struct validation_status
*)state
;
3226 /* Paranoia check. */
3227 if (kbuf
.dsize
> 1024) {
3228 DEBUG(0,("cache_traverse_validate_fn: key length too large (%u) > 1024\n\n",
3229 (unsigned int)kbuf
.dsize
));
3233 for (i
= 0; key_val
[i
].keyname
; i
++) {
3234 size_t namelen
= strlen(key_val
[i
].keyname
);
3235 if (kbuf
.dsize
>= namelen
&& (
3236 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
3237 TALLOC_CTX
*mem_ctx
;
3241 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
3245 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
3246 keystr
[kbuf
.dsize
] = '\0';
3248 mem_ctx
= talloc_init("validate_ctx");
3254 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
3258 talloc_destroy(mem_ctx
);
3263 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
3264 dump_data(0, (uint8
*)kbuf
.dptr
, kbuf
.dsize
);
3265 DEBUG(0,("data :\n"));
3266 dump_data(0, (uint8
*)dbuf
.dptr
, dbuf
.dsize
);
3267 v_state
->unknown_key
= True
;
3268 v_state
->success
= False
;
3269 return 1; /* terminate. */
3272 static void validate_panic(const char *const why
)
3274 DEBUG(0,("validating cache: would panic %s\n", why
));
3275 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
3279 /***********************************************************************
3280 Try and validate every entry in the winbindd cache. If we fail here,
3281 delete the cache tdb and return non-zero - the caller (main winbindd
3282 function) will restart us as we don't know if we crashed or not.
3283 ***********************************************************************/
3286 * internal validation function, executed by the child.
3288 static int winbindd_validate_cache_child(const char *cache_path
, int pfd
)
3292 int num_entries
= 0;
3293 TDB_CONTEXT
*tdb
= NULL
;
3294 struct validation_status v_status
;
3296 v_status
.tdb_error
= False
;
3297 v_status
.bad_freelist
= False
;
3298 v_status
.bad_entry
= False
;
3299 v_status
.unknown_key
= False
;
3300 v_status
.success
= True
;
3302 tdb
= tdb_open_log(cache_path
,
3303 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3304 lp_winbind_offline_logon()
3306 : (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
3307 O_RDWR
|O_CREAT
, 0600);
3309 v_status
.tdb_error
= True
;
3310 v_status
.success
= False
;
3316 /* Check the cache freelist is good. */
3317 if (tdb_validate_freelist(tdb
, &num_entries
) == -1) {
3318 DEBUG(0,("winbindd_validate_cache_child: bad freelist in cache %s\n",
3320 v_status
.bad_freelist
= True
;
3321 v_status
.success
= False
;
3325 DEBUG(10,("winbindd_validate_cache_child: cache %s freelist has %d entries\n",
3326 cache_path
, num_entries
));
3328 /* Now traverse the cache to validate it. */
3329 num_entries
= tdb_traverse(tdb
, cache_traverse_validate_fn
, (void *)&v_status
);
3330 if (num_entries
== -1 || !(v_status
.success
)) {
3331 DEBUG(0,("winbindd_validate_cache_child: cache %s traverse failed\n",
3333 if (!(v_status
.success
)) {
3334 if (v_status
.bad_entry
) {
3335 DEBUGADD(0, (" -> bad entry found\n"));
3337 if (v_status
.unknown_key
) {
3338 DEBUGADD(0, (" -> unknown key encountered\n"));
3344 DEBUG(10,("winbindd_validate_cache_child: cache %s is good "
3345 "with %d entries\n", cache_path
, num_entries
));
3346 ret
= 0; /* Cache is good. */
3353 else if (tfd
!= -1) {
3358 DEBUG(10, ("winbindd_validate_cache_child: writing status to pipe\n"));
3359 write (pfd
, (const char *)&v_status
, sizeof(v_status
));
3365 int winbindd_validate_cache(void)
3367 pid_t child_pid
= -1;
3368 int child_status
= 0;
3372 struct validation_status v_status
;
3374 const char *cache_path
= lock_path("winbindd_cache.tdb");
3376 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3377 smb_panic_fn
= validate_panic
;
3379 /* fork and let the child do the validation.
3380 * benefit: no need to twist signal handlers and panic functions.
3381 * just let the child panic. we catch the signal.
3382 * communicate the extended status struct over a pipe. */
3384 if (pipe(pipe_fds
) != 0) {
3385 DEBUG(0, ("winbindd_validate_cache: unable to create pipe, "
3386 "error %s", strerror(errno
)));
3387 smb_panic("winbind_validate_cache: unable to create pipe.");
3390 DEBUG(10, ("winbindd_validate_cache: forking to let child do validation.\n"));
3391 child_pid
= sys_fork();
3392 if (child_pid
== 0) {
3393 DEBUG(10, ("winbindd_validate_cache (validation child): created\n"));
3394 close(pipe_fds
[0]); /* close reading fd */
3395 DEBUG(10, ("winbindd_validate_cache (validation child): "
3396 "calling winbindd_validate_cache_child\n"));
3397 exit(winbindd_validate_cache_child(cache_path
, pipe_fds
[1]));
3399 else if (child_pid
< 0) {
3400 smb_panic("winbindd_validate_cache: fork for validation failed.");
3405 DEBUG(10, ("winbindd_validate_cache: fork succeeded, child PID = %d\n",
3407 close(pipe_fds
[1]); /* close writing fd */
3409 v_status
.success
= True
;
3410 v_status
.bad_entry
= False
;
3411 v_status
.unknown_key
= False
;
3413 DEBUG(10, ("winbindd_validate_cache: reading from pipe.\n"));
3414 bytes_read
= read(pipe_fds
[0], (void *)&v_status
, sizeof(v_status
));
3417 if (bytes_read
!= sizeof(v_status
)) {
3418 DEBUG(10, ("winbindd_validate_cache: read %d bytes from pipe "
3419 "but expected %d", bytes_read
, sizeof(v_status
)));
3420 DEBUGADD(10, (" -> assuming child crashed\n"));
3421 v_status
.success
= False
;
3424 DEBUG(10, ("winbindd_validate_cache: read status from child\n"));
3425 DEBUGADD(10, (" * tdb error: %s\n", v_status
.tdb_error
? "yes" : "no"));
3426 DEBUGADD(10, (" * bad freelist: %s\n", v_status
.bad_freelist
? "yes" : "no"));
3427 DEBUGADD(10, (" * bad entry: %s\n", v_status
.bad_entry
? "yes" : "no"));
3428 DEBUGADD(10, (" * unknown key: %s\n", v_status
.unknown_key
? "yes" : "no"));
3429 DEBUGADD(10, (" => overall success: %s\n", v_status
.success
? "yes" : "no"));
3432 if (!v_status
.success
) {
3433 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
3434 DEBUGADD(10, ("removing tdb %s.\n", cache_path
));
3438 DEBUG(10, ("winbindd_validate_cache: waiting for child to finish...\n"));
3439 while ((wait_pid
= sys_waitpid(child_pid
, &child_status
, 0)) < 0) {
3440 if (errno
== EINTR
) {
3441 DEBUG(10, ("winbindd_validate_cache: got signal during "
3442 "waitpid, retrying\n"));
3446 DEBUG(0, ("winbindd_validate_cache: waitpid failed with "
3447 "errno %s\n", strerror(errno
)));
3448 smb_panic("winbindd_validate_cache: waitpid failed.");
3450 if (wait_pid
!= child_pid
) {
3451 DEBUG(0, ("winbindd_validate_cache: waitpid returned pid %d, "
3452 "but %d was expexted\n", wait_pid
, child_pid
));
3453 smb_panic("winbindd_validate_cache: waitpid returned "
3458 DEBUG(10, ("winbindd_validate_cache: validating child returned.\n"));
3459 if (WIFEXITED(child_status
)) {
3460 DEBUG(10, ("winbindd_validate_cache: child exited, code %d.\n",
3461 WEXITSTATUS(child_status
)));
3462 ret
= WEXITSTATUS(child_status
);
3464 if (WIFSIGNALED(child_status
)) {
3465 DEBUG(10, ("winbindd_validate_cache: child terminated "
3467 WTERMSIG(child_status
),
3468 #if defined(WCOREDUMP)
3469 WCOREDUMP(child_status
)?" (core dumped)":""
3474 ret
= WTERMSIG(child_status
);
3476 if (WIFSTOPPED(child_status
)) {
3477 DEBUG(10, ("winbindd_validate_cache: child was stopped "
3479 WSTOPSIG(child_status
)));
3480 ret
= WSTOPSIG(child_status
);
3483 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
3484 smb_panic_fn
= smb_panic
;
3488 /*********************************************************************
3489 ********************************************************************/
3491 static BOOL
add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
3492 struct winbindd_tdc_domain
**domains
,
3493 size_t *num_domains
)
3495 struct winbindd_tdc_domain
*list
= NULL
;
3498 BOOL set_only
= False
;
3500 /* don't allow duplicates */
3505 for ( i
=0; i
< (*num_domains
); i
++ ) {
3506 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
3507 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
3518 list
= TALLOC_ARRAY( NULL
, struct winbindd_tdc_domain
, 1 );
3521 list
= TALLOC_REALLOC_ARRAY( *domains
, *domains
,
3522 struct winbindd_tdc_domain
,
3527 ZERO_STRUCT( list
[idx
] );
3533 list
[idx
].domain_name
= talloc_strdup( list
, new_dom
->name
);
3534 list
[idx
].dns_name
= talloc_strdup( list
, new_dom
->alt_name
);
3536 if ( !is_null_sid( &new_dom
->sid
) )
3537 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
3539 if ( new_dom
->domain_flags
!= 0x0 )
3540 list
[idx
].trust_flags
= new_dom
->domain_flags
;
3542 if ( new_dom
->domain_type
!= 0x0 )
3543 list
[idx
].trust_type
= new_dom
->domain_type
;
3545 if ( new_dom
->domain_trust_attribs
!= 0x0 )
3546 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
3550 *num_domains
= idx
+ 1;
3556 /*********************************************************************
3557 ********************************************************************/
3559 static TDB_DATA
make_tdc_key( const char *domain_name
)
3561 char *keystr
= NULL
;
3562 TDB_DATA key
= { NULL
, 0 };
3564 if ( !domain_name
) {
3565 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
3570 asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
);
3571 key
.dptr
= (unsigned char*)keystr
;
3572 key
.dsize
= strlen_m(keystr
) + 1;
3577 /*********************************************************************
3578 ********************************************************************/
3580 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
3582 unsigned char **buf
)
3584 unsigned char *buffer
= NULL
;
3589 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
3597 /* Store the number of array items first */
3598 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
3601 /* now pack each domain trust record */
3602 for ( i
=0; i
<num_domains
; i
++ ) {
3605 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
3606 domains
[i
].domain_name
,
3607 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
3610 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
3611 domains
[i
].domain_name
,
3612 domains
[i
].dns_name
,
3613 sid_string_static(&domains
[i
].sid
),
3614 domains
[i
].trust_flags
,
3615 domains
[i
].trust_attribs
,
3616 domains
[i
].trust_type
);
3619 if ( buflen
< len
) {
3620 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
3621 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
3635 /*********************************************************************
3636 ********************************************************************/
3638 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
3639 struct winbindd_tdc_domain
**domains
)
3641 fstring domain_name
, dns_name
, sid_string
;
3642 uint32 type
, attribs
, flags
;
3646 struct winbindd_tdc_domain
*list
= NULL
;
3648 /* get the number of domains */
3649 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
3651 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3655 list
= TALLOC_ARRAY( NULL
, struct winbindd_tdc_domain
, num_domains
);
3657 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
3661 for ( i
=0; i
<num_domains
; i
++ ) {
3662 len
+= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
3671 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3672 TALLOC_FREE( list
);
3676 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
3677 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
3678 domain_name
, dns_name
, sid_string
,
3679 flags
, attribs
, type
));
3681 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
3682 list
[i
].dns_name
= talloc_strdup( list
, dns_name
);
3683 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
3684 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
3687 list
[i
].trust_flags
= flags
;
3688 list
[i
].trust_attribs
= attribs
;
3689 list
[i
].trust_type
= type
;
3697 /*********************************************************************
3698 ********************************************************************/
3700 static BOOL
wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
3702 TDB_DATA key
= make_tdc_key( lp_workgroup() );
3703 TDB_DATA data
= { NULL
, 0 };
3709 /* See if we were asked to delete the cache entry */
3712 ret
= tdb_delete( wcache
->tdb
, key
);
3716 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
3723 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
3726 SAFE_FREE( data
.dptr
);
3727 SAFE_FREE( key
.dptr
);
3729 return ( ret
!= -1 );
3732 /*********************************************************************
3733 ********************************************************************/
3735 BOOL
wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
3737 TDB_DATA key
= make_tdc_key( lp_workgroup() );
3738 TDB_DATA data
= { NULL
, 0 };
3746 data
= tdb_fetch( wcache
->tdb
, key
);
3748 SAFE_FREE( key
.dptr
);
3753 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
3755 SAFE_FREE( data
.dptr
);
3763 /*********************************************************************
3764 ********************************************************************/
3766 BOOL
wcache_tdc_add_domain( struct winbindd_domain
*domain
)
3768 struct winbindd_tdc_domain
*dom_list
= NULL
;
3769 size_t num_domains
= 0;
3772 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
3773 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
3774 domain
->name
, domain
->alt_name
,
3775 sid_string_static(&domain
->sid
),
3776 domain
->domain_flags
,
3777 domain
->domain_trust_attribs
,
3778 domain
->domain_type
));
3780 if ( !init_wcache() ) {
3784 /* fetch the list */
3786 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
3788 /* add the new domain */
3790 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
3794 /* pack the domain */
3796 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
3804 TALLOC_FREE( dom_list
);
3809 /*********************************************************************
3810 ********************************************************************/
3812 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
3814 struct winbindd_tdc_domain
*dom_list
= NULL
;
3815 size_t num_domains
= 0;
3817 struct winbindd_tdc_domain
*d
= NULL
;
3819 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
3821 if ( !init_wcache() ) {
3825 /* fetch the list */
3827 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
3829 for ( i
=0; i
<num_domains
; i
++ ) {
3830 if ( strequal(name
, dom_list
[i
].domain_name
) ||
3831 strequal(name
, dom_list
[i
].dns_name
) )
3833 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
3836 d
= TALLOC_P( ctx
, struct winbindd_tdc_domain
);
3840 d
->domain_name
= talloc_strdup( d
, dom_list
[i
].domain_name
);
3841 d
->dns_name
= talloc_strdup( d
, dom_list
[i
].dns_name
);
3842 sid_copy( &d
->sid
, &dom_list
[i
].sid
);
3843 d
->trust_flags
= dom_list
[i
].trust_flags
;
3844 d
->trust_type
= dom_list
[i
].trust_type
;
3845 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
3851 TALLOC_FREE( dom_list
);
3857 /*********************************************************************
3858 ********************************************************************/
3860 void wcache_tdc_clear( void )
3862 if ( !init_wcache() )
3865 wcache_tdc_store_list( NULL
, 0 );
3871 /*********************************************************************
3872 ********************************************************************/
3874 static void wcache_save_user_pwinfo(struct winbindd_domain
*domain
,
3876 const DOM_SID
*user_sid
,
3877 const char *homedir
,
3882 struct cache_entry
*centry
;
3884 if ( (centry
= centry_start(domain
, status
)) == NULL
)
3887 centry_put_string( centry
, homedir
);
3888 centry_put_string( centry
, shell
);
3889 centry_put_string( centry
, gecos
);
3890 centry_put_uint32( centry
, gid
);
3892 centry_end(centry
, "NSS/PWINFO/%s", sid_string_static(user_sid
) );
3894 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_static(user_sid
) ));
3896 centry_free(centry
);
3899 NTSTATUS
nss_get_info_cached( struct winbindd_domain
*domain
,
3900 const DOM_SID
*user_sid
,
3902 ADS_STRUCT
*ads
, LDAPMessage
*msg
,
3903 char **homedir
, char **shell
, char **gecos
,
3906 struct winbind_cache
*cache
= get_cache(domain
);
3907 struct cache_entry
*centry
= NULL
;
3913 centry
= wcache_fetch(cache
, domain
, "NSS/PWINFO/%s", sid_string_static(user_sid
));
3918 *homedir
= centry_string( centry
, ctx
);
3919 *shell
= centry_string( centry
, ctx
);
3920 *gecos
= centry_string( centry
, ctx
);
3921 *p_gid
= centry_uint32( centry
);
3923 centry_free(centry
);
3925 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
3926 sid_string_static(user_sid
)));
3928 return NT_STATUS_OK
;
3932 nt_status
= nss_get_info( domain
->name
, user_sid
, ctx
, ads
, msg
,
3933 homedir
, shell
, gecos
, p_gid
);
3935 if ( NT_STATUS_IS_OK(nt_status
) ) {
3936 wcache_save_user_pwinfo( domain
, nt_status
, user_sid
,
3937 *homedir
, *shell
, *gecos
, *p_gid
);
3940 if ( NT_STATUS_EQUAL( nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
3941 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
3943 set_domain_offline( domain
);
3950 /* the cache backend methods are exposed via this structure */
3951 struct winbindd_methods cache_methods
= {