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
;
40 extern struct winbindd_methods builtin_passdb_methods
;
43 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
44 * Here are the list of entry types that are *not* stored
45 * as form struct cache_entry in the cache.
48 static const char *non_centry_keys
[] = {
53 WINBINDD_CACHE_VERSION_KEYSTR
,
57 /************************************************************************
58 Is this key a non-centry type ?
59 ************************************************************************/
61 static bool is_non_centry_key(TDB_DATA kbuf
)
65 if (kbuf
.dptr
== NULL
|| kbuf
.dsize
== 0) {
68 for (i
= 0; non_centry_keys
[i
] != NULL
; i
++) {
69 size_t namelen
= strlen(non_centry_keys
[i
]);
70 if (kbuf
.dsize
< namelen
) {
73 if (strncmp(non_centry_keys
[i
], (const char *)kbuf
.dptr
, namelen
) == 0) {
80 /* Global online/offline state - False when online. winbindd starts up online
81 and sets this to true if the first query fails and there's an entry in
82 the cache tdb telling us to stay offline. */
84 static bool global_winbindd_offline_state
;
86 struct winbind_cache
{
92 uint32 sequence_number
;
97 void (*smb_panic_fn
)(const char *const why
) = smb_panic
;
99 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
101 static struct winbind_cache
*wcache
;
103 void winbindd_check_cache_size(time_t t
)
105 static time_t last_check_time
;
108 if (last_check_time
== (time_t)0)
111 if (t
- last_check_time
< 60 && t
- last_check_time
> 0)
114 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
115 DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
119 if (fstat(tdb_fd(wcache
->tdb
), &st
) == -1) {
120 DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno
) ));
124 if (st
.st_size
> WINBINDD_MAX_CACHE_SIZE
) {
125 DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
126 (unsigned long)st
.st_size
,
127 (unsigned long)WINBINDD_MAX_CACHE_SIZE
));
128 wcache_flush_cache();
132 /* get the winbind_cache structure */
133 static struct winbind_cache
*get_cache(struct winbindd_domain
*domain
)
135 struct winbind_cache
*ret
= wcache
;
137 /* We have to know what type of domain we are dealing with first. */
139 if (domain
->internal
) {
140 domain
->backend
= &builtin_passdb_methods
;
141 domain
->initialized
= True
;
143 if ( !domain
->initialized
) {
144 init_dc_connection( domain
);
148 OK. listen up becasue I'm only going to say this once.
149 We have the following scenarios to consider
150 (a) trusted AD domains on a Samba DC,
151 (b) trusted AD domains and we are joined to a non-kerberos domain
152 (c) trusted AD domains and we are joined to a kerberos (AD) domain
154 For (a) we can always contact the trusted domain using krb5
155 since we have the domain trust account password
157 For (b) we can only use RPC since we have no way of
158 getting a krb5 ticket in our own domain
160 For (c) we can always use krb5 since we have a kerberos trust
165 if (!domain
->backend
) {
167 struct winbindd_domain
*our_domain
= domain
;
169 /* find our domain first so we can figure out if we
170 are joined to a kerberized domain */
172 if ( !domain
->primary
)
173 our_domain
= find_our_domain();
175 if ((our_domain
->active_directory
|| IS_DC
)
176 && domain
->active_directory
177 && !lp_winbind_rpc_only()) {
178 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain
->name
));
179 domain
->backend
= &ads_methods
;
181 #endif /* HAVE_ADS */
182 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain
->name
));
183 domain
->backend
= &reconnect_methods
;
186 #endif /* HAVE_ADS */
192 ret
= SMB_XMALLOC_P(struct winbind_cache
);
196 wcache_flush_cache();
202 free a centry structure
204 static void centry_free(struct cache_entry
*centry
)
208 SAFE_FREE(centry
->data
);
212 static bool centry_check_bytes(struct cache_entry
*centry
, size_t nbytes
)
214 if (centry
->len
- centry
->ofs
< nbytes
) {
215 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
216 (unsigned int)nbytes
,
217 centry
->len
- centry
->ofs
));
224 pull a uint32 from a cache entry
226 static uint32
centry_uint32(struct cache_entry
*centry
)
230 if (!centry_check_bytes(centry
, 4)) {
231 smb_panic_fn("centry_uint32");
233 ret
= IVAL(centry
->data
, centry
->ofs
);
239 pull a uint16 from a cache entry
241 static uint16
centry_uint16(struct cache_entry
*centry
)
244 if (!centry_check_bytes(centry
, 2)) {
245 smb_panic_fn("centry_uint16");
247 ret
= CVAL(centry
->data
, centry
->ofs
);
253 pull a uint8 from a cache entry
255 static uint8
centry_uint8(struct cache_entry
*centry
)
258 if (!centry_check_bytes(centry
, 1)) {
259 smb_panic_fn("centry_uint8");
261 ret
= CVAL(centry
->data
, centry
->ofs
);
267 pull a NTTIME from a cache entry
269 static NTTIME
centry_nttime(struct cache_entry
*centry
)
272 if (!centry_check_bytes(centry
, 8)) {
273 smb_panic_fn("centry_nttime");
275 ret
= IVAL(centry
->data
, centry
->ofs
);
277 ret
+= (uint64_t)IVAL(centry
->data
, centry
->ofs
) << 32;
283 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
285 static time_t centry_time(struct cache_entry
*centry
)
287 return (time_t)centry_nttime(centry
);
290 /* pull a string from a cache entry, using the supplied
293 static char *centry_string(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
298 len
= centry_uint8(centry
);
301 /* a deliberate NULL string */
305 if (!centry_check_bytes(centry
, (size_t)len
)) {
306 smb_panic_fn("centry_string");
309 ret
= TALLOC_ARRAY(mem_ctx
, char, len
+1);
311 smb_panic_fn("centry_string out of memory\n");
313 memcpy(ret
,centry
->data
+ centry
->ofs
, len
);
319 /* pull a hash16 from a cache entry, using the supplied
322 static char *centry_hash16(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
327 len
= centry_uint8(centry
);
330 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
335 if (!centry_check_bytes(centry
, 16)) {
339 ret
= TALLOC_ARRAY(mem_ctx
, char, 16);
341 smb_panic_fn("centry_hash out of memory\n");
343 memcpy(ret
,centry
->data
+ centry
->ofs
, 16);
348 /* pull a sid from a cache entry, using the supplied
351 static bool centry_sid(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
, DOM_SID
*sid
)
354 sid_string
= centry_string(centry
, mem_ctx
);
355 if ((sid_string
== NULL
) || (!string_to_sid(sid
, sid_string
))) {
363 pull a NTSTATUS from a cache entry
365 static NTSTATUS
centry_ntstatus(struct cache_entry
*centry
)
369 status
= NT_STATUS(centry_uint32(centry
));
374 /* the server is considered down if it can't give us a sequence number */
375 static bool wcache_server_down(struct winbindd_domain
*domain
)
382 ret
= (domain
->sequence_number
== DOM_SEQUENCE_NONE
);
385 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
390 static NTSTATUS
fetch_cache_seqnum( struct winbindd_domain
*domain
, time_t now
)
397 DEBUG(10,("fetch_cache_seqnum: tdb == NULL\n"));
398 return NT_STATUS_UNSUCCESSFUL
;
401 fstr_sprintf( key
, "SEQNUM/%s", domain
->name
);
403 data
= tdb_fetch_bystring( wcache
->tdb
, key
);
404 if ( !data
.dptr
|| data
.dsize
!=8 ) {
405 DEBUG(10,("fetch_cache_seqnum: invalid data size key [%s]\n", key
));
406 return NT_STATUS_UNSUCCESSFUL
;
409 domain
->sequence_number
= IVAL(data
.dptr
, 0);
410 domain
->last_seq_check
= IVAL(data
.dptr
, 4);
412 SAFE_FREE(data
.dptr
);
414 /* have we expired? */
416 time_diff
= now
- domain
->last_seq_check
;
417 if ( time_diff
> lp_winbind_cache_time() ) {
418 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
419 domain
->name
, domain
->sequence_number
,
420 (uint32
)domain
->last_seq_check
));
421 return NT_STATUS_UNSUCCESSFUL
;
424 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
425 domain
->name
, domain
->sequence_number
,
426 (uint32
)domain
->last_seq_check
));
431 static NTSTATUS
store_cache_seqnum( struct winbindd_domain
*domain
)
438 DEBUG(10,("store_cache_seqnum: tdb == NULL\n"));
439 return NT_STATUS_UNSUCCESSFUL
;
442 fstr_sprintf( key_str
, "SEQNUM/%s", domain
->name
);
444 SIVAL(buf
, 0, domain
->sequence_number
);
445 SIVAL(buf
, 4, domain
->last_seq_check
);
449 if ( tdb_store_bystring( wcache
->tdb
, key_str
, data
, TDB_REPLACE
) == -1 ) {
450 DEBUG(10,("store_cache_seqnum: tdb_store fail key [%s]\n", key_str
));
451 return NT_STATUS_UNSUCCESSFUL
;
454 DEBUG(10,("store_cache_seqnum: success [%s][%u @ %u]\n",
455 domain
->name
, domain
->sequence_number
,
456 (uint32
)domain
->last_seq_check
));
462 refresh the domain sequence number. If force is true
463 then always refresh it, no matter how recently we fetched it
466 static void refresh_sequence_number(struct winbindd_domain
*domain
, bool force
)
470 time_t t
= time(NULL
);
471 unsigned cache_time
= lp_winbind_cache_time();
473 if ( IS_DOMAIN_OFFLINE(domain
) ) {
479 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
480 /* trying to reconnect is expensive, don't do it too often */
481 if (domain
->sequence_number
== DOM_SEQUENCE_NONE
) {
486 time_diff
= t
- domain
->last_seq_check
;
488 /* see if we have to refetch the domain sequence number */
489 if (!force
&& (time_diff
< cache_time
) &&
490 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
491 NT_STATUS_IS_OK(domain
->last_status
)) {
492 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain
->name
));
496 /* try to get the sequence number from the tdb cache first */
497 /* this will update the timestamp as well */
499 status
= fetch_cache_seqnum( domain
, t
);
500 if (NT_STATUS_IS_OK(status
) &&
501 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
502 NT_STATUS_IS_OK(domain
->last_status
)) {
506 /* important! make sure that we know if this is a native
507 mode domain or not. And that we can contact it. */
509 if ( winbindd_can_contact_domain( domain
) ) {
510 struct winbindd_methods
*orig_backend
= domain
->backend
;
511 status
= domain
->backend
->sequence_number(domain
,
512 &domain
->sequence_number
);
513 if (domain
->backend
!= orig_backend
) {
515 status
= domain
->backend
->sequence_number(domain
,
516 &domain
->sequence_number
);
519 /* just use the current time */
520 status
= NT_STATUS_OK
;
521 domain
->sequence_number
= time(NULL
);
525 /* the above call could have set our domain->backend to NULL when
526 * coming from offline to online mode, make sure to reinitialize the
527 * backend - Guenther */
530 if (!NT_STATUS_IS_OK(status
)) {
531 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status
)));
532 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
535 domain
->last_status
= status
;
536 domain
->last_seq_check
= time(NULL
);
538 /* save the new sequence number in the cache */
539 store_cache_seqnum( domain
);
542 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
543 domain
->name
, domain
->sequence_number
));
549 decide if a cache entry has expired
551 static bool centry_expired(struct winbindd_domain
*domain
, const char *keystr
, struct cache_entry
*centry
)
553 /* If we've been told to be offline - stay in that state... */
554 if (lp_winbind_offline_logon() && global_winbindd_offline_state
) {
555 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
556 keystr
, domain
->name
));
560 /* when the domain is offline return the cached entry.
561 * This deals with transient offline states... */
563 if (!domain
->online
) {
564 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
565 keystr
, domain
->name
));
569 /* if the server is OK and our cache entry came from when it was down then
570 the entry is invalid */
571 if ((domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
572 (centry
->sequence_number
== DOM_SEQUENCE_NONE
)) {
573 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
574 keystr
, domain
->name
));
578 /* if the server is down or the cache entry is not older than the
579 current sequence number then it is OK */
580 if (wcache_server_down(domain
) ||
581 centry
->sequence_number
== domain
->sequence_number
) {
582 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
583 keystr
, domain
->name
));
587 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
588 keystr
, domain
->name
));
594 static struct cache_entry
*wcache_fetch_raw(char *kstr
)
597 struct cache_entry
*centry
;
600 key
= string_tdb_data(kstr
);
601 data
= tdb_fetch(wcache
->tdb
, key
);
607 centry
= SMB_XMALLOC_P(struct cache_entry
);
608 centry
->data
= (unsigned char *)data
.dptr
;
609 centry
->len
= data
.dsize
;
612 if (centry
->len
< 8) {
613 /* huh? corrupt cache? */
614 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr
));
619 centry
->status
= centry_ntstatus(centry
);
620 centry
->sequence_number
= centry_uint32(centry
);
626 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
627 number and return status
629 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
630 struct winbindd_domain
*domain
,
631 const char *format
, ...) PRINTF_ATTRIBUTE(3,4);
632 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
633 struct winbindd_domain
*domain
,
634 const char *format
, ...)
638 struct cache_entry
*centry
;
644 refresh_sequence_number(domain
, false);
646 va_start(ap
, format
);
647 smb_xvasprintf(&kstr
, format
, ap
);
650 centry
= wcache_fetch_raw(kstr
);
651 if (centry
== NULL
) {
656 if (centry_expired(domain
, kstr
, centry
)) {
658 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
659 kstr
, domain
->name
));
666 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
667 kstr
, domain
->name
));
673 static void wcache_delete(const char *format
, ...) PRINTF_ATTRIBUTE(1,2);
674 static void wcache_delete(const char *format
, ...)
680 va_start(ap
, format
);
681 smb_xvasprintf(&kstr
, format
, ap
);
684 key
= string_tdb_data(kstr
);
686 tdb_delete(wcache
->tdb
, key
);
691 make sure we have at least len bytes available in a centry
693 static void centry_expand(struct cache_entry
*centry
, uint32 len
)
695 if (centry
->len
- centry
->ofs
>= len
)
698 centry
->data
= SMB_REALLOC_ARRAY(centry
->data
, unsigned char,
701 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry
->len
));
702 smb_panic_fn("out of memory in centry_expand");
707 push a uint32 into a centry
709 static void centry_put_uint32(struct cache_entry
*centry
, uint32 v
)
711 centry_expand(centry
, 4);
712 SIVAL(centry
->data
, centry
->ofs
, v
);
717 push a uint16 into a centry
719 static void centry_put_uint16(struct cache_entry
*centry
, uint16 v
)
721 centry_expand(centry
, 2);
722 SIVAL(centry
->data
, centry
->ofs
, v
);
727 push a uint8 into a centry
729 static void centry_put_uint8(struct cache_entry
*centry
, uint8 v
)
731 centry_expand(centry
, 1);
732 SCVAL(centry
->data
, centry
->ofs
, v
);
737 push a string into a centry
739 static void centry_put_string(struct cache_entry
*centry
, const char *s
)
744 /* null strings are marked as len 0xFFFF */
745 centry_put_uint8(centry
, 0xFF);
750 /* can't handle more than 254 char strings. Truncating is probably best */
752 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len
));
755 centry_put_uint8(centry
, len
);
756 centry_expand(centry
, len
);
757 memcpy(centry
->data
+ centry
->ofs
, s
, len
);
762 push a 16 byte hash into a centry - treat as 16 byte string.
764 static void centry_put_hash16(struct cache_entry
*centry
, const uint8 val
[16])
766 centry_put_uint8(centry
, 16);
767 centry_expand(centry
, 16);
768 memcpy(centry
->data
+ centry
->ofs
, val
, 16);
772 static void centry_put_sid(struct cache_entry
*centry
, const DOM_SID
*sid
)
775 centry_put_string(centry
, sid_to_fstring(sid_string
, sid
));
780 put NTSTATUS into a centry
782 static void centry_put_ntstatus(struct cache_entry
*centry
, NTSTATUS status
)
784 uint32 status_value
= NT_STATUS_V(status
);
785 centry_put_uint32(centry
, status_value
);
790 push a NTTIME into a centry
792 static void centry_put_nttime(struct cache_entry
*centry
, NTTIME nt
)
794 centry_expand(centry
, 8);
795 SIVAL(centry
->data
, centry
->ofs
, nt
& 0xFFFFFFFF);
797 SIVAL(centry
->data
, centry
->ofs
, nt
>> 32);
802 push a time_t into a centry - use a 64 bit size.
803 NTTIME here is being used as a convenient 64-bit size.
805 static void centry_put_time(struct cache_entry
*centry
, time_t t
)
807 NTTIME nt
= (NTTIME
)t
;
808 centry_put_nttime(centry
, nt
);
812 start a centry for output. When finished, call centry_end()
814 struct cache_entry
*centry_start(struct winbindd_domain
*domain
, NTSTATUS status
)
816 struct cache_entry
*centry
;
821 centry
= SMB_XMALLOC_P(struct cache_entry
);
823 centry
->len
= 8192; /* reasonable default */
824 centry
->data
= SMB_XMALLOC_ARRAY(uint8
, centry
->len
);
826 centry
->sequence_number
= domain
->sequence_number
;
827 centry_put_ntstatus(centry
, status
);
828 centry_put_uint32(centry
, centry
->sequence_number
);
833 finish a centry and write it to the tdb
835 static void centry_end(struct cache_entry
*centry
, const char *format
, ...) PRINTF_ATTRIBUTE(2,3);
836 static void centry_end(struct cache_entry
*centry
, const char *format
, ...)
846 va_start(ap
, format
);
847 smb_xvasprintf(&kstr
, format
, ap
);
850 key
= string_tdb_data(kstr
);
851 data
.dptr
= centry
->data
;
852 data
.dsize
= centry
->ofs
;
854 tdb_store(wcache
->tdb
, key
, data
, TDB_REPLACE
);
858 static void wcache_save_name_to_sid(struct winbindd_domain
*domain
,
859 NTSTATUS status
, const char *domain_name
,
860 const char *name
, const DOM_SID
*sid
,
861 enum lsa_SidType type
)
863 struct cache_entry
*centry
;
866 centry
= centry_start(domain
, status
);
869 centry_put_uint32(centry
, type
);
870 centry_put_sid(centry
, sid
);
871 fstrcpy(uname
, name
);
873 centry_end(centry
, "NS/%s/%s", domain_name
, uname
);
874 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name
,
875 uname
, sid_string_dbg(sid
), nt_errstr(status
)));
879 static void wcache_save_sid_to_name(struct winbindd_domain
*domain
, NTSTATUS status
,
880 const DOM_SID
*sid
, const char *domain_name
, const char *name
, enum lsa_SidType type
)
882 struct cache_entry
*centry
;
885 centry
= centry_start(domain
, status
);
889 if (NT_STATUS_IS_OK(status
)) {
890 centry_put_uint32(centry
, type
);
891 centry_put_string(centry
, domain_name
);
892 centry_put_string(centry
, name
);
895 centry_end(centry
, "SN/%s", sid_to_fstring(sid_string
, sid
));
896 DEBUG(10,("wcache_save_sid_to_name: %s -> %s (%s)\n", sid_string
,
897 name
, nt_errstr(status
)));
902 static void wcache_save_user(struct winbindd_domain
*domain
, NTSTATUS status
, WINBIND_USERINFO
*info
)
904 struct cache_entry
*centry
;
907 if (is_null_sid(&info
->user_sid
)) {
911 centry
= centry_start(domain
, status
);
914 centry_put_string(centry
, info
->acct_name
);
915 centry_put_string(centry
, info
->full_name
);
916 centry_put_string(centry
, info
->homedir
);
917 centry_put_string(centry
, info
->shell
);
918 centry_put_uint32(centry
, info
->primary_gid
);
919 centry_put_sid(centry
, &info
->user_sid
);
920 centry_put_sid(centry
, &info
->group_sid
);
921 centry_end(centry
, "U/%s", sid_to_fstring(sid_string
,
923 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string
, info
->acct_name
));
927 static void wcache_save_lockout_policy(struct winbindd_domain
*domain
,
929 struct samr_DomInfo12
*lockout_policy
)
931 struct cache_entry
*centry
;
933 centry
= centry_start(domain
, status
);
937 centry_put_nttime(centry
, lockout_policy
->lockout_duration
);
938 centry_put_nttime(centry
, lockout_policy
->lockout_window
);
939 centry_put_uint16(centry
, lockout_policy
->lockout_threshold
);
941 centry_end(centry
, "LOC_POL/%s", domain
->name
);
943 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain
->name
));
948 static void wcache_save_password_policy(struct winbindd_domain
*domain
,
950 struct samr_DomInfo1
*policy
)
952 struct cache_entry
*centry
;
954 centry
= centry_start(domain
, status
);
958 centry_put_uint16(centry
, policy
->min_password_length
);
959 centry_put_uint16(centry
, policy
->password_history_length
);
960 centry_put_uint32(centry
, policy
->password_properties
);
961 centry_put_nttime(centry
, policy
->max_password_age
);
962 centry_put_nttime(centry
, policy
->min_password_age
);
964 centry_end(centry
, "PWD_POL/%s", domain
->name
);
966 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
971 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const DOM_SID
*sid
)
973 struct winbind_cache
*cache
= get_cache(domain
);
975 fstring key_str
, tmp
;
979 return NT_STATUS_INTERNAL_DB_ERROR
;
982 if (is_null_sid(sid
)) {
983 return NT_STATUS_INVALID_SID
;
986 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
987 return NT_STATUS_INVALID_SID
;
990 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
992 data
= tdb_fetch(cache
->tdb
, string_tdb_data(key_str
));
994 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
997 SAFE_FREE(data
.dptr
);
1001 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1002 as new salted ones. */
1004 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
1005 TALLOC_CTX
*mem_ctx
,
1007 const uint8
**cached_nt_pass
,
1008 const uint8
**cached_salt
)
1010 struct winbind_cache
*cache
= get_cache(domain
);
1011 struct cache_entry
*centry
= NULL
;
1018 return NT_STATUS_INTERNAL_DB_ERROR
;
1021 if (is_null_sid(sid
)) {
1022 return NT_STATUS_INVALID_SID
;
1025 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1026 return NT_STATUS_INVALID_SID
;
1029 /* Try and get a salted cred first. If we can't
1030 fall back to an unsalted cred. */
1032 centry
= wcache_fetch(cache
, domain
, "CRED/%s",
1033 sid_to_fstring(tmp
, sid
));
1035 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1036 sid_string_dbg(sid
)));
1037 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1040 t
= centry_time(centry
);
1042 /* In the salted case this isn't actually the nt_hash itself,
1043 but the MD5 of the salt + nt_hash. Let the caller
1044 sort this out. It can tell as we only return the cached_salt
1045 if we are returning a salted cred. */
1047 *cached_nt_pass
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1048 if (*cached_nt_pass
== NULL
) {
1051 sid_to_fstring(sidstr
, sid
);
1053 /* Bad (old) cred cache. Delete and pretend we
1055 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1057 wcache_delete("CRED/%s", sidstr
);
1058 centry_free(centry
);
1059 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1062 /* We only have 17 bytes more data in the salted cred case. */
1063 if (centry
->len
- centry
->ofs
== 17) {
1064 *cached_salt
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1066 *cached_salt
= NULL
;
1069 dump_data_pw("cached_nt_pass", *cached_nt_pass
, NT_HASH_LEN
);
1071 dump_data_pw("cached_salt", *cached_salt
, NT_HASH_LEN
);
1074 status
= centry
->status
;
1076 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1077 sid_string_dbg(sid
), nt_errstr(status
) ));
1079 centry_free(centry
);
1083 /* Store creds for a SID - only writes out new salted ones. */
1085 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1086 TALLOC_CTX
*mem_ctx
,
1088 const uint8 nt_pass
[NT_HASH_LEN
])
1090 struct cache_entry
*centry
;
1093 uint8 cred_salt
[NT_HASH_LEN
];
1094 uint8 salted_hash
[NT_HASH_LEN
];
1096 if (is_null_sid(sid
)) {
1097 return NT_STATUS_INVALID_SID
;
1100 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1101 return NT_STATUS_INVALID_SID
;
1104 centry
= centry_start(domain
, NT_STATUS_OK
);
1106 return NT_STATUS_INTERNAL_DB_ERROR
;
1109 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1111 centry_put_time(centry
, time(NULL
));
1113 /* Create a salt and then salt the hash. */
1114 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1115 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1117 centry_put_hash16(centry
, salted_hash
);
1118 centry_put_hash16(centry
, cred_salt
);
1119 centry_end(centry
, "CRED/%s", sid_to_fstring(sid_string
, sid
));
1121 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1123 centry_free(centry
);
1125 return NT_STATUS_OK
;
1129 /* Query display info. This is the basic user list fn */
1130 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
1131 TALLOC_CTX
*mem_ctx
,
1132 uint32
*num_entries
,
1133 WINBIND_USERINFO
**info
)
1135 struct winbind_cache
*cache
= get_cache(domain
);
1136 struct cache_entry
*centry
= NULL
;
1138 unsigned int i
, retry
;
1143 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1147 *num_entries
= centry_uint32(centry
);
1149 if (*num_entries
== 0)
1152 (*info
) = TALLOC_ARRAY(mem_ctx
, WINBIND_USERINFO
, *num_entries
);
1154 smb_panic_fn("query_user_list out of memory");
1156 for (i
=0; i
<(*num_entries
); i
++) {
1157 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
1158 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
1159 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
1160 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
1161 centry_sid(centry
, mem_ctx
, &(*info
)[i
].user_sid
);
1162 centry_sid(centry
, mem_ctx
, &(*info
)[i
].group_sid
);
1166 status
= centry
->status
;
1168 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1169 domain
->name
, nt_errstr(status
) ));
1171 centry_free(centry
);
1178 /* Return status value returned by seq number check */
1180 if (!NT_STATUS_IS_OK(domain
->last_status
))
1181 return domain
->last_status
;
1183 /* Put the query_user_list() in a retry loop. There appears to be
1184 * some bug either with Windows 2000 or Samba's handling of large
1185 * rpc replies. This manifests itself as sudden disconnection
1186 * at a random point in the enumeration of a large (60k) user list.
1187 * The retry loop simply tries the operation again. )-: It's not
1188 * pretty but an acceptable workaround until we work out what the
1189 * real problem is. */
1194 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1197 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
1198 if (!NT_STATUS_IS_OK(status
)) {
1199 DEBUG(3, ("query_user_list: returned 0x%08x, "
1200 "retrying\n", NT_STATUS_V(status
)));
1202 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1203 DEBUG(3, ("query_user_list: flushing "
1204 "connection cache\n"));
1205 invalidate_cm_connection(&domain
->conn
);
1208 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1212 refresh_sequence_number(domain
, false);
1213 centry
= centry_start(domain
, status
);
1216 centry_put_uint32(centry
, *num_entries
);
1217 for (i
=0; i
<(*num_entries
); i
++) {
1218 centry_put_string(centry
, (*info
)[i
].acct_name
);
1219 centry_put_string(centry
, (*info
)[i
].full_name
);
1220 centry_put_string(centry
, (*info
)[i
].homedir
);
1221 centry_put_string(centry
, (*info
)[i
].shell
);
1222 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1223 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1224 if (domain
->backend
&& domain
->backend
->consistent
) {
1225 /* when the backend is consistent we can pre-prime some mappings */
1226 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1228 (*info
)[i
].acct_name
,
1229 &(*info
)[i
].user_sid
,
1231 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1232 &(*info
)[i
].user_sid
,
1234 (*info
)[i
].acct_name
,
1236 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1239 centry_end(centry
, "UL/%s", domain
->name
);
1240 centry_free(centry
);
1246 /* list all domain groups */
1247 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
1248 TALLOC_CTX
*mem_ctx
,
1249 uint32
*num_entries
,
1250 struct acct_info
**info
)
1252 struct winbind_cache
*cache
= get_cache(domain
);
1253 struct cache_entry
*centry
= NULL
;
1260 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1264 *num_entries
= centry_uint32(centry
);
1266 if (*num_entries
== 0)
1269 (*info
) = TALLOC_ARRAY(mem_ctx
, struct acct_info
, *num_entries
);
1271 smb_panic_fn("enum_dom_groups out of memory");
1273 for (i
=0; i
<(*num_entries
); i
++) {
1274 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1275 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1276 (*info
)[i
].rid
= centry_uint32(centry
);
1280 status
= centry
->status
;
1282 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1283 domain
->name
, nt_errstr(status
) ));
1285 centry_free(centry
);
1292 /* Return status value returned by seq number check */
1294 if (!NT_STATUS_IS_OK(domain
->last_status
))
1295 return domain
->last_status
;
1297 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1300 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1303 refresh_sequence_number(domain
, false);
1304 centry
= centry_start(domain
, status
);
1307 centry_put_uint32(centry
, *num_entries
);
1308 for (i
=0; i
<(*num_entries
); i
++) {
1309 centry_put_string(centry
, (*info
)[i
].acct_name
);
1310 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1311 centry_put_uint32(centry
, (*info
)[i
].rid
);
1313 centry_end(centry
, "GL/%s/domain", domain
->name
);
1314 centry_free(centry
);
1320 /* list all domain groups */
1321 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
1322 TALLOC_CTX
*mem_ctx
,
1323 uint32
*num_entries
,
1324 struct acct_info
**info
)
1326 struct winbind_cache
*cache
= get_cache(domain
);
1327 struct cache_entry
*centry
= NULL
;
1334 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1338 *num_entries
= centry_uint32(centry
);
1340 if (*num_entries
== 0)
1343 (*info
) = TALLOC_ARRAY(mem_ctx
, struct acct_info
, *num_entries
);
1345 smb_panic_fn("enum_dom_groups out of memory");
1347 for (i
=0; i
<(*num_entries
); i
++) {
1348 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1349 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1350 (*info
)[i
].rid
= centry_uint32(centry
);
1355 /* If we are returning cached data and the domain controller
1356 is down then we don't know whether the data is up to date
1357 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1360 if (wcache_server_down(domain
)) {
1361 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1362 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1364 status
= centry
->status
;
1366 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1367 domain
->name
, nt_errstr(status
) ));
1369 centry_free(centry
);
1376 /* Return status value returned by seq number check */
1378 if (!NT_STATUS_IS_OK(domain
->last_status
))
1379 return domain
->last_status
;
1381 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1384 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1387 refresh_sequence_number(domain
, false);
1388 centry
= centry_start(domain
, status
);
1391 centry_put_uint32(centry
, *num_entries
);
1392 for (i
=0; i
<(*num_entries
); i
++) {
1393 centry_put_string(centry
, (*info
)[i
].acct_name
);
1394 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1395 centry_put_uint32(centry
, (*info
)[i
].rid
);
1397 centry_end(centry
, "GL/%s/local", domain
->name
);
1398 centry_free(centry
);
1404 /* convert a single name to a sid in a domain */
1405 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
1406 TALLOC_CTX
*mem_ctx
,
1407 enum winbindd_cmd orig_cmd
,
1408 const char *domain_name
,
1411 enum lsa_SidType
*type
)
1413 struct winbind_cache
*cache
= get_cache(domain
);
1414 struct cache_entry
*centry
= NULL
;
1421 fstrcpy(uname
, name
);
1423 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1427 status
= centry
->status
;
1428 if (NT_STATUS_IS_OK(status
)) {
1429 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1430 centry_sid(centry
, mem_ctx
, sid
);
1433 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: %s\n",
1434 domain
->name
, nt_errstr(status
) ));
1436 centry_free(centry
);
1442 /* If the seq number check indicated that there is a problem
1443 * with this DC, then return that status... except for
1444 * access_denied. This is special because the dc may be in
1445 * "restrict anonymous = 1" mode, in which case it will deny
1446 * most unauthenticated operations, but *will* allow the LSA
1447 * name-to-sid that we try as a fallback. */
1449 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1450 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1451 return domain
->last_status
;
1453 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1456 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, orig_cmd
,
1457 domain_name
, name
, sid
, type
);
1460 refresh_sequence_number(domain
, false);
1462 if (domain
->online
&&
1463 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1464 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1466 /* Only save the reverse mapping if this was not a UPN */
1467 if (!strchr(name
, '@')) {
1468 strupper_m(CONST_DISCARD(char *,domain_name
));
1469 strlower_m(CONST_DISCARD(char *,name
));
1470 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1477 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1479 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1480 TALLOC_CTX
*mem_ctx
,
1484 enum lsa_SidType
*type
)
1486 struct winbind_cache
*cache
= get_cache(domain
);
1487 struct cache_entry
*centry
= NULL
;
1494 centry
= wcache_fetch(cache
, domain
, "SN/%s",
1495 sid_to_fstring(sid_string
, sid
));
1499 status
= centry
->status
;
1500 if (NT_STATUS_IS_OK(status
)) {
1501 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1502 *domain_name
= centry_string(centry
, mem_ctx
);
1503 *name
= centry_string(centry
, mem_ctx
);
1506 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: %s\n",
1507 domain
->name
, nt_errstr(status
) ));
1509 centry_free(centry
);
1514 *domain_name
= NULL
;
1516 /* If the seq number check indicated that there is a problem
1517 * with this DC, then return that status... except for
1518 * access_denied. This is special because the dc may be in
1519 * "restrict anonymous = 1" mode, in which case it will deny
1520 * most unauthenticated operations, but *will* allow the LSA
1521 * sid-to-name that we try as a fallback. */
1523 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1524 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1525 return domain
->last_status
;
1527 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1530 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1533 refresh_sequence_number(domain
, false);
1534 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
1536 /* We can't save the name to sid mapping here, as with sid history a
1537 * later name2sid would give the wrong sid. */
1542 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
1543 TALLOC_CTX
*mem_ctx
,
1544 const DOM_SID
*domain_sid
,
1549 enum lsa_SidType
**types
)
1551 struct winbind_cache
*cache
= get_cache(domain
);
1553 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1557 *domain_name
= NULL
;
1565 if (num_rids
== 0) {
1566 return NT_STATUS_OK
;
1569 *names
= TALLOC_ARRAY(mem_ctx
, char *, num_rids
);
1570 *types
= TALLOC_ARRAY(mem_ctx
, enum lsa_SidType
, num_rids
);
1572 if ((*names
== NULL
) || (*types
== NULL
)) {
1573 result
= NT_STATUS_NO_MEMORY
;
1577 have_mapped
= have_unmapped
= false;
1579 for (i
=0; i
<num_rids
; i
++) {
1581 struct cache_entry
*centry
;
1584 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
1585 result
= NT_STATUS_INTERNAL_ERROR
;
1589 centry
= wcache_fetch(cache
, domain
, "SN/%s",
1590 sid_to_fstring(tmp
, &sid
));
1595 (*types
)[i
] = SID_NAME_UNKNOWN
;
1596 (*names
)[i
] = talloc_strdup(*names
, "");
1598 if (NT_STATUS_IS_OK(centry
->status
)) {
1601 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
1603 dom
= centry_string(centry
, mem_ctx
);
1604 if (*domain_name
== NULL
) {
1610 (*names
)[i
] = centry_string(centry
, *names
);
1612 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)) {
1613 have_unmapped
= true;
1616 /* something's definitely wrong */
1617 result
= centry
->status
;
1621 centry_free(centry
);
1625 return NT_STATUS_NONE_MAPPED
;
1627 if (!have_unmapped
) {
1628 return NT_STATUS_OK
;
1630 return STATUS_SOME_UNMAPPED
;
1634 TALLOC_FREE(*names
);
1635 TALLOC_FREE(*types
);
1637 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
1638 rids
, num_rids
, domain_name
,
1642 None of the queried rids has been found so save all negative entries
1644 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
1645 for (i
= 0; i
< num_rids
; i
++) {
1647 const char *name
= "";
1648 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
1649 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
1651 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
1652 return NT_STATUS_INTERNAL_ERROR
;
1655 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
1663 Some or all of the queried rids have been found.
1665 if (!NT_STATUS_IS_OK(result
) &&
1666 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
1670 refresh_sequence_number(domain
, false);
1672 for (i
=0; i
<num_rids
; i
++) {
1676 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
1677 result
= NT_STATUS_INTERNAL_ERROR
;
1681 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
1682 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
1684 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
1685 (*names
)[i
], (*types
)[i
]);
1692 TALLOC_FREE(*names
);
1693 TALLOC_FREE(*types
);
1697 /* Lookup user information from a rid */
1698 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
1699 TALLOC_CTX
*mem_ctx
,
1700 const DOM_SID
*user_sid
,
1701 WINBIND_USERINFO
*info
)
1703 struct winbind_cache
*cache
= get_cache(domain
);
1704 struct cache_entry
*centry
= NULL
;
1711 centry
= wcache_fetch(cache
, domain
, "U/%s",
1712 sid_to_fstring(tmp
, user_sid
));
1714 /* If we have an access denied cache entry and a cached info3 in the
1715 samlogon cache then do a query. This will force the rpc back end
1716 to return the info3 data. */
1718 if (NT_STATUS_V(domain
->last_status
) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED
) &&
1719 netsamlogon_cache_have(user_sid
)) {
1720 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1721 domain
->last_status
= NT_STATUS_OK
;
1722 centry_free(centry
);
1729 /* if status is not ok then this is a negative hit
1730 and the rest of the data doesn't matter */
1731 status
= centry
->status
;
1732 if (NT_STATUS_IS_OK(status
)) {
1733 info
->acct_name
= centry_string(centry
, mem_ctx
);
1734 info
->full_name
= centry_string(centry
, mem_ctx
);
1735 info
->homedir
= centry_string(centry
, mem_ctx
);
1736 info
->shell
= centry_string(centry
, mem_ctx
);
1737 info
->primary_gid
= centry_uint32(centry
);
1738 centry_sid(centry
, mem_ctx
, &info
->user_sid
);
1739 centry_sid(centry
, mem_ctx
, &info
->group_sid
);
1742 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: %s\n",
1743 domain
->name
, nt_errstr(status
) ));
1745 centry_free(centry
);
1751 /* Return status value returned by seq number check */
1753 if (!NT_STATUS_IS_OK(domain
->last_status
))
1754 return domain
->last_status
;
1756 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
1759 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
1762 refresh_sequence_number(domain
, false);
1763 wcache_save_user(domain
, status
, info
);
1769 /* Lookup groups a user is a member of. */
1770 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
1771 TALLOC_CTX
*mem_ctx
,
1772 const DOM_SID
*user_sid
,
1773 uint32
*num_groups
, DOM_SID
**user_gids
)
1775 struct winbind_cache
*cache
= get_cache(domain
);
1776 struct cache_entry
*centry
= NULL
;
1784 centry
= wcache_fetch(cache
, domain
, "UG/%s",
1785 sid_to_fstring(sid_string
, user_sid
));
1787 /* If we have an access denied cache entry and a cached info3 in the
1788 samlogon cache then do a query. This will force the rpc back end
1789 to return the info3 data. */
1791 if (NT_STATUS_V(domain
->last_status
) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED
) &&
1792 netsamlogon_cache_have(user_sid
)) {
1793 DEBUG(10, ("lookup_usergroups: cached access denied and have cached info3\n"));
1794 domain
->last_status
= NT_STATUS_OK
;
1795 centry_free(centry
);
1802 *num_groups
= centry_uint32(centry
);
1804 if (*num_groups
== 0)
1807 (*user_gids
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_groups
);
1808 if (! (*user_gids
)) {
1809 smb_panic_fn("lookup_usergroups out of memory");
1811 for (i
=0; i
<(*num_groups
); i
++) {
1812 centry_sid(centry
, mem_ctx
, &(*user_gids
)[i
]);
1816 status
= centry
->status
;
1818 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status: %s\n",
1819 domain
->name
, nt_errstr(status
) ));
1821 centry_free(centry
);
1826 (*user_gids
) = NULL
;
1828 /* Return status value returned by seq number check */
1830 if (!NT_STATUS_IS_OK(domain
->last_status
))
1831 return domain
->last_status
;
1833 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
1836 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
1838 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
1842 refresh_sequence_number(domain
, false);
1843 centry
= centry_start(domain
, status
);
1847 centry_put_uint32(centry
, *num_groups
);
1848 for (i
=0; i
<(*num_groups
); i
++) {
1849 centry_put_sid(centry
, &(*user_gids
)[i
]);
1852 centry_end(centry
, "UG/%s", sid_to_fstring(sid_string
, user_sid
));
1853 centry_free(centry
);
1859 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
1860 TALLOC_CTX
*mem_ctx
,
1861 uint32 num_sids
, const DOM_SID
*sids
,
1862 uint32
*num_aliases
, uint32
**alias_rids
)
1864 struct winbind_cache
*cache
= get_cache(domain
);
1865 struct cache_entry
*centry
= NULL
;
1867 char *sidlist
= talloc_strdup(mem_ctx
, "");
1873 if (num_sids
== 0) {
1876 return NT_STATUS_OK
;
1879 /* We need to cache indexed by the whole list of SIDs, the aliases
1880 * resulting might come from any of the SIDs. */
1882 for (i
=0; i
<num_sids
; i
++) {
1884 sidlist
= talloc_asprintf(mem_ctx
, "%s/%s", sidlist
,
1885 sid_to_fstring(tmp
, &sids
[i
]));
1886 if (sidlist
== NULL
)
1887 return NT_STATUS_NO_MEMORY
;
1890 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
1895 *num_aliases
= centry_uint32(centry
);
1899 (*alias_rids
) = TALLOC_ARRAY(mem_ctx
, uint32
, *num_aliases
);
1901 if ((*alias_rids
) == NULL
) {
1902 centry_free(centry
);
1903 return NT_STATUS_NO_MEMORY
;
1906 (*alias_rids
) = NULL
;
1909 for (i
=0; i
<(*num_aliases
); i
++)
1910 (*alias_rids
)[i
] = centry_uint32(centry
);
1912 status
= centry
->status
;
1914 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
1915 "status %s\n", domain
->name
, nt_errstr(status
)));
1917 centry_free(centry
);
1922 (*alias_rids
) = NULL
;
1924 if (!NT_STATUS_IS_OK(domain
->last_status
))
1925 return domain
->last_status
;
1927 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
1928 "for domain %s\n", domain
->name
));
1930 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
1932 num_aliases
, alias_rids
);
1935 refresh_sequence_number(domain
, false);
1936 centry
= centry_start(domain
, status
);
1939 centry_put_uint32(centry
, *num_aliases
);
1940 for (i
=0; i
<(*num_aliases
); i
++)
1941 centry_put_uint32(centry
, (*alias_rids
)[i
]);
1942 centry_end(centry
, "UA%s", sidlist
);
1943 centry_free(centry
);
1950 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
1951 TALLOC_CTX
*mem_ctx
,
1952 const DOM_SID
*group_sid
, uint32
*num_names
,
1953 DOM_SID
**sid_mem
, char ***names
,
1954 uint32
**name_types
)
1956 struct winbind_cache
*cache
= get_cache(domain
);
1957 struct cache_entry
*centry
= NULL
;
1965 centry
= wcache_fetch(cache
, domain
, "GM/%s",
1966 sid_to_fstring(sid_string
, group_sid
));
1970 *num_names
= centry_uint32(centry
);
1972 if (*num_names
== 0)
1975 (*sid_mem
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_names
);
1976 (*names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_names
);
1977 (*name_types
) = TALLOC_ARRAY(mem_ctx
, uint32
, *num_names
);
1979 if (! (*sid_mem
) || ! (*names
) || ! (*name_types
)) {
1980 smb_panic_fn("lookup_groupmem out of memory");
1983 for (i
=0; i
<(*num_names
); i
++) {
1984 centry_sid(centry
, mem_ctx
, &(*sid_mem
)[i
]);
1985 (*names
)[i
] = centry_string(centry
, mem_ctx
);
1986 (*name_types
)[i
] = centry_uint32(centry
);
1990 status
= centry
->status
;
1992 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status: %s\n",
1993 domain
->name
, nt_errstr(status
)));
1995 centry_free(centry
);
2002 (*name_types
) = NULL
;
2004 /* Return status value returned by seq number check */
2006 if (!NT_STATUS_IS_OK(domain
->last_status
))
2007 return domain
->last_status
;
2009 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2012 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2013 sid_mem
, names
, name_types
);
2016 refresh_sequence_number(domain
, false);
2017 centry
= centry_start(domain
, status
);
2020 centry_put_uint32(centry
, *num_names
);
2021 for (i
=0; i
<(*num_names
); i
++) {
2022 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2023 centry_put_string(centry
, (*names
)[i
]);
2024 centry_put_uint32(centry
, (*name_types
)[i
]);
2026 centry_end(centry
, "GM/%s", sid_to_fstring(sid_string
, group_sid
));
2027 centry_free(centry
);
2033 /* find the sequence number for a domain */
2034 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
2036 refresh_sequence_number(domain
, false);
2038 *seq
= domain
->sequence_number
;
2040 return NT_STATUS_OK
;
2043 /* enumerate trusted domains
2044 * (we need to have the list of trustdoms in the cache when we go offline) -
2046 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
2047 TALLOC_CTX
*mem_ctx
,
2048 uint32
*num_domains
,
2053 struct winbind_cache
*cache
= get_cache(domain
);
2054 struct cache_entry
*centry
= NULL
;
2061 centry
= wcache_fetch(cache
, domain
, "TRUSTDOMS/%s", domain
->name
);
2067 *num_domains
= centry_uint32(centry
);
2070 (*names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
2071 (*alt_names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
2072 (*dom_sids
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_domains
);
2074 if (! (*dom_sids
) || ! (*names
) || ! (*alt_names
)) {
2075 smb_panic_fn("trusted_domains out of memory");
2079 (*alt_names
) = NULL
;
2083 for (i
=0; i
<(*num_domains
); i
++) {
2084 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2085 (*alt_names
)[i
] = centry_string(centry
, mem_ctx
);
2086 if (!centry_sid(centry
, mem_ctx
, &(*dom_sids
)[i
])) {
2087 sid_copy(&(*dom_sids
)[i
], &global_sid_NULL
);
2091 status
= centry
->status
;
2093 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
2094 domain
->name
, *num_domains
, nt_errstr(status
) ));
2096 centry_free(centry
);
2103 (*alt_names
) = NULL
;
2105 /* Return status value returned by seq number check */
2107 if (!NT_STATUS_IS_OK(domain
->last_status
))
2108 return domain
->last_status
;
2110 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2113 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, num_domains
,
2114 names
, alt_names
, dom_sids
);
2116 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2117 * so that the generic centry handling still applies correctly -
2120 if (!NT_STATUS_IS_ERR(status
)) {
2121 status
= NT_STATUS_OK
;
2125 #if 0 /* Disabled as we want the trust dom list to be managed by
2126 the main parent and always to make the query. --jerry */
2129 refresh_sequence_number(domain
, false);
2131 centry
= centry_start(domain
, status
);
2135 centry_put_uint32(centry
, *num_domains
);
2137 for (i
=0; i
<(*num_domains
); i
++) {
2138 centry_put_string(centry
, (*names
)[i
]);
2139 centry_put_string(centry
, (*alt_names
)[i
]);
2140 centry_put_sid(centry
, &(*dom_sids
)[i
]);
2143 centry_end(centry
, "TRUSTDOMS/%s", domain
->name
);
2145 centry_free(centry
);
2153 /* get lockout policy */
2154 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
2155 TALLOC_CTX
*mem_ctx
,
2156 struct samr_DomInfo12
*policy
)
2158 struct winbind_cache
*cache
= get_cache(domain
);
2159 struct cache_entry
*centry
= NULL
;
2165 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2170 policy
->lockout_duration
= centry_nttime(centry
);
2171 policy
->lockout_window
= centry_nttime(centry
);
2172 policy
->lockout_threshold
= centry_uint16(centry
);
2174 status
= centry
->status
;
2176 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2177 domain
->name
, nt_errstr(status
) ));
2179 centry_free(centry
);
2183 ZERO_STRUCTP(policy
);
2185 /* Return status value returned by seq number check */
2187 if (!NT_STATUS_IS_OK(domain
->last_status
))
2188 return domain
->last_status
;
2190 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2193 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2196 refresh_sequence_number(domain
, false);
2197 wcache_save_lockout_policy(domain
, status
, policy
);
2202 /* get password policy */
2203 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
2204 TALLOC_CTX
*mem_ctx
,
2205 struct samr_DomInfo1
*policy
)
2207 struct winbind_cache
*cache
= get_cache(domain
);
2208 struct cache_entry
*centry
= NULL
;
2214 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2219 policy
->min_password_length
= centry_uint16(centry
);
2220 policy
->password_history_length
= centry_uint16(centry
);
2221 policy
->password_properties
= centry_uint32(centry
);
2222 policy
->max_password_age
= centry_nttime(centry
);
2223 policy
->min_password_age
= centry_nttime(centry
);
2225 status
= centry
->status
;
2227 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2228 domain
->name
, nt_errstr(status
) ));
2230 centry_free(centry
);
2234 ZERO_STRUCTP(policy
);
2236 /* Return status value returned by seq number check */
2238 if (!NT_STATUS_IS_OK(domain
->last_status
))
2239 return domain
->last_status
;
2241 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2244 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
2247 refresh_sequence_number(domain
, false);
2248 if (NT_STATUS_IS_OK(status
)) {
2249 wcache_save_password_policy(domain
, status
, policy
);
2256 /* Invalidate cached user and group lists coherently */
2258 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2261 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
2262 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
2263 tdb_delete(the_tdb
, kbuf
);
2268 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2270 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
2271 struct netr_SamInfo3
*info3
)
2274 fstring key_str
, sid_string
;
2275 struct winbind_cache
*cache
;
2277 /* dont clear cached U/SID and UG/SID entries when we want to logon
2280 if (lp_winbind_offline_logon()) {
2287 cache
= get_cache(domain
);
2293 sid_copy(&sid
, info3
->base
.domain_sid
);
2294 sid_append_rid(&sid
, info3
->base
.rid
);
2296 /* Clear U/SID cache entry */
2297 fstr_sprintf(key_str
, "U/%s", sid_to_fstring(sid_string
, &sid
));
2298 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
2299 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
2301 /* Clear UG/SID cache entry */
2302 fstr_sprintf(key_str
, "UG/%s", sid_to_fstring(sid_string
, &sid
));
2303 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
2304 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
2306 /* Samba/winbindd never needs this. */
2307 netsamlogon_clear_cached_user(info3
);
2310 bool wcache_invalidate_cache(void)
2312 struct winbindd_domain
*domain
;
2314 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
2315 struct winbind_cache
*cache
= get_cache(domain
);
2317 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2318 "entries for %s\n", domain
->name
));
2321 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
2330 bool init_wcache(void)
2332 if (wcache
== NULL
) {
2333 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
2334 ZERO_STRUCTP(wcache
);
2337 if (wcache
->tdb
!= NULL
)
2340 /* when working offline we must not clear the cache on restart */
2341 wcache
->tdb
= tdb_open_log(lock_path("winbindd_cache.tdb"),
2342 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
2343 lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
2344 O_RDWR
|O_CREAT
, 0600);
2346 if (wcache
->tdb
== NULL
) {
2347 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2354 /************************************************************************
2355 This is called by the parent to initialize the cache file.
2356 We don't need sophisticated locking here as we know we're the
2358 ************************************************************************/
2360 bool initialize_winbindd_cache(void)
2362 bool cache_bad
= true;
2365 if (!init_wcache()) {
2366 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
2370 /* Check version number. */
2371 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
2372 vers
== WINBINDD_CACHE_VERSION
) {
2377 DEBUG(0,("initialize_winbindd_cache: clearing cache "
2378 "and re-creating with version number %d\n",
2379 WINBINDD_CACHE_VERSION
));
2381 tdb_close(wcache
->tdb
);
2384 if (unlink(lock_path("winbindd_cache.tdb")) == -1) {
2385 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
2386 lock_path("winbindd_cache.tdb"),
2390 if (!init_wcache()) {
2391 DEBUG(0,("initialize_winbindd_cache: re-initialization "
2392 "init_wcache failed.\n"));
2396 /* Write the version. */
2397 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
2398 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
2399 tdb_errorstr(wcache
->tdb
) ));
2404 tdb_close(wcache
->tdb
);
2409 void close_winbindd_cache(void)
2415 tdb_close(wcache
->tdb
);
2420 void cache_store_response(pid_t pid
, struct winbindd_response
*response
)
2427 DEBUG(10, ("Storing response for pid %d, len %d\n",
2428 pid
, response
->length
));
2430 fstr_sprintf(key_str
, "DR/%d", pid
);
2431 if (tdb_store(wcache
->tdb
, string_tdb_data(key_str
),
2432 make_tdb_data((uint8
*)response
, sizeof(*response
)),
2436 if (response
->length
== sizeof(*response
))
2439 /* There's extra data */
2441 DEBUG(10, ("Storing extra data: len=%d\n",
2442 (int)(response
->length
- sizeof(*response
))));
2444 fstr_sprintf(key_str
, "DE/%d", pid
);
2445 if (tdb_store(wcache
->tdb
, string_tdb_data(key_str
),
2446 make_tdb_data((uint8
*)response
->extra_data
.data
,
2447 response
->length
- sizeof(*response
)),
2451 /* We could not store the extra data, make sure the tdb does not
2452 * contain a main record with wrong dangling extra data */
2454 fstr_sprintf(key_str
, "DR/%d", pid
);
2455 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2460 bool cache_retrieve_response(pid_t pid
, struct winbindd_response
* response
)
2468 DEBUG(10, ("Retrieving response for pid %d\n", pid
));
2470 fstr_sprintf(key_str
, "DR/%d", pid
);
2471 data
= tdb_fetch(wcache
->tdb
, string_tdb_data(key_str
));
2473 if (data
.dptr
== NULL
)
2476 if (data
.dsize
!= sizeof(*response
))
2479 memcpy(response
, data
.dptr
, data
.dsize
);
2480 SAFE_FREE(data
.dptr
);
2482 if (response
->length
== sizeof(*response
)) {
2483 response
->extra_data
.data
= NULL
;
2487 /* There's extra data */
2489 DEBUG(10, ("Retrieving extra data length=%d\n",
2490 (int)(response
->length
- sizeof(*response
))));
2492 fstr_sprintf(key_str
, "DE/%d", pid
);
2493 data
= tdb_fetch(wcache
->tdb
, string_tdb_data(key_str
));
2495 if (data
.dptr
== NULL
) {
2496 DEBUG(0, ("Did not find extra data\n"));
2500 if (data
.dsize
!= (response
->length
- sizeof(*response
))) {
2501 DEBUG(0, ("Invalid extra data length: %d\n", (int)data
.dsize
));
2502 SAFE_FREE(data
.dptr
);
2506 dump_data(11, (uint8
*)data
.dptr
, data
.dsize
);
2508 response
->extra_data
.data
= data
.dptr
;
2512 void cache_cleanup_response(pid_t pid
)
2519 fstr_sprintf(key_str
, "DR/%d", pid
);
2520 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2522 fstr_sprintf(key_str
, "DE/%d", pid
);
2523 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2529 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const DOM_SID
*sid
,
2530 char **domain_name
, char **name
,
2531 enum lsa_SidType
*type
)
2533 struct winbindd_domain
*domain
;
2534 struct winbind_cache
*cache
;
2535 struct cache_entry
*centry
= NULL
;
2539 domain
= find_lookup_domain_from_sid(sid
);
2540 if (domain
== NULL
) {
2544 cache
= get_cache(domain
);
2546 if (cache
->tdb
== NULL
) {
2550 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2551 sid_to_fstring(tmp
, sid
));
2552 if (centry
== NULL
) {
2556 if (NT_STATUS_IS_OK(centry
->status
)) {
2557 *type
= (enum lsa_SidType
)centry_uint32(centry
);
2558 *domain_name
= centry_string(centry
, mem_ctx
);
2559 *name
= centry_string(centry
, mem_ctx
);
2562 status
= centry
->status
;
2563 centry_free(centry
);
2564 return NT_STATUS_IS_OK(status
);
2567 bool lookup_cached_name(TALLOC_CTX
*mem_ctx
,
2568 const char *domain_name
,
2571 enum lsa_SidType
*type
)
2573 struct winbindd_domain
*domain
;
2574 struct winbind_cache
*cache
;
2575 struct cache_entry
*centry
= NULL
;
2578 bool original_online_state
;
2580 domain
= find_lookup_domain_from_name(domain_name
);
2581 if (domain
== NULL
) {
2585 cache
= get_cache(domain
);
2587 if (cache
->tdb
== NULL
) {
2591 fstrcpy(uname
, name
);
2594 /* If we are doing a cached logon, temporarily set the domain
2595 offline so the cache won't expire the entry */
2597 original_online_state
= domain
->online
;
2598 domain
->online
= false;
2599 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
2600 domain
->online
= original_online_state
;
2602 if (centry
== NULL
) {
2606 if (NT_STATUS_IS_OK(centry
->status
)) {
2607 *type
= (enum lsa_SidType
)centry_uint32(centry
);
2608 centry_sid(centry
, mem_ctx
, sid
);
2611 status
= centry
->status
;
2612 centry_free(centry
);
2614 return NT_STATUS_IS_OK(status
);
2617 void cache_name2sid(struct winbindd_domain
*domain
,
2618 const char *domain_name
, const char *name
,
2619 enum lsa_SidType type
, const DOM_SID
*sid
)
2621 refresh_sequence_number(domain
, false);
2622 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
2627 * The original idea that this cache only contains centries has
2628 * been blurred - now other stuff gets put in here. Ensure we
2629 * ignore these things on cleanup.
2632 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
2633 TDB_DATA dbuf
, void *state
)
2635 struct cache_entry
*centry
;
2637 if (is_non_centry_key(kbuf
)) {
2641 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
2646 if (!NT_STATUS_IS_OK(centry
->status
)) {
2647 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
2648 tdb_delete(the_tdb
, kbuf
);
2651 centry_free(centry
);
2655 /* flush the cache */
2656 void wcache_flush_cache(void)
2661 tdb_close(wcache
->tdb
);
2667 /* when working offline we must not clear the cache on restart */
2668 wcache
->tdb
= tdb_open_log(lock_path("winbindd_cache.tdb"),
2669 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
2670 lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
2671 O_RDWR
|O_CREAT
, 0600);
2674 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2678 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
2680 DEBUG(10,("wcache_flush_cache success\n"));
2683 /* Count cached creds */
2685 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2688 int *cred_count
= (int*)state
;
2690 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
2696 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
2698 struct winbind_cache
*cache
= get_cache(domain
);
2703 return NT_STATUS_INTERNAL_DB_ERROR
;
2706 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
2708 return NT_STATUS_OK
;
2712 struct cred_list
*prev
, *next
;
2717 static struct cred_list
*wcache_cred_list
;
2719 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2722 struct cred_list
*cred
;
2724 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
2726 cred
= SMB_MALLOC_P(struct cred_list
);
2728 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2734 /* save a copy of the key */
2736 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
2737 DLIST_ADD(wcache_cred_list
, cred
);
2743 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const DOM_SID
*sid
)
2745 struct winbind_cache
*cache
= get_cache(domain
);
2748 struct cred_list
*cred
, *oldest
= NULL
;
2751 return NT_STATUS_INTERNAL_DB_ERROR
;
2754 /* we possibly already have an entry */
2755 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
2757 fstring key_str
, tmp
;
2759 DEBUG(11,("we already have an entry, deleting that\n"));
2761 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
2763 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
2765 return NT_STATUS_OK
;
2768 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
2770 return NT_STATUS_OK
;
2771 } else if ((ret
== -1) || (wcache_cred_list
== NULL
)) {
2772 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2775 ZERO_STRUCTP(oldest
);
2777 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
2782 data
= tdb_fetch(cache
->tdb
, string_tdb_data(cred
->name
));
2784 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
2786 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2790 t
= IVAL(data
.dptr
, 0);
2791 SAFE_FREE(data
.dptr
);
2794 oldest
= SMB_MALLOC_P(struct cred_list
);
2795 if (oldest
== NULL
) {
2796 status
= NT_STATUS_NO_MEMORY
;
2800 fstrcpy(oldest
->name
, cred
->name
);
2801 oldest
->created
= t
;
2805 if (t
< oldest
->created
) {
2806 fstrcpy(oldest
->name
, cred
->name
);
2807 oldest
->created
= t
;
2811 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
2812 status
= NT_STATUS_OK
;
2814 status
= NT_STATUS_UNSUCCESSFUL
;
2817 SAFE_FREE(wcache_cred_list
);
2823 /* Change the global online/offline state. */
2824 bool set_global_winbindd_state_offline(void)
2828 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
2830 /* Only go offline if someone has created
2831 the key "WINBINDD_OFFLINE" in the cache tdb. */
2833 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
2834 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
2838 if (!lp_winbind_offline_logon()) {
2839 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
2843 if (global_winbindd_offline_state
) {
2844 /* Already offline. */
2848 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
2850 if (!data
.dptr
|| data
.dsize
!= 4) {
2851 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
2852 SAFE_FREE(data
.dptr
);
2855 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
2856 global_winbindd_offline_state
= true;
2857 SAFE_FREE(data
.dptr
);
2862 void set_global_winbindd_state_online(void)
2864 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
2866 if (!lp_winbind_offline_logon()) {
2867 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
2871 if (!global_winbindd_offline_state
) {
2872 /* Already online. */
2875 global_winbindd_offline_state
= false;
2881 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
2882 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
2885 bool get_global_winbindd_state_offline(void)
2887 return global_winbindd_offline_state
;
2890 /***********************************************************************
2891 Validate functions for all possible cache tdb keys.
2892 ***********************************************************************/
2894 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
2895 struct tdb_validation_status
*state
)
2897 struct cache_entry
*centry
;
2899 centry
= SMB_XMALLOC_P(struct cache_entry
);
2900 centry
->data
= (unsigned char *)memdup(data
.dptr
, data
.dsize
);
2901 if (!centry
->data
) {
2905 centry
->len
= data
.dsize
;
2908 if (centry
->len
< 8) {
2909 /* huh? corrupt cache? */
2910 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr
));
2911 centry_free(centry
);
2912 state
->bad_entry
= true;
2913 state
->success
= false;
2917 centry
->status
= NT_STATUS(centry_uint32(centry
));
2918 centry
->sequence_number
= centry_uint32(centry
);
2922 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2923 struct tdb_validation_status
*state
)
2925 if (dbuf
.dsize
!= 8) {
2926 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
2927 keystr
, (unsigned int)dbuf
.dsize
));
2928 state
->bad_entry
= true;
2934 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2935 struct tdb_validation_status
*state
)
2937 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
2942 (void)centry_uint32(centry
);
2943 if (NT_STATUS_IS_OK(centry
->status
)) {
2945 (void)centry_sid(centry
, mem_ctx
, &sid
);
2948 centry_free(centry
);
2950 if (!(state
->success
)) {
2953 DEBUG(10,("validate_ns: %s ok\n", keystr
));
2957 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2958 struct tdb_validation_status
*state
)
2960 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
2965 if (NT_STATUS_IS_OK(centry
->status
)) {
2966 (void)centry_uint32(centry
);
2967 (void)centry_string(centry
, mem_ctx
);
2968 (void)centry_string(centry
, mem_ctx
);
2971 centry_free(centry
);
2973 if (!(state
->success
)) {
2976 DEBUG(10,("validate_sn: %s ok\n", keystr
));
2980 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2981 struct tdb_validation_status
*state
)
2983 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
2990 (void)centry_string(centry
, mem_ctx
);
2991 (void)centry_string(centry
, mem_ctx
);
2992 (void)centry_string(centry
, mem_ctx
);
2993 (void)centry_string(centry
, mem_ctx
);
2994 (void)centry_uint32(centry
);
2995 (void)centry_sid(centry
, mem_ctx
, &sid
);
2996 (void)centry_sid(centry
, mem_ctx
, &sid
);
2998 centry_free(centry
);
3000 if (!(state
->success
)) {
3003 DEBUG(10,("validate_u: %s ok\n", keystr
));
3007 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3008 struct tdb_validation_status
*state
)
3010 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3016 (void)centry_nttime(centry
);
3017 (void)centry_nttime(centry
);
3018 (void)centry_uint16(centry
);
3020 centry_free(centry
);
3022 if (!(state
->success
)) {
3025 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3029 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3030 struct tdb_validation_status
*state
)
3032 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3038 (void)centry_uint16(centry
);
3039 (void)centry_uint16(centry
);
3040 (void)centry_uint32(centry
);
3041 (void)centry_nttime(centry
);
3042 (void)centry_nttime(centry
);
3044 centry_free(centry
);
3046 if (!(state
->success
)) {
3049 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3053 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3054 struct tdb_validation_status
*state
)
3056 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3062 (void)centry_time(centry
);
3063 (void)centry_hash16(centry
, mem_ctx
);
3065 /* We only have 17 bytes more data in the salted cred case. */
3066 if (centry
->len
- centry
->ofs
== 17) {
3067 (void)centry_hash16(centry
, mem_ctx
);
3070 centry_free(centry
);
3072 if (!(state
->success
)) {
3075 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3079 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3080 struct tdb_validation_status
*state
)
3082 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3083 int32 num_entries
, i
;
3089 num_entries
= (int32
)centry_uint32(centry
);
3091 for (i
=0; i
< num_entries
; i
++) {
3093 (void)centry_string(centry
, mem_ctx
);
3094 (void)centry_string(centry
, mem_ctx
);
3095 (void)centry_string(centry
, mem_ctx
);
3096 (void)centry_string(centry
, mem_ctx
);
3097 (void)centry_sid(centry
, mem_ctx
, &sid
);
3098 (void)centry_sid(centry
, mem_ctx
, &sid
);
3101 centry_free(centry
);
3103 if (!(state
->success
)) {
3106 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3110 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3111 struct tdb_validation_status
*state
)
3113 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3114 int32 num_entries
, i
;
3120 num_entries
= centry_uint32(centry
);
3122 for (i
=0; i
< num_entries
; i
++) {
3123 (void)centry_string(centry
, mem_ctx
);
3124 (void)centry_string(centry
, mem_ctx
);
3125 (void)centry_uint32(centry
);
3128 centry_free(centry
);
3130 if (!(state
->success
)) {
3133 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3137 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3138 struct tdb_validation_status
*state
)
3140 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3141 int32 num_groups
, i
;
3147 num_groups
= centry_uint32(centry
);
3149 for (i
=0; i
< num_groups
; i
++) {
3151 centry_sid(centry
, mem_ctx
, &sid
);
3154 centry_free(centry
);
3156 if (!(state
->success
)) {
3159 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3163 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3164 struct tdb_validation_status
*state
)
3166 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3167 int32 num_aliases
, i
;
3173 num_aliases
= centry_uint32(centry
);
3175 for (i
=0; i
< num_aliases
; i
++) {
3176 (void)centry_uint32(centry
);
3179 centry_free(centry
);
3181 if (!(state
->success
)) {
3184 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3188 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3189 struct tdb_validation_status
*state
)
3191 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3198 num_names
= centry_uint32(centry
);
3200 for (i
=0; i
< num_names
; i
++) {
3202 centry_sid(centry
, mem_ctx
, &sid
);
3203 (void)centry_string(centry
, mem_ctx
);
3204 (void)centry_uint32(centry
);
3207 centry_free(centry
);
3209 if (!(state
->success
)) {
3212 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3216 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3217 struct tdb_validation_status
*state
)
3219 /* Can't say anything about this other than must be nonzero. */
3220 if (dbuf
.dsize
== 0) {
3221 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3223 state
->bad_entry
= true;
3224 state
->success
= false;
3228 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3232 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3233 struct tdb_validation_status
*state
)
3235 /* Can't say anything about this other than must be nonzero. */
3236 if (dbuf
.dsize
== 0) {
3237 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3239 state
->bad_entry
= true;
3240 state
->success
= false;
3244 DEBUG(10,("validate_de: %s ok\n", keystr
));
3248 static int validate_pwinfo(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3249 TDB_DATA dbuf
, struct tdb_validation_status
*state
)
3251 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3257 (void)centry_string(centry
, mem_ctx
);
3258 (void)centry_string(centry
, mem_ctx
);
3259 (void)centry_string(centry
, mem_ctx
);
3260 (void)centry_uint32(centry
);
3262 centry_free(centry
);
3264 if (!(state
->success
)) {
3267 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3271 static int validate_trustdoms(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3272 struct tdb_validation_status
*state
)
3274 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3275 int32 num_domains
, i
;
3281 num_domains
= centry_uint32(centry
);
3283 for (i
=0; i
< num_domains
; i
++) {
3285 (void)centry_string(centry
, mem_ctx
);
3286 (void)centry_string(centry
, mem_ctx
);
3287 (void)centry_sid(centry
, mem_ctx
, &sid
);
3290 centry_free(centry
);
3292 if (!(state
->success
)) {
3295 DEBUG(10,("validate_trustdoms: %s ok\n", keystr
));
3299 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3301 struct tdb_validation_status
*state
)
3303 if (dbuf
.dsize
== 0) {
3304 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3305 "key %s (len ==0) ?\n", keystr
));
3306 state
->bad_entry
= true;
3307 state
->success
= false;
3311 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3312 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3316 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3317 struct tdb_validation_status
*state
)
3319 if (dbuf
.dsize
!= 4) {
3320 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3321 keystr
, (unsigned int)dbuf
.dsize
));
3322 state
->bad_entry
= true;
3323 state
->success
= false;
3326 DEBUG(10,("validate_offline: %s ok\n", keystr
));
3330 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3331 struct tdb_validation_status
*state
)
3333 if (dbuf
.dsize
!= 4) {
3334 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3335 "key %s (len %u != 4) ?\n",
3336 keystr
, (unsigned int)dbuf
.dsize
));
3337 state
->bad_entry
= true;
3338 state
->success
= false;
3342 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
3346 /***********************************************************************
3347 A list of all possible cache tdb keys with associated validation
3349 ***********************************************************************/
3351 struct key_val_struct
{
3352 const char *keyname
;
3353 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
3355 {"SEQNUM/", validate_seqnum
},
3356 {"NS/", validate_ns
},
3357 {"SN/", validate_sn
},
3359 {"LOC_POL/", validate_loc_pol
},
3360 {"PWD_POL/", validate_pwd_pol
},
3361 {"CRED/", validate_cred
},
3362 {"UL/", validate_ul
},
3363 {"GL/", validate_gl
},
3364 {"UG/", validate_ug
},
3365 {"UA", validate_ua
},
3366 {"GM/", validate_gm
},
3367 {"DR/", validate_dr
},
3368 {"DE/", validate_de
},
3369 {"NSS/PWINFO/", validate_pwinfo
},
3370 {"TRUSTDOMS/", validate_trustdoms
},
3371 {"TRUSTDOMCACHE/", validate_trustdomcache
},
3372 {"WINBINDD_OFFLINE", validate_offline
},
3373 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
3377 /***********************************************************************
3378 Function to look at every entry in the tdb and validate it as far as
3380 ***********************************************************************/
3382 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
3385 unsigned int max_key_len
= 1024;
3386 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
3388 /* Paranoia check. */
3389 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0) {
3390 max_key_len
= 1024 * 1024;
3392 if (kbuf
.dsize
> max_key_len
) {
3393 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
3395 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
3399 for (i
= 0; key_val
[i
].keyname
; i
++) {
3400 size_t namelen
= strlen(key_val
[i
].keyname
);
3401 if (kbuf
.dsize
>= namelen
&& (
3402 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
3403 TALLOC_CTX
*mem_ctx
;
3407 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
3411 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
3412 keystr
[kbuf
.dsize
] = '\0';
3414 mem_ctx
= talloc_init("validate_ctx");
3420 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
3424 talloc_destroy(mem_ctx
);
3429 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
3430 dump_data(0, (uint8
*)kbuf
.dptr
, kbuf
.dsize
);
3431 DEBUG(0,("data :\n"));
3432 dump_data(0, (uint8
*)dbuf
.dptr
, dbuf
.dsize
);
3433 v_state
->unknown_key
= true;
3434 v_state
->success
= false;
3435 return 1; /* terminate. */
3438 static void validate_panic(const char *const why
)
3440 DEBUG(0,("validating cache: would panic %s\n", why
));
3441 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
3445 /***********************************************************************
3446 Try and validate every entry in the winbindd cache. If we fail here,
3447 delete the cache tdb and return non-zero.
3448 ***********************************************************************/
3450 int winbindd_validate_cache(void)
3453 const char *tdb_path
= lock_path("winbindd_cache.tdb");
3454 TDB_CONTEXT
*tdb
= NULL
;
3456 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3457 smb_panic_fn
= validate_panic
;
3460 tdb
= tdb_open_log(tdb_path
,
3461 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3462 ( lp_winbind_offline_logon()
3464 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
3468 DEBUG(0, ("winbindd_validate_cache: "
3469 "error opening/initializing tdb\n"));
3474 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
3477 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
3478 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
3483 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
3484 smb_panic_fn
= smb_panic
;
3488 /***********************************************************************
3489 Try and validate every entry in the winbindd cache.
3490 ***********************************************************************/
3492 int winbindd_validate_cache_nobackup(void)
3495 const char *tdb_path
= lock_path("winbindd_cache.tdb");
3497 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3498 smb_panic_fn
= validate_panic
;
3501 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3502 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
3504 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
3508 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
3512 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
3514 smb_panic_fn
= smb_panic
;
3518 bool winbindd_cache_validate_and_initialize(void)
3520 close_winbindd_cache();
3522 if (lp_winbind_offline_logon()) {
3523 if (winbindd_validate_cache() < 0) {
3524 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
3525 "could be restored.\n"));
3529 return initialize_winbindd_cache();
3532 /*********************************************************************
3533 ********************************************************************/
3535 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
3536 struct winbindd_tdc_domain
**domains
,
3537 size_t *num_domains
)
3539 struct winbindd_tdc_domain
*list
= NULL
;
3542 bool set_only
= false;
3544 /* don't allow duplicates */
3549 for ( i
=0; i
< (*num_domains
); i
++ ) {
3550 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
3551 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
3562 list
= TALLOC_ARRAY( NULL
, struct winbindd_tdc_domain
, 1 );
3565 list
= TALLOC_REALLOC_ARRAY( *domains
, *domains
,
3566 struct winbindd_tdc_domain
,
3571 ZERO_STRUCT( list
[idx
] );
3577 list
[idx
].domain_name
= talloc_strdup( list
, new_dom
->name
);
3578 list
[idx
].dns_name
= talloc_strdup( list
, new_dom
->alt_name
);
3580 if ( !is_null_sid( &new_dom
->sid
) ) {
3581 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
3583 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
3586 if ( new_dom
->domain_flags
!= 0x0 )
3587 list
[idx
].trust_flags
= new_dom
->domain_flags
;
3589 if ( new_dom
->domain_type
!= 0x0 )
3590 list
[idx
].trust_type
= new_dom
->domain_type
;
3592 if ( new_dom
->domain_trust_attribs
!= 0x0 )
3593 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
3597 *num_domains
= idx
+ 1;
3603 /*********************************************************************
3604 ********************************************************************/
3606 static TDB_DATA
make_tdc_key( const char *domain_name
)
3608 char *keystr
= NULL
;
3609 TDB_DATA key
= { NULL
, 0 };
3611 if ( !domain_name
) {
3612 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
3617 asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
);
3618 key
= string_term_tdb_data(keystr
);
3623 /*********************************************************************
3624 ********************************************************************/
3626 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
3628 unsigned char **buf
)
3630 unsigned char *buffer
= NULL
;
3635 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
3643 /* Store the number of array items first */
3644 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
3647 /* now pack each domain trust record */
3648 for ( i
=0; i
<num_domains
; i
++ ) {
3653 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
3654 domains
[i
].domain_name
,
3655 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
3658 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
3659 domains
[i
].domain_name
,
3660 domains
[i
].dns_name
,
3661 sid_to_fstring(tmp
, &domains
[i
].sid
),
3662 domains
[i
].trust_flags
,
3663 domains
[i
].trust_attribs
,
3664 domains
[i
].trust_type
);
3667 if ( buflen
< len
) {
3669 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
3670 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
3684 /*********************************************************************
3685 ********************************************************************/
3687 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
3688 struct winbindd_tdc_domain
**domains
)
3690 fstring domain_name
, dns_name
, sid_string
;
3691 uint32 type
, attribs
, flags
;
3695 struct winbindd_tdc_domain
*list
= NULL
;
3697 /* get the number of domains */
3698 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
3700 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3704 list
= TALLOC_ARRAY( NULL
, struct winbindd_tdc_domain
, num_domains
);
3706 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
3710 for ( i
=0; i
<num_domains
; i
++ ) {
3711 len
+= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
3720 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3721 TALLOC_FREE( list
);
3725 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
3726 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
3727 domain_name
, dns_name
, sid_string
,
3728 flags
, attribs
, type
));
3730 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
3731 list
[i
].dns_name
= talloc_strdup( list
, dns_name
);
3732 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
3733 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
3736 list
[i
].trust_flags
= flags
;
3737 list
[i
].trust_attribs
= attribs
;
3738 list
[i
].trust_type
= type
;
3746 /*********************************************************************
3747 ********************************************************************/
3749 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
3751 TDB_DATA key
= make_tdc_key( lp_workgroup() );
3752 TDB_DATA data
= { NULL
, 0 };
3758 /* See if we were asked to delete the cache entry */
3761 ret
= tdb_delete( wcache
->tdb
, key
);
3765 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
3772 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
3775 SAFE_FREE( data
.dptr
);
3776 SAFE_FREE( key
.dptr
);
3778 return ( ret
!= -1 );
3781 /*********************************************************************
3782 ********************************************************************/
3784 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
3786 TDB_DATA key
= make_tdc_key( lp_workgroup() );
3787 TDB_DATA data
= { NULL
, 0 };
3795 data
= tdb_fetch( wcache
->tdb
, key
);
3797 SAFE_FREE( key
.dptr
);
3802 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
3804 SAFE_FREE( data
.dptr
);
3812 /*********************************************************************
3813 ********************************************************************/
3815 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
3817 struct winbindd_tdc_domain
*dom_list
= NULL
;
3818 size_t num_domains
= 0;
3821 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
3822 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
3823 domain
->name
, domain
->alt_name
,
3824 sid_string_dbg(&domain
->sid
),
3825 domain
->domain_flags
,
3826 domain
->domain_trust_attribs
,
3827 domain
->domain_type
));
3829 if ( !init_wcache() ) {
3833 /* fetch the list */
3835 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
3837 /* add the new domain */
3839 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
3843 /* pack the domain */
3845 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
3853 TALLOC_FREE( dom_list
);
3858 /*********************************************************************
3859 ********************************************************************/
3861 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
3863 struct winbindd_tdc_domain
*dom_list
= NULL
;
3864 size_t num_domains
= 0;
3866 struct winbindd_tdc_domain
*d
= NULL
;
3868 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
3870 if ( !init_wcache() ) {
3874 /* fetch the list */
3876 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
3878 for ( i
=0; i
<num_domains
; i
++ ) {
3879 if ( strequal(name
, dom_list
[i
].domain_name
) ||
3880 strequal(name
, dom_list
[i
].dns_name
) )
3882 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
3885 d
= TALLOC_P( ctx
, struct winbindd_tdc_domain
);
3889 d
->domain_name
= talloc_strdup( d
, dom_list
[i
].domain_name
);
3890 d
->dns_name
= talloc_strdup( d
, dom_list
[i
].dns_name
);
3891 sid_copy( &d
->sid
, &dom_list
[i
].sid
);
3892 d
->trust_flags
= dom_list
[i
].trust_flags
;
3893 d
->trust_type
= dom_list
[i
].trust_type
;
3894 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
3900 TALLOC_FREE( dom_list
);
3906 /*********************************************************************
3907 ********************************************************************/
3909 void wcache_tdc_clear( void )
3911 if ( !init_wcache() )
3914 wcache_tdc_store_list( NULL
, 0 );
3920 /*********************************************************************
3921 ********************************************************************/
3923 static void wcache_save_user_pwinfo(struct winbindd_domain
*domain
,
3925 const DOM_SID
*user_sid
,
3926 const char *homedir
,
3931 struct cache_entry
*centry
;
3934 if ( (centry
= centry_start(domain
, status
)) == NULL
)
3937 centry_put_string( centry
, homedir
);
3938 centry_put_string( centry
, shell
);
3939 centry_put_string( centry
, gecos
);
3940 centry_put_uint32( centry
, gid
);
3942 centry_end(centry
, "NSS/PWINFO/%s", sid_to_fstring(tmp
, user_sid
) );
3944 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid
) ));
3946 centry_free(centry
);
3949 NTSTATUS
nss_get_info_cached( struct winbindd_domain
*domain
,
3950 const DOM_SID
*user_sid
,
3952 ADS_STRUCT
*ads
, LDAPMessage
*msg
,
3953 char **homedir
, char **shell
, char **gecos
,
3956 struct winbind_cache
*cache
= get_cache(domain
);
3957 struct cache_entry
*centry
= NULL
;
3964 centry
= wcache_fetch(cache
, domain
, "NSS/PWINFO/%s",
3965 sid_to_fstring(tmp
, user_sid
));
3970 *homedir
= centry_string( centry
, ctx
);
3971 *shell
= centry_string( centry
, ctx
);
3972 *gecos
= centry_string( centry
, ctx
);
3973 *p_gid
= centry_uint32( centry
);
3975 centry_free(centry
);
3977 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
3978 sid_string_dbg(user_sid
)));
3980 return NT_STATUS_OK
;
3984 nt_status
= nss_get_info( domain
->name
, user_sid
, ctx
, ads
, msg
,
3985 homedir
, shell
, gecos
, p_gid
);
3987 if ( NT_STATUS_IS_OK(nt_status
) ) {
3988 wcache_save_user_pwinfo( domain
, nt_status
, user_sid
,
3989 *homedir
, *shell
, *gecos
, *p_gid
);
3992 if ( NT_STATUS_EQUAL( nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
3993 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
3995 set_domain_offline( domain
);
4002 /* the cache backend methods are exposed via this structure */
4003 struct winbindd_methods cache_methods
= {