2 Unix SMB/CIFS implementation.
4 Winbind cache backend functions
6 Copyright (C) Andrew Tridgell 2001
7 Copyright (C) Gerald Carter 2003-2007
8 Copyright (C) Volker Lendecke 2005
9 Copyright (C) Guenther Deschner 2005
10 Copyright (C) Michael Adam 2007
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
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 /* We have to know what type of domain we are dealing with first. */
138 if ( !domain
->initialized
) {
139 init_dc_connection( domain
);
143 OK. listen up becasue I'm only going to say this once.
144 We have the following scenarios to consider
145 (a) trusted AD domains on a Samba DC,
146 (b) trusted AD domains and we are joined to a non-kerberos domain
147 (c) trusted AD domains and we are joined to a kerberos (AD) domain
149 For (a) we can always contact the trusted domain using krb5
150 since we have the domain trust account password
152 For (b) we can only use RPC since we have no way of
153 getting a krb5 ticket in our own domain
155 For (c) we can always use krb5 since we have a kerberos trust
160 if (!domain
->backend
) {
162 struct winbindd_domain
*our_domain
= domain
;
164 /* find our domain first so we can figure out if we
165 are joined to a kerberized domain */
167 if ( !domain
->primary
)
168 our_domain
= find_our_domain();
170 if ((our_domain
->active_directory
|| IS_DC
)
171 && domain
->active_directory
172 && !lp_winbind_rpc_only()) {
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 enum winbindd_cmd orig_cmd
,
1359 const char *domain_name
,
1362 enum lsa_SidType
*type
)
1364 struct winbind_cache
*cache
= get_cache(domain
);
1365 struct cache_entry
*centry
= NULL
;
1372 fstrcpy(uname
, name
);
1374 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1377 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1378 status
= centry
->status
;
1379 if (NT_STATUS_IS_OK(status
)) {
1380 centry_sid(centry
, mem_ctx
, sid
);
1383 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: %s\n",
1384 domain
->name
, nt_errstr(status
) ));
1386 centry_free(centry
);
1392 /* If the seq number check indicated that there is a problem
1393 * with this DC, then return that status... except for
1394 * access_denied. This is special because the dc may be in
1395 * "restrict anonymous = 1" mode, in which case it will deny
1396 * most unauthenticated operations, but *will* allow the LSA
1397 * name-to-sid that we try as a fallback. */
1399 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1400 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1401 return domain
->last_status
;
1403 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1406 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, orig_cmd
,
1407 domain_name
, name
, sid
, type
);
1410 refresh_sequence_number(domain
, False
);
1412 if (domain
->online
&& !is_null_sid(sid
)) {
1413 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1416 if (NT_STATUS_IS_OK(status
)) {
1417 strupper_m(CONST_DISCARD(char *,domain_name
));
1418 strlower_m(CONST_DISCARD(char *,name
));
1419 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1425 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1427 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1428 TALLOC_CTX
*mem_ctx
,
1432 enum lsa_SidType
*type
)
1434 struct winbind_cache
*cache
= get_cache(domain
);
1435 struct cache_entry
*centry
= NULL
;
1442 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_to_string(sid_string
, sid
));
1445 if (NT_STATUS_IS_OK(centry
->status
)) {
1446 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1447 *domain_name
= centry_string(centry
, mem_ctx
);
1448 *name
= centry_string(centry
, mem_ctx
);
1450 status
= centry
->status
;
1452 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: %s\n",
1453 domain
->name
, nt_errstr(status
) ));
1455 centry_free(centry
);
1460 *domain_name
= NULL
;
1462 /* If the seq number check indicated that there is a problem
1463 * with this DC, then return that status... except for
1464 * access_denied. This is special because the dc may be in
1465 * "restrict anonymous = 1" mode, in which case it will deny
1466 * most unauthenticated operations, but *will* allow the LSA
1467 * sid-to-name that we try as a fallback. */
1469 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1470 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1471 return domain
->last_status
;
1473 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1476 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1479 refresh_sequence_number(domain
, False
);
1480 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
1482 /* We can't save the name to sid mapping here, as with sid history a
1483 * later name2sid would give the wrong sid. */
1488 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
1489 TALLOC_CTX
*mem_ctx
,
1490 const DOM_SID
*domain_sid
,
1495 enum lsa_SidType
**types
)
1497 struct winbind_cache
*cache
= get_cache(domain
);
1499 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1503 *domain_name
= NULL
;
1511 if (num_rids
== 0) {
1512 return NT_STATUS_OK
;
1515 *names
= TALLOC_ARRAY(mem_ctx
, char *, num_rids
);
1516 *types
= TALLOC_ARRAY(mem_ctx
, enum lsa_SidType
, num_rids
);
1518 if ((*names
== NULL
) || (*types
== NULL
)) {
1519 result
= NT_STATUS_NO_MEMORY
;
1523 have_mapped
= have_unmapped
= False
;
1525 for (i
=0; i
<num_rids
; i
++) {
1527 struct cache_entry
*centry
;
1529 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
1530 result
= NT_STATUS_INTERNAL_ERROR
;
1534 centry
= wcache_fetch(cache
, domain
, "SN/%s",
1535 sid_string_static(&sid
));
1540 (*types
)[i
] = SID_NAME_UNKNOWN
;
1541 (*names
)[i
] = talloc_strdup(*names
, "");
1543 if (NT_STATUS_IS_OK(centry
->status
)) {
1546 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
1547 dom
= centry_string(centry
, mem_ctx
);
1548 if (*domain_name
== NULL
) {
1553 (*names
)[i
] = centry_string(centry
, *names
);
1555 have_unmapped
= True
;
1558 centry_free(centry
);
1562 return NT_STATUS_NONE_MAPPED
;
1564 if (!have_unmapped
) {
1565 return NT_STATUS_OK
;
1567 return STATUS_SOME_UNMAPPED
;
1571 TALLOC_FREE(*names
);
1572 TALLOC_FREE(*types
);
1574 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
1575 rids
, num_rids
, domain_name
,
1578 if (!NT_STATUS_IS_OK(result
) &&
1579 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
1583 refresh_sequence_number(domain
, False
);
1585 for (i
=0; i
<num_rids
; i
++) {
1589 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
1590 result
= NT_STATUS_INTERNAL_ERROR
;
1594 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
1595 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
1597 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
1598 (*names
)[i
], (*types
)[i
]);
1605 TALLOC_FREE(*names
);
1606 TALLOC_FREE(*types
);
1610 /* Lookup user information from a rid */
1611 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
1612 TALLOC_CTX
*mem_ctx
,
1613 const DOM_SID
*user_sid
,
1614 WINBIND_USERINFO
*info
)
1616 struct winbind_cache
*cache
= get_cache(domain
);
1617 struct cache_entry
*centry
= NULL
;
1623 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string_static(user_sid
));
1625 /* If we have an access denied cache entry and a cached info3 in the
1626 samlogon cache then do a query. This will force the rpc back end
1627 to return the info3 data. */
1629 if (NT_STATUS_V(domain
->last_status
) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED
) &&
1630 netsamlogon_cache_have(user_sid
)) {
1631 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1632 domain
->last_status
= NT_STATUS_OK
;
1633 centry_free(centry
);
1640 info
->acct_name
= centry_string(centry
, mem_ctx
);
1641 info
->full_name
= centry_string(centry
, mem_ctx
);
1642 info
->homedir
= centry_string(centry
, mem_ctx
);
1643 info
->shell
= centry_string(centry
, mem_ctx
);
1644 info
->primary_gid
= centry_uint32(centry
);
1645 centry_sid(centry
, mem_ctx
, &info
->user_sid
);
1646 centry_sid(centry
, mem_ctx
, &info
->group_sid
);
1647 status
= centry
->status
;
1649 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: %s\n",
1650 domain
->name
, nt_errstr(status
) ));
1652 centry_free(centry
);
1658 /* Return status value returned by seq number check */
1660 if (!NT_STATUS_IS_OK(domain
->last_status
))
1661 return domain
->last_status
;
1663 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
1666 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
1669 refresh_sequence_number(domain
, False
);
1670 wcache_save_user(domain
, status
, info
);
1676 /* Lookup groups a user is a member of. */
1677 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
1678 TALLOC_CTX
*mem_ctx
,
1679 const DOM_SID
*user_sid
,
1680 uint32
*num_groups
, DOM_SID
**user_gids
)
1682 struct winbind_cache
*cache
= get_cache(domain
);
1683 struct cache_entry
*centry
= NULL
;
1691 centry
= wcache_fetch(cache
, domain
, "UG/%s", sid_to_string(sid_string
, user_sid
));
1693 /* If we have an access denied cache entry and a cached info3 in the
1694 samlogon cache then do a query. This will force the rpc back end
1695 to return the info3 data. */
1697 if (NT_STATUS_V(domain
->last_status
) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED
) &&
1698 netsamlogon_cache_have(user_sid
)) {
1699 DEBUG(10, ("lookup_usergroups: cached access denied and have cached info3\n"));
1700 domain
->last_status
= NT_STATUS_OK
;
1701 centry_free(centry
);
1708 *num_groups
= centry_uint32(centry
);
1710 if (*num_groups
== 0)
1713 (*user_gids
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_groups
);
1714 if (! (*user_gids
)) {
1715 smb_panic_fn("lookup_usergroups out of memory");
1717 for (i
=0; i
<(*num_groups
); i
++) {
1718 centry_sid(centry
, mem_ctx
, &(*user_gids
)[i
]);
1722 status
= centry
->status
;
1724 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status: %s\n",
1725 domain
->name
, nt_errstr(status
) ));
1727 centry_free(centry
);
1732 (*user_gids
) = NULL
;
1734 /* Return status value returned by seq number check */
1736 if (!NT_STATUS_IS_OK(domain
->last_status
))
1737 return domain
->last_status
;
1739 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
1742 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
1744 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
1748 refresh_sequence_number(domain
, False
);
1749 centry
= centry_start(domain
, status
);
1752 centry_put_uint32(centry
, *num_groups
);
1753 for (i
=0; i
<(*num_groups
); i
++) {
1754 centry_put_sid(centry
, &(*user_gids
)[i
]);
1756 centry_end(centry
, "UG/%s", sid_to_string(sid_string
, user_sid
));
1757 centry_free(centry
);
1763 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
1764 TALLOC_CTX
*mem_ctx
,
1765 uint32 num_sids
, const DOM_SID
*sids
,
1766 uint32
*num_aliases
, uint32
**alias_rids
)
1768 struct winbind_cache
*cache
= get_cache(domain
);
1769 struct cache_entry
*centry
= NULL
;
1771 char *sidlist
= talloc_strdup(mem_ctx
, "");
1777 if (num_sids
== 0) {
1780 return NT_STATUS_OK
;
1783 /* We need to cache indexed by the whole list of SIDs, the aliases
1784 * resulting might come from any of the SIDs. */
1786 for (i
=0; i
<num_sids
; i
++) {
1787 sidlist
= talloc_asprintf(mem_ctx
, "%s/%s", sidlist
,
1788 sid_string_static(&sids
[i
]));
1789 if (sidlist
== NULL
)
1790 return NT_STATUS_NO_MEMORY
;
1793 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
1798 *num_aliases
= centry_uint32(centry
);
1802 (*alias_rids
) = TALLOC_ARRAY(mem_ctx
, uint32
, *num_aliases
);
1804 if ((*alias_rids
) == NULL
) {
1805 centry_free(centry
);
1806 return NT_STATUS_NO_MEMORY
;
1809 (*alias_rids
) = NULL
;
1812 for (i
=0; i
<(*num_aliases
); i
++)
1813 (*alias_rids
)[i
] = centry_uint32(centry
);
1815 status
= centry
->status
;
1817 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
1818 "status %s\n", domain
->name
, nt_errstr(status
)));
1820 centry_free(centry
);
1825 (*alias_rids
) = NULL
;
1827 if (!NT_STATUS_IS_OK(domain
->last_status
))
1828 return domain
->last_status
;
1830 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
1831 "for domain %s\n", domain
->name
));
1833 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
1835 num_aliases
, alias_rids
);
1838 refresh_sequence_number(domain
, False
);
1839 centry
= centry_start(domain
, status
);
1842 centry_put_uint32(centry
, *num_aliases
);
1843 for (i
=0; i
<(*num_aliases
); i
++)
1844 centry_put_uint32(centry
, (*alias_rids
)[i
]);
1845 centry_end(centry
, "UA%s", sidlist
);
1846 centry_free(centry
);
1853 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
1854 TALLOC_CTX
*mem_ctx
,
1855 const DOM_SID
*group_sid
, uint32
*num_names
,
1856 DOM_SID
**sid_mem
, char ***names
,
1857 uint32
**name_types
)
1859 struct winbind_cache
*cache
= get_cache(domain
);
1860 struct cache_entry
*centry
= NULL
;
1868 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_to_string(sid_string
, group_sid
));
1872 *num_names
= centry_uint32(centry
);
1874 if (*num_names
== 0)
1877 (*sid_mem
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_names
);
1878 (*names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_names
);
1879 (*name_types
) = TALLOC_ARRAY(mem_ctx
, uint32
, *num_names
);
1881 if (! (*sid_mem
) || ! (*names
) || ! (*name_types
)) {
1882 smb_panic_fn("lookup_groupmem out of memory");
1885 for (i
=0; i
<(*num_names
); i
++) {
1886 centry_sid(centry
, mem_ctx
, &(*sid_mem
)[i
]);
1887 (*names
)[i
] = centry_string(centry
, mem_ctx
);
1888 (*name_types
)[i
] = centry_uint32(centry
);
1892 status
= centry
->status
;
1894 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status: %s\n",
1895 domain
->name
, nt_errstr(status
)));
1897 centry_free(centry
);
1904 (*name_types
) = NULL
;
1906 /* Return status value returned by seq number check */
1908 if (!NT_STATUS_IS_OK(domain
->last_status
))
1909 return domain
->last_status
;
1911 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
1914 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
1915 sid_mem
, names
, name_types
);
1918 refresh_sequence_number(domain
, False
);
1919 centry
= centry_start(domain
, status
);
1922 centry_put_uint32(centry
, *num_names
);
1923 for (i
=0; i
<(*num_names
); i
++) {
1924 centry_put_sid(centry
, &(*sid_mem
)[i
]);
1925 centry_put_string(centry
, (*names
)[i
]);
1926 centry_put_uint32(centry
, (*name_types
)[i
]);
1928 centry_end(centry
, "GM/%s", sid_to_string(sid_string
, group_sid
));
1929 centry_free(centry
);
1935 /* find the sequence number for a domain */
1936 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
1938 refresh_sequence_number(domain
, False
);
1940 *seq
= domain
->sequence_number
;
1942 return NT_STATUS_OK
;
1945 /* enumerate trusted domains
1946 * (we need to have the list of trustdoms in the cache when we go offline) -
1948 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
1949 TALLOC_CTX
*mem_ctx
,
1950 uint32
*num_domains
,
1955 struct winbind_cache
*cache
= get_cache(domain
);
1956 struct cache_entry
*centry
= NULL
;
1963 centry
= wcache_fetch(cache
, domain
, "TRUSTDOMS/%s", domain
->name
);
1969 *num_domains
= centry_uint32(centry
);
1972 (*names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
1973 (*alt_names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
1974 (*dom_sids
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_domains
);
1976 if (! (*dom_sids
) || ! (*names
) || ! (*alt_names
)) {
1977 smb_panic_fn("trusted_domains out of memory");
1981 (*alt_names
) = NULL
;
1985 for (i
=0; i
<(*num_domains
); i
++) {
1986 (*names
)[i
] = centry_string(centry
, mem_ctx
);
1987 (*alt_names
)[i
] = centry_string(centry
, mem_ctx
);
1988 centry_sid(centry
, mem_ctx
, &(*dom_sids
)[i
]);
1991 status
= centry
->status
;
1993 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
1994 domain
->name
, *num_domains
, nt_errstr(status
) ));
1996 centry_free(centry
);
2003 (*alt_names
) = NULL
;
2005 /* Return status value returned by seq number check */
2007 if (!NT_STATUS_IS_OK(domain
->last_status
))
2008 return domain
->last_status
;
2010 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2013 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, num_domains
,
2014 names
, alt_names
, dom_sids
);
2016 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2017 * so that the generic centry handling still applies correctly -
2020 if (!NT_STATUS_IS_ERR(status
)) {
2021 status
= NT_STATUS_OK
;
2025 #if 0 /* Disabled as we want the trust dom list to be managed by
2026 the main parent and always to make the query. --jerry */
2029 refresh_sequence_number(domain
, False
);
2031 centry
= centry_start(domain
, status
);
2035 centry_put_uint32(centry
, *num_domains
);
2037 for (i
=0; i
<(*num_domains
); i
++) {
2038 centry_put_string(centry
, (*names
)[i
]);
2039 centry_put_string(centry
, (*alt_names
)[i
]);
2040 centry_put_sid(centry
, &(*dom_sids
)[i
]);
2043 centry_end(centry
, "TRUSTDOMS/%s", domain
->name
);
2045 centry_free(centry
);
2053 /* get lockout policy */
2054 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
2055 TALLOC_CTX
*mem_ctx
,
2056 SAM_UNK_INFO_12
*policy
){
2057 struct winbind_cache
*cache
= get_cache(domain
);
2058 struct cache_entry
*centry
= NULL
;
2064 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2069 policy
->duration
= centry_nttime(centry
);
2070 policy
->reset_count
= centry_nttime(centry
);
2071 policy
->bad_attempt_lockout
= centry_uint16(centry
);
2073 status
= centry
->status
;
2075 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2076 domain
->name
, nt_errstr(status
) ));
2078 centry_free(centry
);
2082 ZERO_STRUCTP(policy
);
2084 /* Return status value returned by seq number check */
2086 if (!NT_STATUS_IS_OK(domain
->last_status
))
2087 return domain
->last_status
;
2089 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2092 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2095 refresh_sequence_number(domain
, False
);
2096 wcache_save_lockout_policy(domain
, status
, policy
);
2101 /* get password policy */
2102 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
2103 TALLOC_CTX
*mem_ctx
,
2104 SAM_UNK_INFO_1
*policy
)
2106 struct winbind_cache
*cache
= get_cache(domain
);
2107 struct cache_entry
*centry
= NULL
;
2113 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2118 policy
->min_length_password
= centry_uint16(centry
);
2119 policy
->password_history
= centry_uint16(centry
);
2120 policy
->password_properties
= centry_uint32(centry
);
2121 policy
->expire
= centry_nttime(centry
);
2122 policy
->min_passwordage
= centry_nttime(centry
);
2124 status
= centry
->status
;
2126 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2127 domain
->name
, nt_errstr(status
) ));
2129 centry_free(centry
);
2133 ZERO_STRUCTP(policy
);
2135 /* Return status value returned by seq number check */
2137 if (!NT_STATUS_IS_OK(domain
->last_status
))
2138 return domain
->last_status
;
2140 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2143 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
2146 refresh_sequence_number(domain
, False
);
2147 wcache_save_password_policy(domain
, status
, policy
);
2153 /* Invalidate cached user and group lists coherently */
2155 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2158 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
2159 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
2160 tdb_delete(the_tdb
, kbuf
);
2165 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2167 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
2168 NET_USER_INFO_3
*info3
)
2170 struct winbind_cache
*cache
;
2172 /* dont clear cached U/SID and UG/SID entries when we want to logon
2175 if (lp_winbind_offline_logon()) {
2182 cache
= get_cache(domain
);
2183 netsamlogon_clear_cached_user(cache
->tdb
, info3
);
2186 void wcache_invalidate_cache(void)
2188 struct winbindd_domain
*domain
;
2190 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
2191 struct winbind_cache
*cache
= get_cache(domain
);
2193 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2194 "entries for %s\n", domain
->name
));
2196 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
2200 BOOL
init_wcache(void)
2202 if (wcache
== NULL
) {
2203 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
2204 ZERO_STRUCTP(wcache
);
2207 if (wcache
->tdb
!= NULL
)
2210 /* when working offline we must not clear the cache on restart */
2211 wcache
->tdb
= tdb_open_log(lock_path("winbindd_cache.tdb"),
2212 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
2213 lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
2214 O_RDWR
|O_CREAT
, 0600);
2216 if (wcache
->tdb
== NULL
) {
2217 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2224 /************************************************************************
2225 This is called by the parent to initialize the cache file.
2226 We don't need sophisticated locking here as we know we're the
2228 ************************************************************************/
2230 BOOL
initialize_winbindd_cache(void)
2232 BOOL cache_bad
= True
;
2235 if (!init_wcache()) {
2236 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
2240 /* Check version number. */
2241 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
2242 vers
== WINBINDD_CACHE_VERSION
) {
2247 DEBUG(0,("initialize_winbindd_cache: clearing cache "
2248 "and re-creating with version number %d\n",
2249 WINBINDD_CACHE_VERSION
));
2251 tdb_close(wcache
->tdb
);
2254 if (unlink(lock_path("winbindd_cache.tdb")) == -1) {
2255 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
2256 lock_path("winbindd_cache.tdb"),
2260 if (!init_wcache()) {
2261 DEBUG(0,("initialize_winbindd_cache: re-initialization "
2262 "init_wcache failed.\n"));
2266 /* Write the version. */
2267 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
2268 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
2269 tdb_errorstr(wcache
->tdb
) ));
2274 tdb_close(wcache
->tdb
);
2279 void cache_store_response(pid_t pid
, struct winbindd_response
*response
)
2286 DEBUG(10, ("Storing response for pid %d, len %d\n",
2287 pid
, response
->length
));
2289 fstr_sprintf(key_str
, "DR/%d", pid
);
2290 if (tdb_store(wcache
->tdb
, string_tdb_data(key_str
),
2291 make_tdb_data((uint8
*)response
, sizeof(*response
)),
2295 if (response
->length
== sizeof(*response
))
2298 /* There's extra data */
2300 DEBUG(10, ("Storing extra data: len=%d\n",
2301 (int)(response
->length
- sizeof(*response
))));
2303 fstr_sprintf(key_str
, "DE/%d", pid
);
2304 if (tdb_store(wcache
->tdb
, string_tdb_data(key_str
),
2305 make_tdb_data((uint8
*)response
->extra_data
.data
,
2306 response
->length
- sizeof(*response
)),
2310 /* We could not store the extra data, make sure the tdb does not
2311 * contain a main record with wrong dangling extra data */
2313 fstr_sprintf(key_str
, "DR/%d", pid
);
2314 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2319 BOOL
cache_retrieve_response(pid_t pid
, struct winbindd_response
* response
)
2327 DEBUG(10, ("Retrieving response for pid %d\n", pid
));
2329 fstr_sprintf(key_str
, "DR/%d", pid
);
2330 data
= tdb_fetch(wcache
->tdb
, string_tdb_data(key_str
));
2332 if (data
.dptr
== NULL
)
2335 if (data
.dsize
!= sizeof(*response
))
2338 memcpy(response
, data
.dptr
, data
.dsize
);
2339 SAFE_FREE(data
.dptr
);
2341 if (response
->length
== sizeof(*response
)) {
2342 response
->extra_data
.data
= NULL
;
2346 /* There's extra data */
2348 DEBUG(10, ("Retrieving extra data length=%d\n",
2349 (int)(response
->length
- sizeof(*response
))));
2351 fstr_sprintf(key_str
, "DE/%d", pid
);
2352 data
= tdb_fetch(wcache
->tdb
, string_tdb_data(key_str
));
2354 if (data
.dptr
== NULL
) {
2355 DEBUG(0, ("Did not find extra data\n"));
2359 if (data
.dsize
!= (response
->length
- sizeof(*response
))) {
2360 DEBUG(0, ("Invalid extra data length: %d\n", (int)data
.dsize
));
2361 SAFE_FREE(data
.dptr
);
2365 dump_data(11, (uint8
*)data
.dptr
, data
.dsize
);
2367 response
->extra_data
.data
= data
.dptr
;
2371 void cache_cleanup_response(pid_t pid
)
2378 fstr_sprintf(key_str
, "DR/%d", pid
);
2379 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2381 fstr_sprintf(key_str
, "DE/%d", pid
);
2382 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2388 BOOL
lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const DOM_SID
*sid
,
2389 char **domain_name
, char **name
,
2390 enum lsa_SidType
*type
)
2392 struct winbindd_domain
*domain
;
2393 struct winbind_cache
*cache
;
2394 struct cache_entry
*centry
= NULL
;
2397 domain
= find_lookup_domain_from_sid(sid
);
2398 if (domain
== NULL
) {
2402 cache
= get_cache(domain
);
2404 if (cache
->tdb
== NULL
) {
2408 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_string_static(sid
));
2409 if (centry
== NULL
) {
2413 if (NT_STATUS_IS_OK(centry
->status
)) {
2414 *type
= (enum lsa_SidType
)centry_uint32(centry
);
2415 *domain_name
= centry_string(centry
, mem_ctx
);
2416 *name
= centry_string(centry
, mem_ctx
);
2419 status
= centry
->status
;
2420 centry_free(centry
);
2421 return NT_STATUS_IS_OK(status
);
2424 BOOL
lookup_cached_name(TALLOC_CTX
*mem_ctx
,
2425 const char *domain_name
,
2428 enum lsa_SidType
*type
)
2430 struct winbindd_domain
*domain
;
2431 struct winbind_cache
*cache
;
2432 struct cache_entry
*centry
= NULL
;
2435 BOOL original_online_state
;
2437 domain
= find_lookup_domain_from_name(domain_name
);
2438 if (domain
== NULL
) {
2442 cache
= get_cache(domain
);
2444 if (cache
->tdb
== NULL
) {
2448 fstrcpy(uname
, name
);
2451 /* If we are doing a cached logon, temporarily set the domain
2452 offline so the cache won't expire the entry */
2454 original_online_state
= domain
->online
;
2455 domain
->online
= False
;
2456 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
2457 domain
->online
= original_online_state
;
2459 if (centry
== NULL
) {
2463 if (NT_STATUS_IS_OK(centry
->status
)) {
2464 *type
= (enum lsa_SidType
)centry_uint32(centry
);
2465 centry_sid(centry
, mem_ctx
, sid
);
2468 status
= centry
->status
;
2469 centry_free(centry
);
2471 return NT_STATUS_IS_OK(status
);
2474 void cache_name2sid(struct winbindd_domain
*domain
,
2475 const char *domain_name
, const char *name
,
2476 enum lsa_SidType type
, const DOM_SID
*sid
)
2478 refresh_sequence_number(domain
, False
);
2479 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
2484 * The original idea that this cache only contains centries has
2485 * been blurred - now other stuff gets put in here. Ensure we
2486 * ignore these things on cleanup.
2489 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
2490 TDB_DATA dbuf
, void *state
)
2492 struct cache_entry
*centry
;
2494 if (is_non_centry_key(kbuf
)) {
2498 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
2503 if (!NT_STATUS_IS_OK(centry
->status
)) {
2504 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
2505 tdb_delete(the_tdb
, kbuf
);
2508 centry_free(centry
);
2512 /* flush the cache */
2513 void wcache_flush_cache(void)
2518 tdb_close(wcache
->tdb
);
2524 /* when working offline we must not clear the cache on restart */
2525 wcache
->tdb
= tdb_open_log(lock_path("winbindd_cache.tdb"),
2526 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
2527 lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
2528 O_RDWR
|O_CREAT
, 0600);
2531 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2535 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
2537 DEBUG(10,("wcache_flush_cache success\n"));
2540 /* Count cached creds */
2542 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2545 int *cred_count
= (int*)state
;
2547 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
2553 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
2555 struct winbind_cache
*cache
= get_cache(domain
);
2560 return NT_STATUS_INTERNAL_DB_ERROR
;
2563 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
2565 return NT_STATUS_OK
;
2569 struct cred_list
*prev
, *next
;
2574 static struct cred_list
*wcache_cred_list
;
2576 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2579 struct cred_list
*cred
;
2581 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
2583 cred
= SMB_MALLOC_P(struct cred_list
);
2585 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2591 /* save a copy of the key */
2593 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
2594 DLIST_ADD(wcache_cred_list
, cred
);
2600 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const DOM_SID
*sid
)
2602 struct winbind_cache
*cache
= get_cache(domain
);
2605 struct cred_list
*cred
, *oldest
= NULL
;
2608 return NT_STATUS_INTERNAL_DB_ERROR
;
2611 /* we possibly already have an entry */
2612 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
2616 DEBUG(11,("we already have an entry, deleting that\n"));
2618 fstr_sprintf(key_str
, "CRED/%s", sid_string_static(sid
));
2620 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
2622 return NT_STATUS_OK
;
2625 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
2627 return NT_STATUS_OK
;
2628 } else if ((ret
== -1) || (wcache_cred_list
== NULL
)) {
2629 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2632 ZERO_STRUCTP(oldest
);
2634 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
2639 data
= tdb_fetch(cache
->tdb
, string_tdb_data(cred
->name
));
2641 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
2643 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2647 t
= IVAL(data
.dptr
, 0);
2648 SAFE_FREE(data
.dptr
);
2651 oldest
= SMB_MALLOC_P(struct cred_list
);
2652 if (oldest
== NULL
) {
2653 status
= NT_STATUS_NO_MEMORY
;
2657 fstrcpy(oldest
->name
, cred
->name
);
2658 oldest
->created
= t
;
2662 if (t
< oldest
->created
) {
2663 fstrcpy(oldest
->name
, cred
->name
);
2664 oldest
->created
= t
;
2668 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
2669 status
= NT_STATUS_OK
;
2671 status
= NT_STATUS_UNSUCCESSFUL
;
2674 SAFE_FREE(wcache_cred_list
);
2680 /* Change the global online/offline state. */
2681 BOOL
set_global_winbindd_state_offline(void)
2685 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
2687 /* Only go offline if someone has created
2688 the key "WINBINDD_OFFLINE" in the cache tdb. */
2690 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
2691 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
2695 if (!lp_winbind_offline_logon()) {
2696 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
2700 if (global_winbindd_offline_state
) {
2701 /* Already offline. */
2705 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
2707 if (!data
.dptr
|| data
.dsize
!= 4) {
2708 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
2709 SAFE_FREE(data
.dptr
);
2712 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
2713 global_winbindd_offline_state
= True
;
2714 SAFE_FREE(data
.dptr
);
2719 void set_global_winbindd_state_online(void)
2721 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
2723 if (!lp_winbind_offline_logon()) {
2724 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
2728 if (!global_winbindd_offline_state
) {
2729 /* Already online. */
2732 global_winbindd_offline_state
= False
;
2738 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
2739 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
2742 BOOL
get_global_winbindd_state_offline(void)
2744 return global_winbindd_offline_state
;
2747 /***********************************************************************
2748 Validate functions for all possible cache tdb keys.
2749 ***********************************************************************/
2751 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
2752 struct tdb_validation_status
*state
)
2754 struct cache_entry
*centry
;
2756 centry
= SMB_XMALLOC_P(struct cache_entry
);
2757 centry
->data
= (unsigned char *)memdup(data
.dptr
, data
.dsize
);
2758 if (!centry
->data
) {
2762 centry
->len
= data
.dsize
;
2765 if (centry
->len
< 8) {
2766 /* huh? corrupt cache? */
2767 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr
));
2768 centry_free(centry
);
2769 state
->bad_entry
= True
;
2770 state
->success
= False
;
2774 centry
->status
= NT_STATUS(centry_uint32(centry
));
2775 centry
->sequence_number
= centry_uint32(centry
);
2779 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2780 struct tdb_validation_status
*state
)
2782 if (dbuf
.dsize
!= 8) {
2783 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
2784 keystr
, (unsigned int)dbuf
.dsize
));
2785 state
->bad_entry
= True
;
2791 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2792 struct tdb_validation_status
*state
)
2794 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
2799 (void)centry_uint32(centry
);
2800 if (NT_STATUS_IS_OK(centry
->status
)) {
2802 (void)centry_sid(centry
, mem_ctx
, &sid
);
2805 centry_free(centry
);
2807 if (!(state
->success
)) {
2810 DEBUG(10,("validate_ns: %s ok\n", keystr
));
2814 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2815 struct tdb_validation_status
*state
)
2817 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
2822 if (NT_STATUS_IS_OK(centry
->status
)) {
2823 (void)centry_uint32(centry
);
2824 (void)centry_string(centry
, mem_ctx
);
2825 (void)centry_string(centry
, mem_ctx
);
2828 centry_free(centry
);
2830 if (!(state
->success
)) {
2833 DEBUG(10,("validate_sn: %s ok\n", keystr
));
2837 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2838 struct tdb_validation_status
*state
)
2840 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
2847 (void)centry_string(centry
, mem_ctx
);
2848 (void)centry_string(centry
, mem_ctx
);
2849 (void)centry_string(centry
, mem_ctx
);
2850 (void)centry_string(centry
, mem_ctx
);
2851 (void)centry_uint32(centry
);
2852 (void)centry_sid(centry
, mem_ctx
, &sid
);
2853 (void)centry_sid(centry
, mem_ctx
, &sid
);
2855 centry_free(centry
);
2857 if (!(state
->success
)) {
2860 DEBUG(10,("validate_u: %s ok\n", keystr
));
2864 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2865 struct tdb_validation_status
*state
)
2867 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
2873 (void)centry_nttime(centry
);
2874 (void)centry_nttime(centry
);
2875 (void)centry_uint16(centry
);
2877 centry_free(centry
);
2879 if (!(state
->success
)) {
2882 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
2886 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2887 struct tdb_validation_status
*state
)
2889 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
2895 (void)centry_uint16(centry
);
2896 (void)centry_uint16(centry
);
2897 (void)centry_uint32(centry
);
2898 (void)centry_nttime(centry
);
2899 (void)centry_nttime(centry
);
2901 centry_free(centry
);
2903 if (!(state
->success
)) {
2906 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
2910 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2911 struct tdb_validation_status
*state
)
2913 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
2919 (void)centry_time(centry
);
2920 (void)centry_hash16(centry
, mem_ctx
);
2922 /* We only have 17 bytes more data in the salted cred case. */
2923 if (centry
->len
- centry
->ofs
== 17) {
2924 (void)centry_hash16(centry
, mem_ctx
);
2927 centry_free(centry
);
2929 if (!(state
->success
)) {
2932 DEBUG(10,("validate_cred: %s ok\n", keystr
));
2936 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2937 struct tdb_validation_status
*state
)
2939 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
2940 int32 num_entries
, i
;
2946 num_entries
= (int32
)centry_uint32(centry
);
2948 for (i
=0; i
< num_entries
; i
++) {
2950 (void)centry_string(centry
, mem_ctx
);
2951 (void)centry_string(centry
, mem_ctx
);
2952 (void)centry_string(centry
, mem_ctx
);
2953 (void)centry_string(centry
, mem_ctx
);
2954 (void)centry_sid(centry
, mem_ctx
, &sid
);
2955 (void)centry_sid(centry
, mem_ctx
, &sid
);
2958 centry_free(centry
);
2960 if (!(state
->success
)) {
2963 DEBUG(10,("validate_ul: %s ok\n", keystr
));
2967 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2968 struct tdb_validation_status
*state
)
2970 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
2971 int32 num_entries
, i
;
2977 num_entries
= centry_uint32(centry
);
2979 for (i
=0; i
< num_entries
; i
++) {
2980 (void)centry_string(centry
, mem_ctx
);
2981 (void)centry_string(centry
, mem_ctx
);
2982 (void)centry_uint32(centry
);
2985 centry_free(centry
);
2987 if (!(state
->success
)) {
2990 DEBUG(10,("validate_gl: %s ok\n", keystr
));
2994 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2995 struct tdb_validation_status
*state
)
2997 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
2998 int32 num_groups
, i
;
3004 num_groups
= centry_uint32(centry
);
3006 for (i
=0; i
< num_groups
; i
++) {
3008 centry_sid(centry
, mem_ctx
, &sid
);
3011 centry_free(centry
);
3013 if (!(state
->success
)) {
3016 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3020 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3021 struct tdb_validation_status
*state
)
3023 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3024 int32 num_aliases
, i
;
3030 num_aliases
= centry_uint32(centry
);
3032 for (i
=0; i
< num_aliases
; i
++) {
3033 (void)centry_uint32(centry
);
3036 centry_free(centry
);
3038 if (!(state
->success
)) {
3041 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3045 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3046 struct tdb_validation_status
*state
)
3048 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3055 num_names
= centry_uint32(centry
);
3057 for (i
=0; i
< num_names
; i
++) {
3059 centry_sid(centry
, mem_ctx
, &sid
);
3060 (void)centry_string(centry
, mem_ctx
);
3061 (void)centry_uint32(centry
);
3064 centry_free(centry
);
3066 if (!(state
->success
)) {
3069 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3073 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3074 struct tdb_validation_status
*state
)
3076 /* Can't say anything about this other than must be nonzero. */
3077 if (dbuf
.dsize
== 0) {
3078 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3080 state
->bad_entry
= True
;
3081 state
->success
= False
;
3085 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3089 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3090 struct tdb_validation_status
*state
)
3092 /* Can't say anything about this other than must be nonzero. */
3093 if (dbuf
.dsize
== 0) {
3094 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3096 state
->bad_entry
= True
;
3097 state
->success
= False
;
3101 DEBUG(10,("validate_de: %s ok\n", keystr
));
3105 static int validate_trustdoms(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3106 struct tdb_validation_status
*state
)
3108 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3109 int32 num_domains
, i
;
3115 num_domains
= centry_uint32(centry
);
3117 for (i
=0; i
< num_domains
; i
++) {
3119 (void)centry_string(centry
, mem_ctx
);
3120 (void)centry_string(centry
, mem_ctx
);
3121 (void)centry_sid(centry
, mem_ctx
, &sid
);
3124 centry_free(centry
);
3126 if (!(state
->success
)) {
3129 DEBUG(10,("validate_trustdoms: %s ok\n", keystr
));
3133 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3135 struct tdb_validation_status
*state
)
3137 if (dbuf
.dsize
== 0) {
3138 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3139 "key %s (len ==0) ?\n", keystr
));
3140 state
->bad_entry
= True
;
3141 state
->success
= False
;
3145 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3146 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3150 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3151 struct tdb_validation_status
*state
)
3153 if (dbuf
.dsize
!= 4) {
3154 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3155 keystr
, (unsigned int)dbuf
.dsize
));
3156 state
->bad_entry
= True
;
3157 state
->success
= False
;
3160 DEBUG(10,("validate_offline: %s ok\n", keystr
));
3164 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3165 struct tdb_validation_status
*state
)
3167 if (dbuf
.dsize
!= 4) {
3168 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3169 "key %s (len %u != 4) ?\n",
3170 keystr
, (unsigned int)dbuf
.dsize
));
3171 state
->bad_entry
= True
;
3172 state
->success
= False
;
3176 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
3180 /***********************************************************************
3181 A list of all possible cache tdb keys with associated validation
3183 ***********************************************************************/
3185 struct key_val_struct
{
3186 const char *keyname
;
3187 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
3189 {"SEQNUM/", validate_seqnum
},
3190 {"NS/", validate_ns
},
3191 {"SN/", validate_sn
},
3193 {"LOC_POL/", validate_loc_pol
},
3194 {"PWD_POL/", validate_pwd_pol
},
3195 {"CRED/", validate_cred
},
3196 {"UL/", validate_ul
},
3197 {"GL/", validate_gl
},
3198 {"UG/", validate_ug
},
3199 {"UA", validate_ua
},
3200 {"GM/", validate_gm
},
3201 {"DR/", validate_dr
},
3202 {"DE/", validate_de
},
3203 {"TRUSTDOMS/", validate_trustdoms
},
3204 {"TRUSTDOMCACHE/", validate_trustdomcache
},
3205 {"WINBINDD_OFFLINE", validate_offline
},
3206 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
3210 /***********************************************************************
3211 Function to look at every entry in the tdb and validate it as far as
3213 ***********************************************************************/
3215 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
3218 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
3220 /* Paranoia check. */
3221 if (kbuf
.dsize
> 1024) {
3222 DEBUG(0,("cache_traverse_validate_fn: key length too large (%u) > 1024\n\n",
3223 (unsigned int)kbuf
.dsize
));
3227 for (i
= 0; key_val
[i
].keyname
; i
++) {
3228 size_t namelen
= strlen(key_val
[i
].keyname
);
3229 if (kbuf
.dsize
>= namelen
&& (
3230 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
3231 TALLOC_CTX
*mem_ctx
;
3235 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
3239 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
3240 keystr
[kbuf
.dsize
] = '\0';
3242 mem_ctx
= talloc_init("validate_ctx");
3248 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
3252 talloc_destroy(mem_ctx
);
3257 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
3258 dump_data(0, (uint8
*)kbuf
.dptr
, kbuf
.dsize
);
3259 DEBUG(0,("data :\n"));
3260 dump_data(0, (uint8
*)dbuf
.dptr
, dbuf
.dsize
);
3261 v_state
->unknown_key
= True
;
3262 v_state
->success
= False
;
3263 return 1; /* terminate. */
3266 static void validate_panic(const char *const why
)
3268 DEBUG(0,("validating cache: would panic %s\n", why
));
3269 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
3273 /***********************************************************************
3274 Try and validate every entry in the winbindd cache. If we fail here,
3275 delete the cache tdb and return non-zero - the caller (main winbindd
3276 function) will restart us as we don't know if we crashed or not.
3277 ***********************************************************************/
3279 int winbindd_validate_cache(void)
3282 const char *tdb_path
= lock_path("winbindd_cache.tdb");
3283 TDB_CONTEXT
*tdb
= NULL
;
3285 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3286 smb_panic_fn
= validate_panic
;
3289 tdb
= tdb_open_log(tdb_path
,
3290 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3291 ( lp_winbind_offline_logon()
3293 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
3297 DEBUG(0, ("winbindd_validate_cache: "
3298 "error opening/initializing tdb\n"));
3303 ret
= tdb_validate(lock_path("winbindd_cache.tdb"),
3304 cache_traverse_validate_fn
);
3307 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
3308 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
3313 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
3314 smb_panic_fn
= smb_panic
;
3318 /*********************************************************************
3319 ********************************************************************/
3321 static BOOL
add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
3322 struct winbindd_tdc_domain
**domains
,
3323 size_t *num_domains
)
3325 struct winbindd_tdc_domain
*list
= NULL
;
3328 BOOL set_only
= False
;
3330 /* don't allow duplicates */
3335 for ( i
=0; i
< (*num_domains
); i
++ ) {
3336 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
3337 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
3348 list
= TALLOC_ARRAY( NULL
, struct winbindd_tdc_domain
, 1 );
3351 list
= TALLOC_REALLOC_ARRAY( *domains
, *domains
,
3352 struct winbindd_tdc_domain
,
3357 ZERO_STRUCT( list
[idx
] );
3363 list
[idx
].domain_name
= talloc_strdup( list
, new_dom
->name
);
3364 list
[idx
].dns_name
= talloc_strdup( list
, new_dom
->alt_name
);
3366 if ( !is_null_sid( &new_dom
->sid
) )
3367 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
3369 if ( new_dom
->domain_flags
!= 0x0 )
3370 list
[idx
].trust_flags
= new_dom
->domain_flags
;
3372 if ( new_dom
->domain_type
!= 0x0 )
3373 list
[idx
].trust_type
= new_dom
->domain_type
;
3375 if ( new_dom
->domain_trust_attribs
!= 0x0 )
3376 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
3380 *num_domains
= idx
+ 1;
3386 /*********************************************************************
3387 ********************************************************************/
3389 static TDB_DATA
make_tdc_key( const char *domain_name
)
3391 char *keystr
= NULL
;
3392 TDB_DATA key
= { NULL
, 0 };
3394 if ( !domain_name
) {
3395 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
3400 asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
);
3401 key
= string_term_tdb_data(keystr
);
3406 /*********************************************************************
3407 ********************************************************************/
3409 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
3411 unsigned char **buf
)
3413 unsigned char *buffer
= NULL
;
3418 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
3426 /* Store the number of array items first */
3427 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
3430 /* now pack each domain trust record */
3431 for ( i
=0; i
<num_domains
; i
++ ) {
3434 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
3435 domains
[i
].domain_name
,
3436 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
3439 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
3440 domains
[i
].domain_name
,
3441 domains
[i
].dns_name
,
3442 sid_string_static(&domains
[i
].sid
),
3443 domains
[i
].trust_flags
,
3444 domains
[i
].trust_attribs
,
3445 domains
[i
].trust_type
);
3448 if ( buflen
< len
) {
3450 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
3451 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
3465 /*********************************************************************
3466 ********************************************************************/
3468 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
3469 struct winbindd_tdc_domain
**domains
)
3471 fstring domain_name
, dns_name
, sid_string
;
3472 uint32 type
, attribs
, flags
;
3476 struct winbindd_tdc_domain
*list
= NULL
;
3478 /* get the number of domains */
3479 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
3481 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3485 list
= TALLOC_ARRAY( NULL
, struct winbindd_tdc_domain
, num_domains
);
3487 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
3491 for ( i
=0; i
<num_domains
; i
++ ) {
3492 len
+= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
3501 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3502 TALLOC_FREE( list
);
3506 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
3507 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
3508 domain_name
, dns_name
, sid_string
,
3509 flags
, attribs
, type
));
3511 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
3512 list
[i
].dns_name
= talloc_strdup( list
, dns_name
);
3513 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
3514 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
3517 list
[i
].trust_flags
= flags
;
3518 list
[i
].trust_attribs
= attribs
;
3519 list
[i
].trust_type
= type
;
3527 /*********************************************************************
3528 ********************************************************************/
3530 static BOOL
wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
3532 TDB_DATA key
= make_tdc_key( lp_workgroup() );
3533 TDB_DATA data
= { NULL
, 0 };
3539 /* See if we were asked to delete the cache entry */
3542 ret
= tdb_delete( wcache
->tdb
, key
);
3546 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
3553 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
3556 SAFE_FREE( data
.dptr
);
3557 SAFE_FREE( key
.dptr
);
3559 return ( ret
!= -1 );
3562 /*********************************************************************
3563 ********************************************************************/
3565 BOOL
wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
3567 TDB_DATA key
= make_tdc_key( lp_workgroup() );
3568 TDB_DATA data
= { NULL
, 0 };
3576 data
= tdb_fetch( wcache
->tdb
, key
);
3578 SAFE_FREE( key
.dptr
);
3583 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
3585 SAFE_FREE( data
.dptr
);
3593 /*********************************************************************
3594 ********************************************************************/
3596 BOOL
wcache_tdc_add_domain( struct winbindd_domain
*domain
)
3598 struct winbindd_tdc_domain
*dom_list
= NULL
;
3599 size_t num_domains
= 0;
3602 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
3603 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
3604 domain
->name
, domain
->alt_name
,
3605 sid_string_static(&domain
->sid
),
3606 domain
->domain_flags
,
3607 domain
->domain_trust_attribs
,
3608 domain
->domain_type
));
3610 if ( !init_wcache() ) {
3614 /* fetch the list */
3616 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
3618 /* add the new domain */
3620 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
3624 /* pack the domain */
3626 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
3634 TALLOC_FREE( dom_list
);
3639 /*********************************************************************
3640 ********************************************************************/
3642 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
3644 struct winbindd_tdc_domain
*dom_list
= NULL
;
3645 size_t num_domains
= 0;
3647 struct winbindd_tdc_domain
*d
= NULL
;
3649 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
3651 if ( !init_wcache() ) {
3655 /* fetch the list */
3657 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
3659 for ( i
=0; i
<num_domains
; i
++ ) {
3660 if ( strequal(name
, dom_list
[i
].domain_name
) ||
3661 strequal(name
, dom_list
[i
].dns_name
) )
3663 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
3666 d
= TALLOC_P( ctx
, struct winbindd_tdc_domain
);
3670 d
->domain_name
= talloc_strdup( d
, dom_list
[i
].domain_name
);
3671 d
->dns_name
= talloc_strdup( d
, dom_list
[i
].dns_name
);
3672 sid_copy( &d
->sid
, &dom_list
[i
].sid
);
3673 d
->trust_flags
= dom_list
[i
].trust_flags
;
3674 d
->trust_type
= dom_list
[i
].trust_type
;
3675 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
3681 TALLOC_FREE( dom_list
);
3687 /*********************************************************************
3688 ********************************************************************/
3690 void wcache_tdc_clear( void )
3692 if ( !init_wcache() )
3695 wcache_tdc_store_list( NULL
, 0 );
3701 /*********************************************************************
3702 ********************************************************************/
3704 static void wcache_save_user_pwinfo(struct winbindd_domain
*domain
,
3706 const DOM_SID
*user_sid
,
3707 const char *homedir
,
3712 struct cache_entry
*centry
;
3714 if ( (centry
= centry_start(domain
, status
)) == NULL
)
3717 centry_put_string( centry
, homedir
);
3718 centry_put_string( centry
, shell
);
3719 centry_put_string( centry
, gecos
);
3720 centry_put_uint32( centry
, gid
);
3722 centry_end(centry
, "NSS/PWINFO/%s", sid_string_static(user_sid
) );
3724 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_static(user_sid
) ));
3726 centry_free(centry
);
3729 NTSTATUS
nss_get_info_cached( struct winbindd_domain
*domain
,
3730 const DOM_SID
*user_sid
,
3732 ADS_STRUCT
*ads
, LDAPMessage
*msg
,
3733 char **homedir
, char **shell
, char **gecos
,
3736 struct winbind_cache
*cache
= get_cache(domain
);
3737 struct cache_entry
*centry
= NULL
;
3743 centry
= wcache_fetch(cache
, domain
, "NSS/PWINFO/%s", sid_string_static(user_sid
));
3748 *homedir
= centry_string( centry
, ctx
);
3749 *shell
= centry_string( centry
, ctx
);
3750 *gecos
= centry_string( centry
, ctx
);
3751 *p_gid
= centry_uint32( centry
);
3753 centry_free(centry
);
3755 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
3756 sid_string_static(user_sid
)));
3758 return NT_STATUS_OK
;
3762 nt_status
= nss_get_info( domain
->name
, user_sid
, ctx
, ads
, msg
,
3763 homedir
, shell
, gecos
, p_gid
);
3765 if ( NT_STATUS_IS_OK(nt_status
) ) {
3766 wcache_save_user_pwinfo( domain
, nt_status
, user_sid
,
3767 *homedir
, *shell
, *gecos
, *p_gid
);
3770 if ( NT_STATUS_EQUAL( nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
3771 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
3773 set_domain_offline( domain
);
3780 /* the cache backend methods are exposed via this structure */
3781 struct winbindd_methods cache_methods
= {