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 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain
->name
));
494 /* try to get the sequence number from the tdb cache first */
495 /* this will update the timestamp as well */
497 status
= fetch_cache_seqnum( domain
, t
);
498 if ( NT_STATUS_IS_OK(status
) )
501 /* important! make sure that we know if this is a native
502 mode domain or not. And that we can contact it. */
504 if ( winbindd_can_contact_domain( domain
) ) {
505 struct winbindd_methods
*orig_backend
= domain
->backend
;
506 status
= domain
->backend
->sequence_number(domain
,
507 &domain
->sequence_number
);
508 if (domain
->backend
!= orig_backend
) {
510 status
= domain
->backend
->sequence_number(domain
,
511 &domain
->sequence_number
);
514 /* just use the current time */
515 status
= NT_STATUS_OK
;
516 domain
->sequence_number
= time(NULL
);
520 /* the above call could have set our domain->backend to NULL when
521 * coming from offline to online mode, make sure to reinitialize the
522 * backend - Guenther */
525 if (!NT_STATUS_IS_OK(status
)) {
526 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status
)));
527 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
530 domain
->last_status
= status
;
531 domain
->last_seq_check
= time(NULL
);
533 /* save the new sequence number in the cache */
534 store_cache_seqnum( domain
);
537 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
538 domain
->name
, domain
->sequence_number
));
544 decide if a cache entry has expired
546 static bool centry_expired(struct winbindd_domain
*domain
, const char *keystr
, struct cache_entry
*centry
)
548 /* If we've been told to be offline - stay in that state... */
549 if (lp_winbind_offline_logon() && global_winbindd_offline_state
) {
550 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
551 keystr
, domain
->name
));
555 /* when the domain is offline return the cached entry.
556 * This deals with transient offline states... */
558 if (!domain
->online
) {
559 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
560 keystr
, domain
->name
));
564 /* if the server is OK and our cache entry came from when it was down then
565 the entry is invalid */
566 if ((domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
567 (centry
->sequence_number
== DOM_SEQUENCE_NONE
)) {
568 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
569 keystr
, domain
->name
));
573 /* if the server is down or the cache entry is not older than the
574 current sequence number then it is OK */
575 if (wcache_server_down(domain
) ||
576 centry
->sequence_number
== domain
->sequence_number
) {
577 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
578 keystr
, domain
->name
));
582 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
583 keystr
, domain
->name
));
589 static struct cache_entry
*wcache_fetch_raw(char *kstr
)
592 struct cache_entry
*centry
;
595 key
= string_tdb_data(kstr
);
596 data
= tdb_fetch(wcache
->tdb
, key
);
602 centry
= SMB_XMALLOC_P(struct cache_entry
);
603 centry
->data
= (unsigned char *)data
.dptr
;
604 centry
->len
= data
.dsize
;
607 if (centry
->len
< 8) {
608 /* huh? corrupt cache? */
609 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr
));
614 centry
->status
= centry_ntstatus(centry
);
615 centry
->sequence_number
= centry_uint32(centry
);
621 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
622 number and return status
624 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
625 struct winbindd_domain
*domain
,
626 const char *format
, ...) PRINTF_ATTRIBUTE(3,4);
627 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
628 struct winbindd_domain
*domain
,
629 const char *format
, ...)
633 struct cache_entry
*centry
;
639 refresh_sequence_number(domain
, false);
641 va_start(ap
, format
);
642 smb_xvasprintf(&kstr
, format
, ap
);
645 centry
= wcache_fetch_raw(kstr
);
646 if (centry
== NULL
) {
651 if (centry_expired(domain
, kstr
, centry
)) {
653 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
654 kstr
, domain
->name
));
661 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
662 kstr
, domain
->name
));
668 static void wcache_delete(const char *format
, ...) PRINTF_ATTRIBUTE(1,2);
669 static void wcache_delete(const char *format
, ...)
675 va_start(ap
, format
);
676 smb_xvasprintf(&kstr
, format
, ap
);
679 key
= string_tdb_data(kstr
);
681 tdb_delete(wcache
->tdb
, key
);
686 make sure we have at least len bytes available in a centry
688 static void centry_expand(struct cache_entry
*centry
, uint32 len
)
690 if (centry
->len
- centry
->ofs
>= len
)
693 centry
->data
= SMB_REALLOC_ARRAY(centry
->data
, unsigned char,
696 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry
->len
));
697 smb_panic_fn("out of memory in centry_expand");
702 push a uint32 into a centry
704 static void centry_put_uint32(struct cache_entry
*centry
, uint32 v
)
706 centry_expand(centry
, 4);
707 SIVAL(centry
->data
, centry
->ofs
, v
);
712 push a uint16 into a centry
714 static void centry_put_uint16(struct cache_entry
*centry
, uint16 v
)
716 centry_expand(centry
, 2);
717 SIVAL(centry
->data
, centry
->ofs
, v
);
722 push a uint8 into a centry
724 static void centry_put_uint8(struct cache_entry
*centry
, uint8 v
)
726 centry_expand(centry
, 1);
727 SCVAL(centry
->data
, centry
->ofs
, v
);
732 push a string into a centry
734 static void centry_put_string(struct cache_entry
*centry
, const char *s
)
739 /* null strings are marked as len 0xFFFF */
740 centry_put_uint8(centry
, 0xFF);
745 /* can't handle more than 254 char strings. Truncating is probably best */
747 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len
));
750 centry_put_uint8(centry
, len
);
751 centry_expand(centry
, len
);
752 memcpy(centry
->data
+ centry
->ofs
, s
, len
);
757 push a 16 byte hash into a centry - treat as 16 byte string.
759 static void centry_put_hash16(struct cache_entry
*centry
, const uint8 val
[16])
761 centry_put_uint8(centry
, 16);
762 centry_expand(centry
, 16);
763 memcpy(centry
->data
+ centry
->ofs
, val
, 16);
767 static void centry_put_sid(struct cache_entry
*centry
, const DOM_SID
*sid
)
770 centry_put_string(centry
, sid_to_fstring(sid_string
, sid
));
775 put NTSTATUS into a centry
777 static void centry_put_ntstatus(struct cache_entry
*centry
, NTSTATUS status
)
779 uint32 status_value
= NT_STATUS_V(status
);
780 centry_put_uint32(centry
, status_value
);
785 push a NTTIME into a centry
787 static void centry_put_nttime(struct cache_entry
*centry
, NTTIME nt
)
789 centry_expand(centry
, 8);
790 SIVAL(centry
->data
, centry
->ofs
, nt
& 0xFFFFFFFF);
792 SIVAL(centry
->data
, centry
->ofs
, nt
>> 32);
797 push a time_t into a centry - use a 64 bit size.
798 NTTIME here is being used as a convenient 64-bit size.
800 static void centry_put_time(struct cache_entry
*centry
, time_t t
)
802 NTTIME nt
= (NTTIME
)t
;
803 centry_put_nttime(centry
, nt
);
807 start a centry for output. When finished, call centry_end()
809 struct cache_entry
*centry_start(struct winbindd_domain
*domain
, NTSTATUS status
)
811 struct cache_entry
*centry
;
816 centry
= SMB_XMALLOC_P(struct cache_entry
);
818 centry
->len
= 8192; /* reasonable default */
819 centry
->data
= SMB_XMALLOC_ARRAY(uint8
, centry
->len
);
821 centry
->sequence_number
= domain
->sequence_number
;
822 centry_put_ntstatus(centry
, status
);
823 centry_put_uint32(centry
, centry
->sequence_number
);
828 finish a centry and write it to the tdb
830 static void centry_end(struct cache_entry
*centry
, const char *format
, ...) PRINTF_ATTRIBUTE(2,3);
831 static void centry_end(struct cache_entry
*centry
, const char *format
, ...)
841 va_start(ap
, format
);
842 smb_xvasprintf(&kstr
, format
, ap
);
845 key
= string_tdb_data(kstr
);
846 data
.dptr
= centry
->data
;
847 data
.dsize
= centry
->ofs
;
849 tdb_store(wcache
->tdb
, key
, data
, TDB_REPLACE
);
853 static void wcache_save_name_to_sid(struct winbindd_domain
*domain
,
854 NTSTATUS status
, const char *domain_name
,
855 const char *name
, const DOM_SID
*sid
,
856 enum lsa_SidType type
)
858 struct cache_entry
*centry
;
861 centry
= centry_start(domain
, status
);
864 centry_put_uint32(centry
, type
);
865 centry_put_sid(centry
, sid
);
866 fstrcpy(uname
, name
);
868 centry_end(centry
, "NS/%s/%s", domain_name
, uname
);
869 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s (%s)\n", domain_name
,
870 uname
, sid_string_dbg(sid
), nt_errstr(status
)));
874 static void wcache_save_sid_to_name(struct winbindd_domain
*domain
, NTSTATUS status
,
875 const DOM_SID
*sid
, const char *domain_name
, const char *name
, enum lsa_SidType type
)
877 struct cache_entry
*centry
;
880 centry
= centry_start(domain
, status
);
884 if (NT_STATUS_IS_OK(status
)) {
885 centry_put_uint32(centry
, type
);
886 centry_put_string(centry
, domain_name
);
887 centry_put_string(centry
, name
);
890 centry_end(centry
, "SN/%s", sid_to_fstring(sid_string
, sid
));
891 DEBUG(10,("wcache_save_sid_to_name: %s -> %s (%s)\n", sid_string
,
892 name
, nt_errstr(status
)));
897 static void wcache_save_user(struct winbindd_domain
*domain
, NTSTATUS status
, WINBIND_USERINFO
*info
)
899 struct cache_entry
*centry
;
902 if (is_null_sid(&info
->user_sid
)) {
906 centry
= centry_start(domain
, status
);
909 centry_put_string(centry
, info
->acct_name
);
910 centry_put_string(centry
, info
->full_name
);
911 centry_put_string(centry
, info
->homedir
);
912 centry_put_string(centry
, info
->shell
);
913 centry_put_uint32(centry
, info
->primary_gid
);
914 centry_put_sid(centry
, &info
->user_sid
);
915 centry_put_sid(centry
, &info
->group_sid
);
916 centry_end(centry
, "U/%s", sid_to_fstring(sid_string
,
918 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string
, info
->acct_name
));
922 static void wcache_save_lockout_policy(struct winbindd_domain
*domain
,
924 struct samr_DomInfo12
*lockout_policy
)
926 struct cache_entry
*centry
;
928 centry
= centry_start(domain
, status
);
932 centry_put_nttime(centry
, lockout_policy
->lockout_duration
);
933 centry_put_nttime(centry
, lockout_policy
->lockout_window
);
934 centry_put_uint16(centry
, lockout_policy
->lockout_threshold
);
936 centry_end(centry
, "LOC_POL/%s", domain
->name
);
938 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain
->name
));
943 static void wcache_save_password_policy(struct winbindd_domain
*domain
,
945 struct samr_DomInfo1
*policy
)
947 struct cache_entry
*centry
;
949 centry
= centry_start(domain
, status
);
953 centry_put_uint16(centry
, policy
->min_password_length
);
954 centry_put_uint16(centry
, policy
->password_history_length
);
955 centry_put_uint32(centry
, policy
->password_properties
);
956 centry_put_nttime(centry
, policy
->max_password_age
);
957 centry_put_nttime(centry
, policy
->min_password_age
);
959 centry_end(centry
, "PWD_POL/%s", domain
->name
);
961 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
966 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const DOM_SID
*sid
)
968 struct winbind_cache
*cache
= get_cache(domain
);
970 fstring key_str
, tmp
;
974 return NT_STATUS_INTERNAL_DB_ERROR
;
977 if (is_null_sid(sid
)) {
978 return NT_STATUS_INVALID_SID
;
981 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
982 return NT_STATUS_INVALID_SID
;
985 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
987 data
= tdb_fetch(cache
->tdb
, string_tdb_data(key_str
));
989 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
992 SAFE_FREE(data
.dptr
);
996 /* Lookup creds for a SID - copes with old (unsalted) creds as well
997 as new salted ones. */
999 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
1000 TALLOC_CTX
*mem_ctx
,
1002 const uint8
**cached_nt_pass
,
1003 const uint8
**cached_salt
)
1005 struct winbind_cache
*cache
= get_cache(domain
);
1006 struct cache_entry
*centry
= NULL
;
1013 return NT_STATUS_INTERNAL_DB_ERROR
;
1016 if (is_null_sid(sid
)) {
1017 return NT_STATUS_INVALID_SID
;
1020 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1021 return NT_STATUS_INVALID_SID
;
1024 /* Try and get a salted cred first. If we can't
1025 fall back to an unsalted cred. */
1027 centry
= wcache_fetch(cache
, domain
, "CRED/%s",
1028 sid_to_fstring(tmp
, sid
));
1030 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1031 sid_string_dbg(sid
)));
1032 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1035 t
= centry_time(centry
);
1037 /* In the salted case this isn't actually the nt_hash itself,
1038 but the MD5 of the salt + nt_hash. Let the caller
1039 sort this out. It can tell as we only return the cached_salt
1040 if we are returning a salted cred. */
1042 *cached_nt_pass
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1043 if (*cached_nt_pass
== NULL
) {
1046 sid_to_fstring(sidstr
, sid
);
1048 /* Bad (old) cred cache. Delete and pretend we
1050 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1052 wcache_delete("CRED/%s", sidstr
);
1053 centry_free(centry
);
1054 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1057 /* We only have 17 bytes more data in the salted cred case. */
1058 if (centry
->len
- centry
->ofs
== 17) {
1059 *cached_salt
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1061 *cached_salt
= NULL
;
1064 dump_data_pw("cached_nt_pass", *cached_nt_pass
, NT_HASH_LEN
);
1066 dump_data_pw("cached_salt", *cached_salt
, NT_HASH_LEN
);
1069 status
= centry
->status
;
1071 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1072 sid_string_dbg(sid
), nt_errstr(status
) ));
1074 centry_free(centry
);
1078 /* Store creds for a SID - only writes out new salted ones. */
1080 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1081 TALLOC_CTX
*mem_ctx
,
1083 const uint8 nt_pass
[NT_HASH_LEN
])
1085 struct cache_entry
*centry
;
1088 uint8 cred_salt
[NT_HASH_LEN
];
1089 uint8 salted_hash
[NT_HASH_LEN
];
1091 if (is_null_sid(sid
)) {
1092 return NT_STATUS_INVALID_SID
;
1095 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1096 return NT_STATUS_INVALID_SID
;
1099 centry
= centry_start(domain
, NT_STATUS_OK
);
1101 return NT_STATUS_INTERNAL_DB_ERROR
;
1104 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1106 centry_put_time(centry
, time(NULL
));
1108 /* Create a salt and then salt the hash. */
1109 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1110 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1112 centry_put_hash16(centry
, salted_hash
);
1113 centry_put_hash16(centry
, cred_salt
);
1114 centry_end(centry
, "CRED/%s", sid_to_fstring(sid_string
, sid
));
1116 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1118 centry_free(centry
);
1120 return NT_STATUS_OK
;
1124 /* Query display info. This is the basic user list fn */
1125 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
1126 TALLOC_CTX
*mem_ctx
,
1127 uint32
*num_entries
,
1128 WINBIND_USERINFO
**info
)
1130 struct winbind_cache
*cache
= get_cache(domain
);
1131 struct cache_entry
*centry
= NULL
;
1133 unsigned int i
, retry
;
1138 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1142 *num_entries
= centry_uint32(centry
);
1144 if (*num_entries
== 0)
1147 (*info
) = TALLOC_ARRAY(mem_ctx
, WINBIND_USERINFO
, *num_entries
);
1149 smb_panic_fn("query_user_list out of memory");
1151 for (i
=0; i
<(*num_entries
); i
++) {
1152 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
1153 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
1154 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
1155 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
1156 centry_sid(centry
, mem_ctx
, &(*info
)[i
].user_sid
);
1157 centry_sid(centry
, mem_ctx
, &(*info
)[i
].group_sid
);
1161 status
= centry
->status
;
1163 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1164 domain
->name
, nt_errstr(status
) ));
1166 centry_free(centry
);
1173 /* Return status value returned by seq number check */
1175 if (!NT_STATUS_IS_OK(domain
->last_status
))
1176 return domain
->last_status
;
1178 /* Put the query_user_list() in a retry loop. There appears to be
1179 * some bug either with Windows 2000 or Samba's handling of large
1180 * rpc replies. This manifests itself as sudden disconnection
1181 * at a random point in the enumeration of a large (60k) user list.
1182 * The retry loop simply tries the operation again. )-: It's not
1183 * pretty but an acceptable workaround until we work out what the
1184 * real problem is. */
1189 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1192 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
1193 if (!NT_STATUS_IS_OK(status
)) {
1194 DEBUG(3, ("query_user_list: returned 0x%08x, "
1195 "retrying\n", NT_STATUS_V(status
)));
1197 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1198 DEBUG(3, ("query_user_list: flushing "
1199 "connection cache\n"));
1200 invalidate_cm_connection(&domain
->conn
);
1203 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1207 refresh_sequence_number(domain
, false);
1208 centry
= centry_start(domain
, status
);
1211 centry_put_uint32(centry
, *num_entries
);
1212 for (i
=0; i
<(*num_entries
); i
++) {
1213 centry_put_string(centry
, (*info
)[i
].acct_name
);
1214 centry_put_string(centry
, (*info
)[i
].full_name
);
1215 centry_put_string(centry
, (*info
)[i
].homedir
);
1216 centry_put_string(centry
, (*info
)[i
].shell
);
1217 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1218 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1219 if (domain
->backend
&& domain
->backend
->consistent
) {
1220 /* when the backend is consistent we can pre-prime some mappings */
1221 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1223 (*info
)[i
].acct_name
,
1224 &(*info
)[i
].user_sid
,
1226 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1227 &(*info
)[i
].user_sid
,
1229 (*info
)[i
].acct_name
,
1231 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1234 centry_end(centry
, "UL/%s", domain
->name
);
1235 centry_free(centry
);
1241 /* list all domain groups */
1242 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
1243 TALLOC_CTX
*mem_ctx
,
1244 uint32
*num_entries
,
1245 struct acct_info
**info
)
1247 struct winbind_cache
*cache
= get_cache(domain
);
1248 struct cache_entry
*centry
= NULL
;
1255 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1259 *num_entries
= centry_uint32(centry
);
1261 if (*num_entries
== 0)
1264 (*info
) = TALLOC_ARRAY(mem_ctx
, struct acct_info
, *num_entries
);
1266 smb_panic_fn("enum_dom_groups out of memory");
1268 for (i
=0; i
<(*num_entries
); i
++) {
1269 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1270 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1271 (*info
)[i
].rid
= centry_uint32(centry
);
1275 status
= centry
->status
;
1277 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1278 domain
->name
, nt_errstr(status
) ));
1280 centry_free(centry
);
1287 /* Return status value returned by seq number check */
1289 if (!NT_STATUS_IS_OK(domain
->last_status
))
1290 return domain
->last_status
;
1292 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1295 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1298 refresh_sequence_number(domain
, false);
1299 centry
= centry_start(domain
, status
);
1302 centry_put_uint32(centry
, *num_entries
);
1303 for (i
=0; i
<(*num_entries
); i
++) {
1304 centry_put_string(centry
, (*info
)[i
].acct_name
);
1305 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1306 centry_put_uint32(centry
, (*info
)[i
].rid
);
1308 centry_end(centry
, "GL/%s/domain", domain
->name
);
1309 centry_free(centry
);
1315 /* list all domain groups */
1316 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
1317 TALLOC_CTX
*mem_ctx
,
1318 uint32
*num_entries
,
1319 struct acct_info
**info
)
1321 struct winbind_cache
*cache
= get_cache(domain
);
1322 struct cache_entry
*centry
= NULL
;
1329 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1333 *num_entries
= centry_uint32(centry
);
1335 if (*num_entries
== 0)
1338 (*info
) = TALLOC_ARRAY(mem_ctx
, struct acct_info
, *num_entries
);
1340 smb_panic_fn("enum_dom_groups out of memory");
1342 for (i
=0; i
<(*num_entries
); i
++) {
1343 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1344 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1345 (*info
)[i
].rid
= centry_uint32(centry
);
1350 /* If we are returning cached data and the domain controller
1351 is down then we don't know whether the data is up to date
1352 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1355 if (wcache_server_down(domain
)) {
1356 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1357 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1359 status
= centry
->status
;
1361 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1362 domain
->name
, nt_errstr(status
) ));
1364 centry_free(centry
);
1371 /* Return status value returned by seq number check */
1373 if (!NT_STATUS_IS_OK(domain
->last_status
))
1374 return domain
->last_status
;
1376 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1379 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1382 refresh_sequence_number(domain
, false);
1383 centry
= centry_start(domain
, status
);
1386 centry_put_uint32(centry
, *num_entries
);
1387 for (i
=0; i
<(*num_entries
); i
++) {
1388 centry_put_string(centry
, (*info
)[i
].acct_name
);
1389 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1390 centry_put_uint32(centry
, (*info
)[i
].rid
);
1392 centry_end(centry
, "GL/%s/local", domain
->name
);
1393 centry_free(centry
);
1399 /* convert a single name to a sid in a domain */
1400 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
1401 TALLOC_CTX
*mem_ctx
,
1402 enum winbindd_cmd orig_cmd
,
1403 const char *domain_name
,
1406 enum lsa_SidType
*type
)
1408 struct winbind_cache
*cache
= get_cache(domain
);
1409 struct cache_entry
*centry
= NULL
;
1416 fstrcpy(uname
, name
);
1418 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1422 status
= centry
->status
;
1423 if (NT_STATUS_IS_OK(status
)) {
1424 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1425 centry_sid(centry
, mem_ctx
, sid
);
1428 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: %s\n",
1429 domain
->name
, nt_errstr(status
) ));
1431 centry_free(centry
);
1437 /* If the seq number check indicated that there is a problem
1438 * with this DC, then return that status... except for
1439 * access_denied. This is special because the dc may be in
1440 * "restrict anonymous = 1" mode, in which case it will deny
1441 * most unauthenticated operations, but *will* allow the LSA
1442 * name-to-sid that we try as a fallback. */
1444 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1445 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1446 return domain
->last_status
;
1448 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1451 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, orig_cmd
,
1452 domain_name
, name
, sid
, type
);
1455 refresh_sequence_number(domain
, false);
1457 if (domain
->online
&&
1458 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1459 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1461 /* Only save the reverse mapping if this was not a UPN */
1462 if (!strchr(name
, '@')) {
1463 strupper_m(CONST_DISCARD(char *,domain_name
));
1464 strlower_m(CONST_DISCARD(char *,name
));
1465 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1472 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1474 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1475 TALLOC_CTX
*mem_ctx
,
1479 enum lsa_SidType
*type
)
1481 struct winbind_cache
*cache
= get_cache(domain
);
1482 struct cache_entry
*centry
= NULL
;
1489 centry
= wcache_fetch(cache
, domain
, "SN/%s",
1490 sid_to_fstring(sid_string
, sid
));
1494 status
= centry
->status
;
1495 if (NT_STATUS_IS_OK(status
)) {
1496 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1497 *domain_name
= centry_string(centry
, mem_ctx
);
1498 *name
= centry_string(centry
, mem_ctx
);
1501 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: %s\n",
1502 domain
->name
, nt_errstr(status
) ));
1504 centry_free(centry
);
1509 *domain_name
= NULL
;
1511 /* If the seq number check indicated that there is a problem
1512 * with this DC, then return that status... except for
1513 * access_denied. This is special because the dc may be in
1514 * "restrict anonymous = 1" mode, in which case it will deny
1515 * most unauthenticated operations, but *will* allow the LSA
1516 * sid-to-name that we try as a fallback. */
1518 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1519 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1520 return domain
->last_status
;
1522 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1525 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1528 refresh_sequence_number(domain
, false);
1529 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
1531 /* We can't save the name to sid mapping here, as with sid history a
1532 * later name2sid would give the wrong sid. */
1537 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
1538 TALLOC_CTX
*mem_ctx
,
1539 const DOM_SID
*domain_sid
,
1544 enum lsa_SidType
**types
)
1546 struct winbind_cache
*cache
= get_cache(domain
);
1548 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1552 *domain_name
= NULL
;
1560 if (num_rids
== 0) {
1561 return NT_STATUS_OK
;
1564 *names
= TALLOC_ARRAY(mem_ctx
, char *, num_rids
);
1565 *types
= TALLOC_ARRAY(mem_ctx
, enum lsa_SidType
, num_rids
);
1567 if ((*names
== NULL
) || (*types
== NULL
)) {
1568 result
= NT_STATUS_NO_MEMORY
;
1572 have_mapped
= have_unmapped
= false;
1574 for (i
=0; i
<num_rids
; i
++) {
1576 struct cache_entry
*centry
;
1579 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
1580 result
= NT_STATUS_INTERNAL_ERROR
;
1584 centry
= wcache_fetch(cache
, domain
, "SN/%s",
1585 sid_to_fstring(tmp
, &sid
));
1590 (*types
)[i
] = SID_NAME_UNKNOWN
;
1591 (*names
)[i
] = talloc_strdup(*names
, "");
1593 if (NT_STATUS_IS_OK(centry
->status
)) {
1596 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
1598 dom
= centry_string(centry
, mem_ctx
);
1599 if (*domain_name
== NULL
) {
1605 (*names
)[i
] = centry_string(centry
, *names
);
1607 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)) {
1608 have_unmapped
= true;
1611 /* something's definitely wrong */
1612 result
= centry
->status
;
1616 centry_free(centry
);
1620 return NT_STATUS_NONE_MAPPED
;
1622 if (!have_unmapped
) {
1623 return NT_STATUS_OK
;
1625 return STATUS_SOME_UNMAPPED
;
1629 TALLOC_FREE(*names
);
1630 TALLOC_FREE(*types
);
1632 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
1633 rids
, num_rids
, domain_name
,
1637 None of the queried rids has been found so save all negative entries
1639 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
1640 for (i
= 0; i
< num_rids
; i
++) {
1642 const char *name
= "";
1643 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
1644 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
1646 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
1647 return NT_STATUS_INTERNAL_ERROR
;
1650 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
1658 Some or all of the queried rids have been found.
1660 if (!NT_STATUS_IS_OK(result
) &&
1661 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
1665 refresh_sequence_number(domain
, false);
1667 for (i
=0; i
<num_rids
; i
++) {
1671 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
1672 result
= NT_STATUS_INTERNAL_ERROR
;
1676 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
1677 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
1679 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
1680 (*names
)[i
], (*types
)[i
]);
1687 TALLOC_FREE(*names
);
1688 TALLOC_FREE(*types
);
1692 /* Lookup user information from a rid */
1693 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
1694 TALLOC_CTX
*mem_ctx
,
1695 const DOM_SID
*user_sid
,
1696 WINBIND_USERINFO
*info
)
1698 struct winbind_cache
*cache
= get_cache(domain
);
1699 struct cache_entry
*centry
= NULL
;
1706 centry
= wcache_fetch(cache
, domain
, "U/%s",
1707 sid_to_fstring(tmp
, user_sid
));
1709 /* If we have an access denied cache entry and a cached info3 in the
1710 samlogon cache then do a query. This will force the rpc back end
1711 to return the info3 data. */
1713 if (NT_STATUS_V(domain
->last_status
) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED
) &&
1714 netsamlogon_cache_have(user_sid
)) {
1715 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1716 domain
->last_status
= NT_STATUS_OK
;
1717 centry_free(centry
);
1724 /* if status is not ok then this is a negative hit
1725 and the rest of the data doesn't matter */
1726 status
= centry
->status
;
1727 if (NT_STATUS_IS_OK(status
)) {
1728 info
->acct_name
= centry_string(centry
, mem_ctx
);
1729 info
->full_name
= centry_string(centry
, mem_ctx
);
1730 info
->homedir
= centry_string(centry
, mem_ctx
);
1731 info
->shell
= centry_string(centry
, mem_ctx
);
1732 info
->primary_gid
= centry_uint32(centry
);
1733 centry_sid(centry
, mem_ctx
, &info
->user_sid
);
1734 centry_sid(centry
, mem_ctx
, &info
->group_sid
);
1737 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: %s\n",
1738 domain
->name
, nt_errstr(status
) ));
1740 centry_free(centry
);
1746 /* Return status value returned by seq number check */
1748 if (!NT_STATUS_IS_OK(domain
->last_status
))
1749 return domain
->last_status
;
1751 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
1754 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
1757 refresh_sequence_number(domain
, false);
1758 wcache_save_user(domain
, status
, info
);
1764 /* Lookup groups a user is a member of. */
1765 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
1766 TALLOC_CTX
*mem_ctx
,
1767 const DOM_SID
*user_sid
,
1768 uint32
*num_groups
, DOM_SID
**user_gids
)
1770 struct winbind_cache
*cache
= get_cache(domain
);
1771 struct cache_entry
*centry
= NULL
;
1779 centry
= wcache_fetch(cache
, domain
, "UG/%s",
1780 sid_to_fstring(sid_string
, user_sid
));
1782 /* If we have an access denied cache entry and a cached info3 in the
1783 samlogon cache then do a query. This will force the rpc back end
1784 to return the info3 data. */
1786 if (NT_STATUS_V(domain
->last_status
) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED
) &&
1787 netsamlogon_cache_have(user_sid
)) {
1788 DEBUG(10, ("lookup_usergroups: cached access denied and have cached info3\n"));
1789 domain
->last_status
= NT_STATUS_OK
;
1790 centry_free(centry
);
1797 *num_groups
= centry_uint32(centry
);
1799 if (*num_groups
== 0)
1802 (*user_gids
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_groups
);
1803 if (! (*user_gids
)) {
1804 smb_panic_fn("lookup_usergroups out of memory");
1806 for (i
=0; i
<(*num_groups
); i
++) {
1807 centry_sid(centry
, mem_ctx
, &(*user_gids
)[i
]);
1811 status
= centry
->status
;
1813 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status: %s\n",
1814 domain
->name
, nt_errstr(status
) ));
1816 centry_free(centry
);
1821 (*user_gids
) = NULL
;
1823 /* Return status value returned by seq number check */
1825 if (!NT_STATUS_IS_OK(domain
->last_status
))
1826 return domain
->last_status
;
1828 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
1831 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
1833 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
1837 refresh_sequence_number(domain
, false);
1838 centry
= centry_start(domain
, status
);
1842 centry_put_uint32(centry
, *num_groups
);
1843 for (i
=0; i
<(*num_groups
); i
++) {
1844 centry_put_sid(centry
, &(*user_gids
)[i
]);
1847 centry_end(centry
, "UG/%s", sid_to_fstring(sid_string
, user_sid
));
1848 centry_free(centry
);
1854 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
1855 TALLOC_CTX
*mem_ctx
,
1856 uint32 num_sids
, const DOM_SID
*sids
,
1857 uint32
*num_aliases
, uint32
**alias_rids
)
1859 struct winbind_cache
*cache
= get_cache(domain
);
1860 struct cache_entry
*centry
= NULL
;
1862 char *sidlist
= talloc_strdup(mem_ctx
, "");
1868 if (num_sids
== 0) {
1871 return NT_STATUS_OK
;
1874 /* We need to cache indexed by the whole list of SIDs, the aliases
1875 * resulting might come from any of the SIDs. */
1877 for (i
=0; i
<num_sids
; i
++) {
1879 sidlist
= talloc_asprintf(mem_ctx
, "%s/%s", sidlist
,
1880 sid_to_fstring(tmp
, &sids
[i
]));
1881 if (sidlist
== NULL
)
1882 return NT_STATUS_NO_MEMORY
;
1885 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
1890 *num_aliases
= centry_uint32(centry
);
1894 (*alias_rids
) = TALLOC_ARRAY(mem_ctx
, uint32
, *num_aliases
);
1896 if ((*alias_rids
) == NULL
) {
1897 centry_free(centry
);
1898 return NT_STATUS_NO_MEMORY
;
1901 (*alias_rids
) = NULL
;
1904 for (i
=0; i
<(*num_aliases
); i
++)
1905 (*alias_rids
)[i
] = centry_uint32(centry
);
1907 status
= centry
->status
;
1909 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
1910 "status %s\n", domain
->name
, nt_errstr(status
)));
1912 centry_free(centry
);
1917 (*alias_rids
) = NULL
;
1919 if (!NT_STATUS_IS_OK(domain
->last_status
))
1920 return domain
->last_status
;
1922 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
1923 "for domain %s\n", domain
->name
));
1925 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
1927 num_aliases
, alias_rids
);
1930 refresh_sequence_number(domain
, false);
1931 centry
= centry_start(domain
, status
);
1934 centry_put_uint32(centry
, *num_aliases
);
1935 for (i
=0; i
<(*num_aliases
); i
++)
1936 centry_put_uint32(centry
, (*alias_rids
)[i
]);
1937 centry_end(centry
, "UA%s", sidlist
);
1938 centry_free(centry
);
1945 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
1946 TALLOC_CTX
*mem_ctx
,
1947 const DOM_SID
*group_sid
, uint32
*num_names
,
1948 DOM_SID
**sid_mem
, char ***names
,
1949 uint32
**name_types
)
1951 struct winbind_cache
*cache
= get_cache(domain
);
1952 struct cache_entry
*centry
= NULL
;
1960 centry
= wcache_fetch(cache
, domain
, "GM/%s",
1961 sid_to_fstring(sid_string
, group_sid
));
1965 *num_names
= centry_uint32(centry
);
1967 if (*num_names
== 0)
1970 (*sid_mem
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_names
);
1971 (*names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_names
);
1972 (*name_types
) = TALLOC_ARRAY(mem_ctx
, uint32
, *num_names
);
1974 if (! (*sid_mem
) || ! (*names
) || ! (*name_types
)) {
1975 smb_panic_fn("lookup_groupmem out of memory");
1978 for (i
=0; i
<(*num_names
); i
++) {
1979 centry_sid(centry
, mem_ctx
, &(*sid_mem
)[i
]);
1980 (*names
)[i
] = centry_string(centry
, mem_ctx
);
1981 (*name_types
)[i
] = centry_uint32(centry
);
1985 status
= centry
->status
;
1987 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status: %s\n",
1988 domain
->name
, nt_errstr(status
)));
1990 centry_free(centry
);
1997 (*name_types
) = NULL
;
1999 /* Return status value returned by seq number check */
2001 if (!NT_STATUS_IS_OK(domain
->last_status
))
2002 return domain
->last_status
;
2004 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2007 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2008 sid_mem
, names
, name_types
);
2011 refresh_sequence_number(domain
, false);
2012 centry
= centry_start(domain
, status
);
2015 centry_put_uint32(centry
, *num_names
);
2016 for (i
=0; i
<(*num_names
); i
++) {
2017 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2018 centry_put_string(centry
, (*names
)[i
]);
2019 centry_put_uint32(centry
, (*name_types
)[i
]);
2021 centry_end(centry
, "GM/%s", sid_to_fstring(sid_string
, group_sid
));
2022 centry_free(centry
);
2028 /* find the sequence number for a domain */
2029 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
2031 refresh_sequence_number(domain
, false);
2033 *seq
= domain
->sequence_number
;
2035 return NT_STATUS_OK
;
2038 /* enumerate trusted domains
2039 * (we need to have the list of trustdoms in the cache when we go offline) -
2041 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
2042 TALLOC_CTX
*mem_ctx
,
2043 uint32
*num_domains
,
2048 struct winbind_cache
*cache
= get_cache(domain
);
2049 struct cache_entry
*centry
= NULL
;
2056 centry
= wcache_fetch(cache
, domain
, "TRUSTDOMS/%s", domain
->name
);
2062 *num_domains
= centry_uint32(centry
);
2065 (*names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
2066 (*alt_names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
2067 (*dom_sids
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_domains
);
2069 if (! (*dom_sids
) || ! (*names
) || ! (*alt_names
)) {
2070 smb_panic_fn("trusted_domains out of memory");
2074 (*alt_names
) = NULL
;
2078 for (i
=0; i
<(*num_domains
); i
++) {
2079 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2080 (*alt_names
)[i
] = centry_string(centry
, mem_ctx
);
2081 centry_sid(centry
, mem_ctx
, &(*dom_sids
)[i
]);
2084 status
= centry
->status
;
2086 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
2087 domain
->name
, *num_domains
, nt_errstr(status
) ));
2089 centry_free(centry
);
2096 (*alt_names
) = NULL
;
2098 /* Return status value returned by seq number check */
2100 if (!NT_STATUS_IS_OK(domain
->last_status
))
2101 return domain
->last_status
;
2103 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2106 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, num_domains
,
2107 names
, alt_names
, dom_sids
);
2109 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2110 * so that the generic centry handling still applies correctly -
2113 if (!NT_STATUS_IS_ERR(status
)) {
2114 status
= NT_STATUS_OK
;
2118 #if 0 /* Disabled as we want the trust dom list to be managed by
2119 the main parent and always to make the query. --jerry */
2122 refresh_sequence_number(domain
, false);
2124 centry
= centry_start(domain
, status
);
2128 centry_put_uint32(centry
, *num_domains
);
2130 for (i
=0; i
<(*num_domains
); i
++) {
2131 centry_put_string(centry
, (*names
)[i
]);
2132 centry_put_string(centry
, (*alt_names
)[i
]);
2133 centry_put_sid(centry
, &(*dom_sids
)[i
]);
2136 centry_end(centry
, "TRUSTDOMS/%s", domain
->name
);
2138 centry_free(centry
);
2146 /* get lockout policy */
2147 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
2148 TALLOC_CTX
*mem_ctx
,
2149 struct samr_DomInfo12
*policy
)
2151 struct winbind_cache
*cache
= get_cache(domain
);
2152 struct cache_entry
*centry
= NULL
;
2158 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2163 policy
->lockout_duration
= centry_nttime(centry
);
2164 policy
->lockout_window
= centry_nttime(centry
);
2165 policy
->lockout_threshold
= centry_uint16(centry
);
2167 status
= centry
->status
;
2169 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2170 domain
->name
, nt_errstr(status
) ));
2172 centry_free(centry
);
2176 ZERO_STRUCTP(policy
);
2178 /* Return status value returned by seq number check */
2180 if (!NT_STATUS_IS_OK(domain
->last_status
))
2181 return domain
->last_status
;
2183 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2186 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2189 refresh_sequence_number(domain
, false);
2190 wcache_save_lockout_policy(domain
, status
, policy
);
2195 /* get password policy */
2196 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
2197 TALLOC_CTX
*mem_ctx
,
2198 struct samr_DomInfo1
*policy
)
2200 struct winbind_cache
*cache
= get_cache(domain
);
2201 struct cache_entry
*centry
= NULL
;
2207 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2212 policy
->min_password_length
= centry_uint16(centry
);
2213 policy
->password_history_length
= centry_uint16(centry
);
2214 policy
->password_properties
= centry_uint32(centry
);
2215 policy
->max_password_age
= centry_nttime(centry
);
2216 policy
->min_password_age
= centry_nttime(centry
);
2218 status
= centry
->status
;
2220 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2221 domain
->name
, nt_errstr(status
) ));
2223 centry_free(centry
);
2227 ZERO_STRUCTP(policy
);
2229 /* Return status value returned by seq number check */
2231 if (!NT_STATUS_IS_OK(domain
->last_status
))
2232 return domain
->last_status
;
2234 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2237 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
2240 refresh_sequence_number(domain
, false);
2241 if (NT_STATUS_IS_OK(status
)) {
2242 wcache_save_password_policy(domain
, status
, policy
);
2249 /* Invalidate cached user and group lists coherently */
2251 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2254 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
2255 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
2256 tdb_delete(the_tdb
, kbuf
);
2261 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2263 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
2264 struct netr_SamInfo3
*info3
)
2266 struct winbind_cache
*cache
;
2268 /* dont clear cached U/SID and UG/SID entries when we want to logon
2271 if (lp_winbind_offline_logon()) {
2278 cache
= get_cache(domain
);
2279 netsamlogon_clear_cached_user(cache
->tdb
, info3
);
2282 bool wcache_invalidate_cache(void)
2284 struct winbindd_domain
*domain
;
2286 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
2287 struct winbind_cache
*cache
= get_cache(domain
);
2289 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2290 "entries for %s\n", domain
->name
));
2293 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
2302 bool init_wcache(void)
2304 if (wcache
== NULL
) {
2305 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
2306 ZERO_STRUCTP(wcache
);
2309 if (wcache
->tdb
!= NULL
)
2312 /* when working offline we must not clear the cache on restart */
2313 wcache
->tdb
= tdb_open_log(lock_path("winbindd_cache.tdb"),
2314 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
2315 lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
2316 O_RDWR
|O_CREAT
, 0600);
2318 if (wcache
->tdb
== NULL
) {
2319 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2326 /************************************************************************
2327 This is called by the parent to initialize the cache file.
2328 We don't need sophisticated locking here as we know we're the
2330 ************************************************************************/
2332 bool initialize_winbindd_cache(void)
2334 bool cache_bad
= true;
2337 if (!init_wcache()) {
2338 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
2342 /* Check version number. */
2343 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
2344 vers
== WINBINDD_CACHE_VERSION
) {
2349 DEBUG(0,("initialize_winbindd_cache: clearing cache "
2350 "and re-creating with version number %d\n",
2351 WINBINDD_CACHE_VERSION
));
2353 tdb_close(wcache
->tdb
);
2356 if (unlink(lock_path("winbindd_cache.tdb")) == -1) {
2357 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
2358 lock_path("winbindd_cache.tdb"),
2362 if (!init_wcache()) {
2363 DEBUG(0,("initialize_winbindd_cache: re-initialization "
2364 "init_wcache failed.\n"));
2368 /* Write the version. */
2369 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
2370 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
2371 tdb_errorstr(wcache
->tdb
) ));
2376 tdb_close(wcache
->tdb
);
2381 void close_winbindd_cache(void)
2387 tdb_close(wcache
->tdb
);
2392 void cache_store_response(pid_t pid
, struct winbindd_response
*response
)
2399 DEBUG(10, ("Storing response for pid %d, len %d\n",
2400 pid
, response
->length
));
2402 fstr_sprintf(key_str
, "DR/%d", pid
);
2403 if (tdb_store(wcache
->tdb
, string_tdb_data(key_str
),
2404 make_tdb_data((uint8
*)response
, sizeof(*response
)),
2408 if (response
->length
== sizeof(*response
))
2411 /* There's extra data */
2413 DEBUG(10, ("Storing extra data: len=%d\n",
2414 (int)(response
->length
- sizeof(*response
))));
2416 fstr_sprintf(key_str
, "DE/%d", pid
);
2417 if (tdb_store(wcache
->tdb
, string_tdb_data(key_str
),
2418 make_tdb_data((uint8
*)response
->extra_data
.data
,
2419 response
->length
- sizeof(*response
)),
2423 /* We could not store the extra data, make sure the tdb does not
2424 * contain a main record with wrong dangling extra data */
2426 fstr_sprintf(key_str
, "DR/%d", pid
);
2427 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2432 bool cache_retrieve_response(pid_t pid
, struct winbindd_response
* response
)
2440 DEBUG(10, ("Retrieving response for pid %d\n", pid
));
2442 fstr_sprintf(key_str
, "DR/%d", pid
);
2443 data
= tdb_fetch(wcache
->tdb
, string_tdb_data(key_str
));
2445 if (data
.dptr
== NULL
)
2448 if (data
.dsize
!= sizeof(*response
))
2451 memcpy(response
, data
.dptr
, data
.dsize
);
2452 SAFE_FREE(data
.dptr
);
2454 if (response
->length
== sizeof(*response
)) {
2455 response
->extra_data
.data
= NULL
;
2459 /* There's extra data */
2461 DEBUG(10, ("Retrieving extra data length=%d\n",
2462 (int)(response
->length
- sizeof(*response
))));
2464 fstr_sprintf(key_str
, "DE/%d", pid
);
2465 data
= tdb_fetch(wcache
->tdb
, string_tdb_data(key_str
));
2467 if (data
.dptr
== NULL
) {
2468 DEBUG(0, ("Did not find extra data\n"));
2472 if (data
.dsize
!= (response
->length
- sizeof(*response
))) {
2473 DEBUG(0, ("Invalid extra data length: %d\n", (int)data
.dsize
));
2474 SAFE_FREE(data
.dptr
);
2478 dump_data(11, (uint8
*)data
.dptr
, data
.dsize
);
2480 response
->extra_data
.data
= data
.dptr
;
2484 void cache_cleanup_response(pid_t pid
)
2491 fstr_sprintf(key_str
, "DR/%d", pid
);
2492 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2494 fstr_sprintf(key_str
, "DE/%d", pid
);
2495 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2501 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const DOM_SID
*sid
,
2502 char **domain_name
, char **name
,
2503 enum lsa_SidType
*type
)
2505 struct winbindd_domain
*domain
;
2506 struct winbind_cache
*cache
;
2507 struct cache_entry
*centry
= NULL
;
2511 domain
= find_lookup_domain_from_sid(sid
);
2512 if (domain
== NULL
) {
2516 cache
= get_cache(domain
);
2518 if (cache
->tdb
== NULL
) {
2522 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2523 sid_to_fstring(tmp
, sid
));
2524 if (centry
== NULL
) {
2528 if (NT_STATUS_IS_OK(centry
->status
)) {
2529 *type
= (enum lsa_SidType
)centry_uint32(centry
);
2530 *domain_name
= centry_string(centry
, mem_ctx
);
2531 *name
= centry_string(centry
, mem_ctx
);
2534 status
= centry
->status
;
2535 centry_free(centry
);
2536 return NT_STATUS_IS_OK(status
);
2539 bool lookup_cached_name(TALLOC_CTX
*mem_ctx
,
2540 const char *domain_name
,
2543 enum lsa_SidType
*type
)
2545 struct winbindd_domain
*domain
;
2546 struct winbind_cache
*cache
;
2547 struct cache_entry
*centry
= NULL
;
2550 bool original_online_state
;
2552 domain
= find_lookup_domain_from_name(domain_name
);
2553 if (domain
== NULL
) {
2557 cache
= get_cache(domain
);
2559 if (cache
->tdb
== NULL
) {
2563 fstrcpy(uname
, name
);
2566 /* If we are doing a cached logon, temporarily set the domain
2567 offline so the cache won't expire the entry */
2569 original_online_state
= domain
->online
;
2570 domain
->online
= false;
2571 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
2572 domain
->online
= original_online_state
;
2574 if (centry
== NULL
) {
2578 if (NT_STATUS_IS_OK(centry
->status
)) {
2579 *type
= (enum lsa_SidType
)centry_uint32(centry
);
2580 centry_sid(centry
, mem_ctx
, sid
);
2583 status
= centry
->status
;
2584 centry_free(centry
);
2586 return NT_STATUS_IS_OK(status
);
2589 void cache_name2sid(struct winbindd_domain
*domain
,
2590 const char *domain_name
, const char *name
,
2591 enum lsa_SidType type
, const DOM_SID
*sid
)
2593 refresh_sequence_number(domain
, false);
2594 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
2599 * The original idea that this cache only contains centries has
2600 * been blurred - now other stuff gets put in here. Ensure we
2601 * ignore these things on cleanup.
2604 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
2605 TDB_DATA dbuf
, void *state
)
2607 struct cache_entry
*centry
;
2609 if (is_non_centry_key(kbuf
)) {
2613 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
2618 if (!NT_STATUS_IS_OK(centry
->status
)) {
2619 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
2620 tdb_delete(the_tdb
, kbuf
);
2623 centry_free(centry
);
2627 /* flush the cache */
2628 void wcache_flush_cache(void)
2633 tdb_close(wcache
->tdb
);
2639 /* when working offline we must not clear the cache on restart */
2640 wcache
->tdb
= tdb_open_log(lock_path("winbindd_cache.tdb"),
2641 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
2642 lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
2643 O_RDWR
|O_CREAT
, 0600);
2646 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2650 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
2652 DEBUG(10,("wcache_flush_cache success\n"));
2655 /* Count cached creds */
2657 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2660 int *cred_count
= (int*)state
;
2662 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
2668 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
2670 struct winbind_cache
*cache
= get_cache(domain
);
2675 return NT_STATUS_INTERNAL_DB_ERROR
;
2678 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
2680 return NT_STATUS_OK
;
2684 struct cred_list
*prev
, *next
;
2689 static struct cred_list
*wcache_cred_list
;
2691 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2694 struct cred_list
*cred
;
2696 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
2698 cred
= SMB_MALLOC_P(struct cred_list
);
2700 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2706 /* save a copy of the key */
2708 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
2709 DLIST_ADD(wcache_cred_list
, cred
);
2715 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const DOM_SID
*sid
)
2717 struct winbind_cache
*cache
= get_cache(domain
);
2720 struct cred_list
*cred
, *oldest
= NULL
;
2723 return NT_STATUS_INTERNAL_DB_ERROR
;
2726 /* we possibly already have an entry */
2727 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
2729 fstring key_str
, tmp
;
2731 DEBUG(11,("we already have an entry, deleting that\n"));
2733 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
2735 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
2737 return NT_STATUS_OK
;
2740 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
2742 return NT_STATUS_OK
;
2743 } else if ((ret
== -1) || (wcache_cred_list
== NULL
)) {
2744 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2747 ZERO_STRUCTP(oldest
);
2749 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
2754 data
= tdb_fetch(cache
->tdb
, string_tdb_data(cred
->name
));
2756 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
2758 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2762 t
= IVAL(data
.dptr
, 0);
2763 SAFE_FREE(data
.dptr
);
2766 oldest
= SMB_MALLOC_P(struct cred_list
);
2767 if (oldest
== NULL
) {
2768 status
= NT_STATUS_NO_MEMORY
;
2772 fstrcpy(oldest
->name
, cred
->name
);
2773 oldest
->created
= t
;
2777 if (t
< oldest
->created
) {
2778 fstrcpy(oldest
->name
, cred
->name
);
2779 oldest
->created
= t
;
2783 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
2784 status
= NT_STATUS_OK
;
2786 status
= NT_STATUS_UNSUCCESSFUL
;
2789 SAFE_FREE(wcache_cred_list
);
2795 /* Change the global online/offline state. */
2796 bool set_global_winbindd_state_offline(void)
2800 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
2802 /* Only go offline if someone has created
2803 the key "WINBINDD_OFFLINE" in the cache tdb. */
2805 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
2806 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
2810 if (!lp_winbind_offline_logon()) {
2811 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
2815 if (global_winbindd_offline_state
) {
2816 /* Already offline. */
2820 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
2822 if (!data
.dptr
|| data
.dsize
!= 4) {
2823 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
2824 SAFE_FREE(data
.dptr
);
2827 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
2828 global_winbindd_offline_state
= true;
2829 SAFE_FREE(data
.dptr
);
2834 void set_global_winbindd_state_online(void)
2836 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
2838 if (!lp_winbind_offline_logon()) {
2839 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
2843 if (!global_winbindd_offline_state
) {
2844 /* Already online. */
2847 global_winbindd_offline_state
= false;
2853 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
2854 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
2857 bool get_global_winbindd_state_offline(void)
2859 return global_winbindd_offline_state
;
2862 /***********************************************************************
2863 Validate functions for all possible cache tdb keys.
2864 ***********************************************************************/
2866 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
2867 struct tdb_validation_status
*state
)
2869 struct cache_entry
*centry
;
2871 centry
= SMB_XMALLOC_P(struct cache_entry
);
2872 centry
->data
= (unsigned char *)memdup(data
.dptr
, data
.dsize
);
2873 if (!centry
->data
) {
2877 centry
->len
= data
.dsize
;
2880 if (centry
->len
< 8) {
2881 /* huh? corrupt cache? */
2882 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr
));
2883 centry_free(centry
);
2884 state
->bad_entry
= true;
2885 state
->success
= false;
2889 centry
->status
= NT_STATUS(centry_uint32(centry
));
2890 centry
->sequence_number
= centry_uint32(centry
);
2894 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2895 struct tdb_validation_status
*state
)
2897 if (dbuf
.dsize
!= 8) {
2898 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
2899 keystr
, (unsigned int)dbuf
.dsize
));
2900 state
->bad_entry
= true;
2906 static int validate_ns(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2907 struct tdb_validation_status
*state
)
2909 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
2914 (void)centry_uint32(centry
);
2915 if (NT_STATUS_IS_OK(centry
->status
)) {
2917 (void)centry_sid(centry
, mem_ctx
, &sid
);
2920 centry_free(centry
);
2922 if (!(state
->success
)) {
2925 DEBUG(10,("validate_ns: %s ok\n", keystr
));
2929 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2930 struct tdb_validation_status
*state
)
2932 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
2937 if (NT_STATUS_IS_OK(centry
->status
)) {
2938 (void)centry_uint32(centry
);
2939 (void)centry_string(centry
, mem_ctx
);
2940 (void)centry_string(centry
, mem_ctx
);
2943 centry_free(centry
);
2945 if (!(state
->success
)) {
2948 DEBUG(10,("validate_sn: %s ok\n", keystr
));
2952 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2953 struct tdb_validation_status
*state
)
2955 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
2962 (void)centry_string(centry
, mem_ctx
);
2963 (void)centry_string(centry
, mem_ctx
);
2964 (void)centry_string(centry
, mem_ctx
);
2965 (void)centry_string(centry
, mem_ctx
);
2966 (void)centry_uint32(centry
);
2967 (void)centry_sid(centry
, mem_ctx
, &sid
);
2968 (void)centry_sid(centry
, mem_ctx
, &sid
);
2970 centry_free(centry
);
2972 if (!(state
->success
)) {
2975 DEBUG(10,("validate_u: %s ok\n", keystr
));
2979 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
2980 struct tdb_validation_status
*state
)
2982 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
2988 (void)centry_nttime(centry
);
2989 (void)centry_nttime(centry
);
2990 (void)centry_uint16(centry
);
2992 centry_free(centry
);
2994 if (!(state
->success
)) {
2997 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3001 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3002 struct tdb_validation_status
*state
)
3004 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3010 (void)centry_uint16(centry
);
3011 (void)centry_uint16(centry
);
3012 (void)centry_uint32(centry
);
3013 (void)centry_nttime(centry
);
3014 (void)centry_nttime(centry
);
3016 centry_free(centry
);
3018 if (!(state
->success
)) {
3021 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3025 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3026 struct tdb_validation_status
*state
)
3028 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3034 (void)centry_time(centry
);
3035 (void)centry_hash16(centry
, mem_ctx
);
3037 /* We only have 17 bytes more data in the salted cred case. */
3038 if (centry
->len
- centry
->ofs
== 17) {
3039 (void)centry_hash16(centry
, mem_ctx
);
3042 centry_free(centry
);
3044 if (!(state
->success
)) {
3047 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3051 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3052 struct tdb_validation_status
*state
)
3054 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3055 int32 num_entries
, i
;
3061 num_entries
= (int32
)centry_uint32(centry
);
3063 for (i
=0; i
< num_entries
; i
++) {
3065 (void)centry_string(centry
, mem_ctx
);
3066 (void)centry_string(centry
, mem_ctx
);
3067 (void)centry_string(centry
, mem_ctx
);
3068 (void)centry_string(centry
, mem_ctx
);
3069 (void)centry_sid(centry
, mem_ctx
, &sid
);
3070 (void)centry_sid(centry
, mem_ctx
, &sid
);
3073 centry_free(centry
);
3075 if (!(state
->success
)) {
3078 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3082 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3083 struct tdb_validation_status
*state
)
3085 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3086 int32 num_entries
, i
;
3092 num_entries
= centry_uint32(centry
);
3094 for (i
=0; i
< num_entries
; i
++) {
3095 (void)centry_string(centry
, mem_ctx
);
3096 (void)centry_string(centry
, mem_ctx
);
3097 (void)centry_uint32(centry
);
3100 centry_free(centry
);
3102 if (!(state
->success
)) {
3105 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3109 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3110 struct tdb_validation_status
*state
)
3112 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3113 int32 num_groups
, i
;
3119 num_groups
= centry_uint32(centry
);
3121 for (i
=0; i
< num_groups
; i
++) {
3123 centry_sid(centry
, mem_ctx
, &sid
);
3126 centry_free(centry
);
3128 if (!(state
->success
)) {
3131 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3135 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3136 struct tdb_validation_status
*state
)
3138 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3139 int32 num_aliases
, i
;
3145 num_aliases
= centry_uint32(centry
);
3147 for (i
=0; i
< num_aliases
; i
++) {
3148 (void)centry_uint32(centry
);
3151 centry_free(centry
);
3153 if (!(state
->success
)) {
3156 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3160 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3161 struct tdb_validation_status
*state
)
3163 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3170 num_names
= centry_uint32(centry
);
3172 for (i
=0; i
< num_names
; i
++) {
3174 centry_sid(centry
, mem_ctx
, &sid
);
3175 (void)centry_string(centry
, mem_ctx
);
3176 (void)centry_uint32(centry
);
3179 centry_free(centry
);
3181 if (!(state
->success
)) {
3184 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3188 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3189 struct tdb_validation_status
*state
)
3191 /* Can't say anything about this other than must be nonzero. */
3192 if (dbuf
.dsize
== 0) {
3193 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3195 state
->bad_entry
= true;
3196 state
->success
= false;
3200 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3204 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3205 struct tdb_validation_status
*state
)
3207 /* Can't say anything about this other than must be nonzero. */
3208 if (dbuf
.dsize
== 0) {
3209 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3211 state
->bad_entry
= true;
3212 state
->success
= false;
3216 DEBUG(10,("validate_de: %s ok\n", keystr
));
3220 static int validate_pwinfo(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3221 TDB_DATA dbuf
, struct tdb_validation_status
*state
)
3223 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3229 (void)centry_string(centry
, mem_ctx
);
3230 (void)centry_string(centry
, mem_ctx
);
3231 (void)centry_string(centry
, mem_ctx
);
3232 (void)centry_uint32(centry
);
3234 centry_free(centry
);
3236 if (!(state
->success
)) {
3239 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3243 static int validate_trustdoms(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3244 struct tdb_validation_status
*state
)
3246 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3247 int32 num_domains
, i
;
3253 num_domains
= centry_uint32(centry
);
3255 for (i
=0; i
< num_domains
; i
++) {
3257 (void)centry_string(centry
, mem_ctx
);
3258 (void)centry_string(centry
, mem_ctx
);
3259 (void)centry_sid(centry
, mem_ctx
, &sid
);
3262 centry_free(centry
);
3264 if (!(state
->success
)) {
3267 DEBUG(10,("validate_trustdoms: %s ok\n", keystr
));
3271 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3273 struct tdb_validation_status
*state
)
3275 if (dbuf
.dsize
== 0) {
3276 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3277 "key %s (len ==0) ?\n", keystr
));
3278 state
->bad_entry
= true;
3279 state
->success
= false;
3283 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3284 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3288 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3289 struct tdb_validation_status
*state
)
3291 if (dbuf
.dsize
!= 4) {
3292 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3293 keystr
, (unsigned int)dbuf
.dsize
));
3294 state
->bad_entry
= true;
3295 state
->success
= false;
3298 DEBUG(10,("validate_offline: %s ok\n", keystr
));
3302 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3303 struct tdb_validation_status
*state
)
3305 if (dbuf
.dsize
!= 4) {
3306 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3307 "key %s (len %u != 4) ?\n",
3308 keystr
, (unsigned int)dbuf
.dsize
));
3309 state
->bad_entry
= true;
3310 state
->success
= false;
3314 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
3318 /***********************************************************************
3319 A list of all possible cache tdb keys with associated validation
3321 ***********************************************************************/
3323 struct key_val_struct
{
3324 const char *keyname
;
3325 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
3327 {"SEQNUM/", validate_seqnum
},
3328 {"NS/", validate_ns
},
3329 {"SN/", validate_sn
},
3331 {"LOC_POL/", validate_loc_pol
},
3332 {"PWD_POL/", validate_pwd_pol
},
3333 {"CRED/", validate_cred
},
3334 {"UL/", validate_ul
},
3335 {"GL/", validate_gl
},
3336 {"UG/", validate_ug
},
3337 {"UA", validate_ua
},
3338 {"GM/", validate_gm
},
3339 {"DR/", validate_dr
},
3340 {"DE/", validate_de
},
3341 {"NSS/PWINFO/", validate_pwinfo
},
3342 {"TRUSTDOMS/", validate_trustdoms
},
3343 {"TRUSTDOMCACHE/", validate_trustdomcache
},
3344 {"WINBINDD_OFFLINE", validate_offline
},
3345 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
3349 /***********************************************************************
3350 Function to look at every entry in the tdb and validate it as far as
3352 ***********************************************************************/
3354 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
3357 unsigned int max_key_len
= 1024;
3358 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
3360 /* Paranoia check. */
3361 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0) {
3362 max_key_len
= 1024 * 1024;
3364 if (kbuf
.dsize
> max_key_len
) {
3365 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
3367 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
3371 for (i
= 0; key_val
[i
].keyname
; i
++) {
3372 size_t namelen
= strlen(key_val
[i
].keyname
);
3373 if (kbuf
.dsize
>= namelen
&& (
3374 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
3375 TALLOC_CTX
*mem_ctx
;
3379 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
3383 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
3384 keystr
[kbuf
.dsize
] = '\0';
3386 mem_ctx
= talloc_init("validate_ctx");
3392 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
3396 talloc_destroy(mem_ctx
);
3401 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
3402 dump_data(0, (uint8
*)kbuf
.dptr
, kbuf
.dsize
);
3403 DEBUG(0,("data :\n"));
3404 dump_data(0, (uint8
*)dbuf
.dptr
, dbuf
.dsize
);
3405 v_state
->unknown_key
= true;
3406 v_state
->success
= false;
3407 return 1; /* terminate. */
3410 static void validate_panic(const char *const why
)
3412 DEBUG(0,("validating cache: would panic %s\n", why
));
3413 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
3417 /***********************************************************************
3418 Try and validate every entry in the winbindd cache. If we fail here,
3419 delete the cache tdb and return non-zero.
3420 ***********************************************************************/
3422 int winbindd_validate_cache(void)
3425 const char *tdb_path
= lock_path("winbindd_cache.tdb");
3426 TDB_CONTEXT
*tdb
= NULL
;
3428 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3429 smb_panic_fn
= validate_panic
;
3432 tdb
= tdb_open_log(tdb_path
,
3433 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3434 ( lp_winbind_offline_logon()
3436 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
3440 DEBUG(0, ("winbindd_validate_cache: "
3441 "error opening/initializing tdb\n"));
3446 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
3449 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
3450 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
3455 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
3456 smb_panic_fn
= smb_panic
;
3460 /***********************************************************************
3461 Try and validate every entry in the winbindd cache.
3462 ***********************************************************************/
3464 int winbindd_validate_cache_nobackup(void)
3467 const char *tdb_path
= lock_path("winbindd_cache.tdb");
3469 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3470 smb_panic_fn
= validate_panic
;
3473 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3474 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
3476 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
3480 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
3484 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
3486 smb_panic_fn
= smb_panic
;
3490 bool winbindd_cache_validate_and_initialize(void)
3492 close_winbindd_cache();
3494 if (lp_winbind_offline_logon()) {
3495 if (winbindd_validate_cache() < 0) {
3496 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
3497 "could be restored.\n"));
3501 return initialize_winbindd_cache();
3504 /*********************************************************************
3505 ********************************************************************/
3507 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
3508 struct winbindd_tdc_domain
**domains
,
3509 size_t *num_domains
)
3511 struct winbindd_tdc_domain
*list
= NULL
;
3514 bool set_only
= false;
3516 /* don't allow duplicates */
3521 for ( i
=0; i
< (*num_domains
); i
++ ) {
3522 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
3523 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
3534 list
= TALLOC_ARRAY( NULL
, struct winbindd_tdc_domain
, 1 );
3537 list
= TALLOC_REALLOC_ARRAY( *domains
, *domains
,
3538 struct winbindd_tdc_domain
,
3543 ZERO_STRUCT( list
[idx
] );
3549 list
[idx
].domain_name
= talloc_strdup( list
, new_dom
->name
);
3550 list
[idx
].dns_name
= talloc_strdup( list
, new_dom
->alt_name
);
3552 if ( !is_null_sid( &new_dom
->sid
) )
3553 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
3555 if ( new_dom
->domain_flags
!= 0x0 )
3556 list
[idx
].trust_flags
= new_dom
->domain_flags
;
3558 if ( new_dom
->domain_type
!= 0x0 )
3559 list
[idx
].trust_type
= new_dom
->domain_type
;
3561 if ( new_dom
->domain_trust_attribs
!= 0x0 )
3562 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
3566 *num_domains
= idx
+ 1;
3572 /*********************************************************************
3573 ********************************************************************/
3575 static TDB_DATA
make_tdc_key( const char *domain_name
)
3577 char *keystr
= NULL
;
3578 TDB_DATA key
= { NULL
, 0 };
3580 if ( !domain_name
) {
3581 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
3586 asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
);
3587 key
= string_term_tdb_data(keystr
);
3592 /*********************************************************************
3593 ********************************************************************/
3595 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
3597 unsigned char **buf
)
3599 unsigned char *buffer
= NULL
;
3604 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
3612 /* Store the number of array items first */
3613 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
3616 /* now pack each domain trust record */
3617 for ( i
=0; i
<num_domains
; i
++ ) {
3622 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
3623 domains
[i
].domain_name
,
3624 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
3627 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
3628 domains
[i
].domain_name
,
3629 domains
[i
].dns_name
,
3630 sid_to_fstring(tmp
, &domains
[i
].sid
),
3631 domains
[i
].trust_flags
,
3632 domains
[i
].trust_attribs
,
3633 domains
[i
].trust_type
);
3636 if ( buflen
< len
) {
3638 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
3639 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
3653 /*********************************************************************
3654 ********************************************************************/
3656 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
3657 struct winbindd_tdc_domain
**domains
)
3659 fstring domain_name
, dns_name
, sid_string
;
3660 uint32 type
, attribs
, flags
;
3664 struct winbindd_tdc_domain
*list
= NULL
;
3666 /* get the number of domains */
3667 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
3669 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3673 list
= TALLOC_ARRAY( NULL
, struct winbindd_tdc_domain
, num_domains
);
3675 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
3679 for ( i
=0; i
<num_domains
; i
++ ) {
3680 len
+= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
3689 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3690 TALLOC_FREE( list
);
3694 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
3695 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
3696 domain_name
, dns_name
, sid_string
,
3697 flags
, attribs
, type
));
3699 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
3700 list
[i
].dns_name
= talloc_strdup( list
, dns_name
);
3701 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
3702 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
3705 list
[i
].trust_flags
= flags
;
3706 list
[i
].trust_attribs
= attribs
;
3707 list
[i
].trust_type
= type
;
3715 /*********************************************************************
3716 ********************************************************************/
3718 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
3720 TDB_DATA key
= make_tdc_key( lp_workgroup() );
3721 TDB_DATA data
= { NULL
, 0 };
3727 /* See if we were asked to delete the cache entry */
3730 ret
= tdb_delete( wcache
->tdb
, key
);
3734 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
3741 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
3744 SAFE_FREE( data
.dptr
);
3745 SAFE_FREE( key
.dptr
);
3747 return ( ret
!= -1 );
3750 /*********************************************************************
3751 ********************************************************************/
3753 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
3755 TDB_DATA key
= make_tdc_key( lp_workgroup() );
3756 TDB_DATA data
= { NULL
, 0 };
3764 data
= tdb_fetch( wcache
->tdb
, key
);
3766 SAFE_FREE( key
.dptr
);
3771 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
3773 SAFE_FREE( data
.dptr
);
3781 /*********************************************************************
3782 ********************************************************************/
3784 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
3786 struct winbindd_tdc_domain
*dom_list
= NULL
;
3787 size_t num_domains
= 0;
3790 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
3791 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
3792 domain
->name
, domain
->alt_name
,
3793 sid_string_dbg(&domain
->sid
),
3794 domain
->domain_flags
,
3795 domain
->domain_trust_attribs
,
3796 domain
->domain_type
));
3798 if ( !init_wcache() ) {
3802 /* fetch the list */
3804 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
3806 /* add the new domain */
3808 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
3812 /* pack the domain */
3814 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
3822 TALLOC_FREE( dom_list
);
3827 /*********************************************************************
3828 ********************************************************************/
3830 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
3832 struct winbindd_tdc_domain
*dom_list
= NULL
;
3833 size_t num_domains
= 0;
3835 struct winbindd_tdc_domain
*d
= NULL
;
3837 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
3839 if ( !init_wcache() ) {
3843 /* fetch the list */
3845 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
3847 for ( i
=0; i
<num_domains
; i
++ ) {
3848 if ( strequal(name
, dom_list
[i
].domain_name
) ||
3849 strequal(name
, dom_list
[i
].dns_name
) )
3851 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
3854 d
= TALLOC_P( ctx
, struct winbindd_tdc_domain
);
3858 d
->domain_name
= talloc_strdup( d
, dom_list
[i
].domain_name
);
3859 d
->dns_name
= talloc_strdup( d
, dom_list
[i
].dns_name
);
3860 sid_copy( &d
->sid
, &dom_list
[i
].sid
);
3861 d
->trust_flags
= dom_list
[i
].trust_flags
;
3862 d
->trust_type
= dom_list
[i
].trust_type
;
3863 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
3869 TALLOC_FREE( dom_list
);
3875 /*********************************************************************
3876 ********************************************************************/
3878 void wcache_tdc_clear( void )
3880 if ( !init_wcache() )
3883 wcache_tdc_store_list( NULL
, 0 );
3889 /*********************************************************************
3890 ********************************************************************/
3892 static void wcache_save_user_pwinfo(struct winbindd_domain
*domain
,
3894 const DOM_SID
*user_sid
,
3895 const char *homedir
,
3900 struct cache_entry
*centry
;
3903 if ( (centry
= centry_start(domain
, status
)) == NULL
)
3906 centry_put_string( centry
, homedir
);
3907 centry_put_string( centry
, shell
);
3908 centry_put_string( centry
, gecos
);
3909 centry_put_uint32( centry
, gid
);
3911 centry_end(centry
, "NSS/PWINFO/%s", sid_to_fstring(tmp
, user_sid
) );
3913 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid
) ));
3915 centry_free(centry
);
3918 NTSTATUS
nss_get_info_cached( struct winbindd_domain
*domain
,
3919 const DOM_SID
*user_sid
,
3921 ADS_STRUCT
*ads
, LDAPMessage
*msg
,
3922 char **homedir
, char **shell
, char **gecos
,
3925 struct winbind_cache
*cache
= get_cache(domain
);
3926 struct cache_entry
*centry
= NULL
;
3933 centry
= wcache_fetch(cache
, domain
, "NSS/PWINFO/%s",
3934 sid_to_fstring(tmp
, user_sid
));
3939 *homedir
= centry_string( centry
, ctx
);
3940 *shell
= centry_string( centry
, ctx
);
3941 *gecos
= centry_string( centry
, ctx
);
3942 *p_gid
= centry_uint32( centry
);
3944 centry_free(centry
);
3946 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
3947 sid_string_dbg(user_sid
)));
3949 return NT_STATUS_OK
;
3953 nt_status
= nss_get_info( domain
->name
, user_sid
, ctx
, ads
, msg
,
3954 homedir
, shell
, gecos
, p_gid
);
3956 if ( NT_STATUS_IS_OK(nt_status
) ) {
3957 wcache_save_user_pwinfo( domain
, nt_status
, user_sid
,
3958 *homedir
, *shell
, *gecos
, *p_gid
);
3961 if ( NT_STATUS_EQUAL( nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
3962 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
3964 set_domain_offline( domain
);
3971 /* the cache backend methods are exposed via this structure */
3972 struct winbindd_methods cache_methods
= {