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/>.
28 #include "tdb_validate.h"
29 #include "../libcli/auth/libcli_auth.h"
32 #define DBGC_CLASS DBGC_WINBIND
34 #define WINBINDD_CACHE_VERSION 1
35 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
37 extern struct winbindd_methods reconnect_methods
;
39 extern struct winbindd_methods ads_methods
;
41 extern struct winbindd_methods builtin_passdb_methods
;
44 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
45 * Here are the list of entry types that are *not* stored
46 * as form struct cache_entry in the cache.
49 static const char *non_centry_keys
[] = {
54 WINBINDD_CACHE_VERSION_KEYSTR
,
58 /************************************************************************
59 Is this key a non-centry type ?
60 ************************************************************************/
62 static bool is_non_centry_key(TDB_DATA kbuf
)
66 if (kbuf
.dptr
== NULL
|| kbuf
.dsize
== 0) {
69 for (i
= 0; non_centry_keys
[i
] != NULL
; i
++) {
70 size_t namelen
= strlen(non_centry_keys
[i
]);
71 if (kbuf
.dsize
< namelen
) {
74 if (strncmp(non_centry_keys
[i
], (const char *)kbuf
.dptr
, namelen
) == 0) {
81 /* Global online/offline state - False when online. winbindd starts up online
82 and sets this to true if the first query fails and there's an entry in
83 the cache tdb telling us to stay offline. */
85 static bool global_winbindd_offline_state
;
87 struct winbind_cache
{
93 uint32 sequence_number
;
98 void (*smb_panic_fn
)(const char *const why
) = smb_panic
;
100 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
102 static struct winbind_cache
*wcache
;
104 void winbindd_check_cache_size(time_t t
)
106 static time_t last_check_time
;
109 if (last_check_time
== (time_t)0)
112 if (t
- last_check_time
< 60 && t
- last_check_time
> 0)
115 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
116 DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
120 if (fstat(tdb_fd(wcache
->tdb
), &st
) == -1) {
121 DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno
) ));
125 if (st
.st_size
> WINBINDD_MAX_CACHE_SIZE
) {
126 DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
127 (unsigned long)st
.st_size
,
128 (unsigned long)WINBINDD_MAX_CACHE_SIZE
));
129 wcache_flush_cache();
133 /* get the winbind_cache structure */
134 static struct winbind_cache
*get_cache(struct winbindd_domain
*domain
)
136 struct winbind_cache
*ret
= wcache
;
138 /* We have to know what type of domain we are dealing with first. */
140 if (domain
->internal
) {
141 domain
->backend
= &builtin_passdb_methods
;
142 domain
->initialized
= True
;
144 if ( !domain
->initialized
) {
145 init_dc_connection( domain
);
149 OK. listen up becasue I'm only going to say this once.
150 We have the following scenarios to consider
151 (a) trusted AD domains on a Samba DC,
152 (b) trusted AD domains and we are joined to a non-kerberos domain
153 (c) trusted AD domains and we are joined to a kerberos (AD) domain
155 For (a) we can always contact the trusted domain using krb5
156 since we have the domain trust account password
158 For (b) we can only use RPC since we have no way of
159 getting a krb5 ticket in our own domain
161 For (c) we can always use krb5 since we have a kerberos trust
166 if (!domain
->backend
) {
168 struct winbindd_domain
*our_domain
= domain
;
170 /* find our domain first so we can figure out if we
171 are joined to a kerberized domain */
173 if ( !domain
->primary
)
174 our_domain
= find_our_domain();
176 if ((our_domain
->active_directory
|| IS_DC
)
177 && domain
->active_directory
178 && !lp_winbind_rpc_only()) {
179 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain
->name
));
180 domain
->backend
= &ads_methods
;
182 #endif /* HAVE_ADS */
183 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain
->name
));
184 domain
->backend
= &reconnect_methods
;
187 #endif /* HAVE_ADS */
193 ret
= SMB_XMALLOC_P(struct winbind_cache
);
197 wcache_flush_cache();
203 free a centry structure
205 static void centry_free(struct cache_entry
*centry
)
209 SAFE_FREE(centry
->data
);
213 static bool centry_check_bytes(struct cache_entry
*centry
, size_t nbytes
)
215 if (centry
->len
- centry
->ofs
< nbytes
) {
216 DEBUG(0,("centry corruption? needed %u bytes, have %d\n",
217 (unsigned int)nbytes
,
218 centry
->len
- centry
->ofs
));
225 pull a uint32 from a cache entry
227 static uint32
centry_uint32(struct cache_entry
*centry
)
231 if (!centry_check_bytes(centry
, 4)) {
232 smb_panic_fn("centry_uint32");
234 ret
= IVAL(centry
->data
, centry
->ofs
);
240 pull a uint16 from a cache entry
242 static uint16
centry_uint16(struct cache_entry
*centry
)
245 if (!centry_check_bytes(centry
, 2)) {
246 smb_panic_fn("centry_uint16");
248 ret
= CVAL(centry
->data
, centry
->ofs
);
254 pull a uint8 from a cache entry
256 static uint8
centry_uint8(struct cache_entry
*centry
)
259 if (!centry_check_bytes(centry
, 1)) {
260 smb_panic_fn("centry_uint8");
262 ret
= CVAL(centry
->data
, centry
->ofs
);
268 pull a NTTIME from a cache entry
270 static NTTIME
centry_nttime(struct cache_entry
*centry
)
273 if (!centry_check_bytes(centry
, 8)) {
274 smb_panic_fn("centry_nttime");
276 ret
= IVAL(centry
->data
, centry
->ofs
);
278 ret
+= (uint64_t)IVAL(centry
->data
, centry
->ofs
) << 32;
284 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
286 static time_t centry_time(struct cache_entry
*centry
)
288 return (time_t)centry_nttime(centry
);
291 /* pull a string from a cache entry, using the supplied
294 static char *centry_string(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
299 len
= centry_uint8(centry
);
302 /* a deliberate NULL string */
306 if (!centry_check_bytes(centry
, (size_t)len
)) {
307 smb_panic_fn("centry_string");
310 ret
= TALLOC_ARRAY(mem_ctx
, char, len
+1);
312 smb_panic_fn("centry_string out of memory\n");
314 memcpy(ret
,centry
->data
+ centry
->ofs
, len
);
320 /* pull a hash16 from a cache entry, using the supplied
323 static char *centry_hash16(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
328 len
= centry_uint8(centry
);
331 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
336 if (!centry_check_bytes(centry
, 16)) {
340 ret
= TALLOC_ARRAY(mem_ctx
, char, 16);
342 smb_panic_fn("centry_hash out of memory\n");
344 memcpy(ret
,centry
->data
+ centry
->ofs
, 16);
349 /* pull a sid from a cache entry, using the supplied
352 static bool centry_sid(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
, DOM_SID
*sid
)
355 sid_string
= centry_string(centry
, mem_ctx
);
356 if ((sid_string
== NULL
) || (!string_to_sid(sid
, sid_string
))) {
364 pull a NTSTATUS from a cache entry
366 static NTSTATUS
centry_ntstatus(struct cache_entry
*centry
)
370 status
= NT_STATUS(centry_uint32(centry
));
375 /* the server is considered down if it can't give us a sequence number */
376 static bool wcache_server_down(struct winbindd_domain
*domain
)
383 ret
= (domain
->sequence_number
== DOM_SEQUENCE_NONE
);
386 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
391 static NTSTATUS
fetch_cache_seqnum( struct winbindd_domain
*domain
, time_t now
)
398 DEBUG(10,("fetch_cache_seqnum: tdb == NULL\n"));
399 return NT_STATUS_UNSUCCESSFUL
;
402 fstr_sprintf( key
, "SEQNUM/%s", domain
->name
);
404 data
= tdb_fetch_bystring( wcache
->tdb
, key
);
405 if ( !data
.dptr
|| data
.dsize
!=8 ) {
406 DEBUG(10,("fetch_cache_seqnum: invalid data size key [%s]\n", key
));
407 return NT_STATUS_UNSUCCESSFUL
;
410 domain
->sequence_number
= IVAL(data
.dptr
, 0);
411 domain
->last_seq_check
= IVAL(data
.dptr
, 4);
413 SAFE_FREE(data
.dptr
);
415 /* have we expired? */
417 time_diff
= now
- domain
->last_seq_check
;
418 if ( time_diff
> lp_winbind_cache_time() ) {
419 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
420 domain
->name
, domain
->sequence_number
,
421 (uint32
)domain
->last_seq_check
));
422 return NT_STATUS_UNSUCCESSFUL
;
425 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
426 domain
->name
, domain
->sequence_number
,
427 (uint32
)domain
->last_seq_check
));
432 static NTSTATUS
store_cache_seqnum( struct winbindd_domain
*domain
)
439 DEBUG(10,("store_cache_seqnum: tdb == NULL\n"));
440 return NT_STATUS_UNSUCCESSFUL
;
443 fstr_sprintf( key_str
, "SEQNUM/%s", domain
->name
);
445 SIVAL(buf
, 0, domain
->sequence_number
);
446 SIVAL(buf
, 4, domain
->last_seq_check
);
450 if ( tdb_store_bystring( wcache
->tdb
, key_str
, data
, TDB_REPLACE
) == -1 ) {
451 DEBUG(10,("store_cache_seqnum: tdb_store fail key [%s]\n", key_str
));
452 return NT_STATUS_UNSUCCESSFUL
;
455 DEBUG(10,("store_cache_seqnum: success [%s][%u @ %u]\n",
456 domain
->name
, domain
->sequence_number
,
457 (uint32
)domain
->last_seq_check
));
463 refresh the domain sequence number. If force is true
464 then always refresh it, no matter how recently we fetched it
467 static void refresh_sequence_number(struct winbindd_domain
*domain
, bool force
)
471 time_t t
= time(NULL
);
472 unsigned cache_time
= lp_winbind_cache_time();
474 if ( IS_DOMAIN_OFFLINE(domain
) ) {
480 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
481 /* trying to reconnect is expensive, don't do it too often */
482 if (domain
->sequence_number
== DOM_SEQUENCE_NONE
) {
487 time_diff
= t
- domain
->last_seq_check
;
489 /* see if we have to refetch the domain sequence number */
490 if (!force
&& (time_diff
< cache_time
) &&
491 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
492 NT_STATUS_IS_OK(domain
->last_status
)) {
493 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain
->name
));
497 /* try to get the sequence number from the tdb cache first */
498 /* this will update the timestamp as well */
500 status
= fetch_cache_seqnum( domain
, t
);
501 if (NT_STATUS_IS_OK(status
) &&
502 (domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
503 NT_STATUS_IS_OK(domain
->last_status
)) {
507 /* important! make sure that we know if this is a native
508 mode domain or not. And that we can contact it. */
510 if ( winbindd_can_contact_domain( domain
) ) {
511 status
= domain
->backend
->sequence_number(domain
,
512 &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
;
635 if (!winbindd_use_cache()) {
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
, ...)
837 if (!winbindd_use_cache()) {
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
));
945 static void wcache_save_password_policy(struct winbindd_domain
*domain
,
947 struct samr_DomInfo1
*policy
)
949 struct cache_entry
*centry
;
951 centry
= centry_start(domain
, status
);
955 centry_put_uint16(centry
, policy
->min_password_length
);
956 centry_put_uint16(centry
, policy
->password_history_length
);
957 centry_put_uint32(centry
, policy
->password_properties
);
958 centry_put_nttime(centry
, policy
->max_password_age
);
959 centry_put_nttime(centry
, policy
->min_password_age
);
961 centry_end(centry
, "PWD_POL/%s", domain
->name
);
963 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
968 /***************************************************************************
969 ***************************************************************************/
971 static void wcache_save_username_alias(struct winbindd_domain
*domain
,
973 const char *name
, const char *alias
)
975 struct cache_entry
*centry
;
978 if ( (centry
= centry_start(domain
, status
)) == NULL
)
981 centry_put_string( centry
, alias
);
983 fstrcpy(uname
, name
);
985 centry_end(centry
, "NSS/NA/%s", uname
);
987 DEBUG(10,("wcache_save_username_alias: %s -> %s\n", name
, alias
));
992 static void wcache_save_alias_username(struct winbindd_domain
*domain
,
994 const char *alias
, const char *name
)
996 struct cache_entry
*centry
;
999 if ( (centry
= centry_start(domain
, status
)) == NULL
)
1002 centry_put_string( centry
, name
);
1004 fstrcpy(uname
, alias
);
1006 centry_end(centry
, "NSS/AN/%s", uname
);
1008 DEBUG(10,("wcache_save_alias_username: %s -> %s\n", alias
, name
));
1010 centry_free(centry
);
1013 /***************************************************************************
1014 ***************************************************************************/
1016 NTSTATUS
resolve_username_to_alias( TALLOC_CTX
*mem_ctx
,
1017 struct winbindd_domain
*domain
,
1018 const char *name
, char **alias
)
1020 struct winbind_cache
*cache
= get_cache(domain
);
1021 struct cache_entry
*centry
= NULL
;
1025 if ( domain
->internal
)
1026 return NT_STATUS_NOT_SUPPORTED
;
1031 if ( (upper_name
= SMB_STRDUP(name
)) == NULL
)
1032 return NT_STATUS_NO_MEMORY
;
1033 strupper_m(upper_name
);
1035 centry
= wcache_fetch(cache
, domain
, "NSS/NA/%s", upper_name
);
1037 SAFE_FREE( upper_name
);
1042 status
= centry
->status
;
1044 if (!NT_STATUS_IS_OK(status
)) {
1045 centry_free(centry
);
1049 *alias
= centry_string( centry
, mem_ctx
);
1051 centry_free(centry
);
1053 DEBUG(10,("resolve_username_to_alias: [Cached] - mapped %s to %s\n",
1054 name
, *alias
? *alias
: "(none)"));
1056 return (*alias
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1060 /* If its not in cache and we are offline, then fail */
1062 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1063 DEBUG(8,("resolve_username_to_alias: rejecting query "
1064 "in offline mode\n"));
1065 return NT_STATUS_NOT_FOUND
;
1068 status
= nss_map_to_alias( mem_ctx
, domain
->name
, name
, alias
);
1070 if ( NT_STATUS_IS_OK( status
) ) {
1071 wcache_save_username_alias(domain
, status
, name
, *alias
);
1074 if ( NT_STATUS_EQUAL( status
, NT_STATUS_NONE_MAPPED
) ) {
1075 wcache_save_username_alias(domain
, status
, name
, "(NULL)");
1078 DEBUG(5,("resolve_username_to_alias: backend query returned %s\n",
1079 nt_errstr(status
)));
1081 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1082 set_domain_offline( domain
);
1088 /***************************************************************************
1089 ***************************************************************************/
1091 NTSTATUS
resolve_alias_to_username( TALLOC_CTX
*mem_ctx
,
1092 struct winbindd_domain
*domain
,
1093 const char *alias
, char **name
)
1095 struct winbind_cache
*cache
= get_cache(domain
);
1096 struct cache_entry
*centry
= NULL
;
1100 if ( domain
->internal
)
1101 return NT_STATUS_NOT_SUPPORTED
;
1106 if ( (upper_name
= SMB_STRDUP(alias
)) == NULL
)
1107 return NT_STATUS_NO_MEMORY
;
1108 strupper_m(upper_name
);
1110 centry
= wcache_fetch(cache
, domain
, "NSS/AN/%s", upper_name
);
1112 SAFE_FREE( upper_name
);
1117 status
= centry
->status
;
1119 if (!NT_STATUS_IS_OK(status
)) {
1120 centry_free(centry
);
1124 *name
= centry_string( centry
, mem_ctx
);
1126 centry_free(centry
);
1128 DEBUG(10,("resolve_alias_to_username: [Cached] - mapped %s to %s\n",
1129 alias
, *name
? *name
: "(none)"));
1131 return (*name
) ? NT_STATUS_OK
: NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1135 /* If its not in cache and we are offline, then fail */
1137 if ( get_global_winbindd_state_offline() || !domain
->online
) {
1138 DEBUG(8,("resolve_alias_to_username: rejecting query "
1139 "in offline mode\n"));
1140 return NT_STATUS_NOT_FOUND
;
1143 /* an alias cannot contain a domain prefix or '@' */
1145 if (strchr(alias
, '\\') || strchr(alias
, '@')) {
1146 DEBUG(10,("resolve_alias_to_username: skipping fully "
1147 "qualified name %s\n", alias
));
1148 return NT_STATUS_OBJECT_NAME_INVALID
;
1151 status
= nss_map_from_alias( mem_ctx
, domain
->name
, alias
, name
);
1153 if ( NT_STATUS_IS_OK( status
) ) {
1154 wcache_save_alias_username( domain
, status
, alias
, *name
);
1157 if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1158 wcache_save_alias_username(domain
, status
, alias
, "(NULL)");
1161 DEBUG(5,("resolve_alias_to_username: backend query returned %s\n",
1162 nt_errstr(status
)));
1164 if ( NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
1165 set_domain_offline( domain
);
1171 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const DOM_SID
*sid
)
1173 struct winbind_cache
*cache
= get_cache(domain
);
1175 fstring key_str
, tmp
;
1179 return NT_STATUS_INTERNAL_DB_ERROR
;
1182 if (is_null_sid(sid
)) {
1183 return NT_STATUS_INVALID_SID
;
1186 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1187 return NT_STATUS_INVALID_SID
;
1190 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
1192 data
= tdb_fetch(cache
->tdb
, string_tdb_data(key_str
));
1194 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1197 SAFE_FREE(data
.dptr
);
1198 return NT_STATUS_OK
;
1201 /* Lookup creds for a SID - copes with old (unsalted) creds as well
1202 as new salted ones. */
1204 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
1205 TALLOC_CTX
*mem_ctx
,
1207 const uint8
**cached_nt_pass
,
1208 const uint8
**cached_salt
)
1210 struct winbind_cache
*cache
= get_cache(domain
);
1211 struct cache_entry
*centry
= NULL
;
1218 return NT_STATUS_INTERNAL_DB_ERROR
;
1221 if (is_null_sid(sid
)) {
1222 return NT_STATUS_INVALID_SID
;
1225 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1226 return NT_STATUS_INVALID_SID
;
1229 /* Try and get a salted cred first. If we can't
1230 fall back to an unsalted cred. */
1232 centry
= wcache_fetch(cache
, domain
, "CRED/%s",
1233 sid_to_fstring(tmp
, sid
));
1235 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
1236 sid_string_dbg(sid
)));
1237 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1240 t
= centry_time(centry
);
1242 /* In the salted case this isn't actually the nt_hash itself,
1243 but the MD5 of the salt + nt_hash. Let the caller
1244 sort this out. It can tell as we only return the cached_salt
1245 if we are returning a salted cred. */
1247 *cached_nt_pass
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1248 if (*cached_nt_pass
== NULL
) {
1251 sid_to_fstring(sidstr
, sid
);
1253 /* Bad (old) cred cache. Delete and pretend we
1255 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
1257 wcache_delete("CRED/%s", sidstr
);
1258 centry_free(centry
);
1259 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1262 /* We only have 17 bytes more data in the salted cred case. */
1263 if (centry
->len
- centry
->ofs
== 17) {
1264 *cached_salt
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1266 *cached_salt
= NULL
;
1269 dump_data_pw("cached_nt_pass", *cached_nt_pass
, NT_HASH_LEN
);
1271 dump_data_pw("cached_salt", *cached_salt
, NT_HASH_LEN
);
1274 status
= centry
->status
;
1276 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1277 sid_string_dbg(sid
), nt_errstr(status
) ));
1279 centry_free(centry
);
1283 /* Store creds for a SID - only writes out new salted ones. */
1285 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1286 TALLOC_CTX
*mem_ctx
,
1288 const uint8 nt_pass
[NT_HASH_LEN
])
1290 struct cache_entry
*centry
;
1293 uint8 cred_salt
[NT_HASH_LEN
];
1294 uint8 salted_hash
[NT_HASH_LEN
];
1296 if (is_null_sid(sid
)) {
1297 return NT_STATUS_INVALID_SID
;
1300 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1301 return NT_STATUS_INVALID_SID
;
1304 centry
= centry_start(domain
, NT_STATUS_OK
);
1306 return NT_STATUS_INTERNAL_DB_ERROR
;
1309 dump_data_pw("nt_pass", nt_pass
, NT_HASH_LEN
);
1311 centry_put_time(centry
, time(NULL
));
1313 /* Create a salt and then salt the hash. */
1314 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1315 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1317 centry_put_hash16(centry
, salted_hash
);
1318 centry_put_hash16(centry
, cred_salt
);
1319 centry_end(centry
, "CRED/%s", sid_to_fstring(sid_string
, sid
));
1321 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1323 centry_free(centry
);
1325 return NT_STATUS_OK
;
1329 /* Query display info. This is the basic user list fn */
1330 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
1331 TALLOC_CTX
*mem_ctx
,
1332 uint32
*num_entries
,
1333 WINBIND_USERINFO
**info
)
1335 struct winbind_cache
*cache
= get_cache(domain
);
1336 struct cache_entry
*centry
= NULL
;
1338 unsigned int i
, retry
;
1343 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1347 *num_entries
= centry_uint32(centry
);
1349 if (*num_entries
== 0)
1352 (*info
) = TALLOC_ARRAY(mem_ctx
, WINBIND_USERINFO
, *num_entries
);
1354 smb_panic_fn("query_user_list out of memory");
1356 for (i
=0; i
<(*num_entries
); i
++) {
1357 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
1358 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
1359 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
1360 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
1361 centry_sid(centry
, mem_ctx
, &(*info
)[i
].user_sid
);
1362 centry_sid(centry
, mem_ctx
, &(*info
)[i
].group_sid
);
1366 status
= centry
->status
;
1368 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1369 domain
->name
, nt_errstr(status
) ));
1371 centry_free(centry
);
1378 /* Return status value returned by seq number check */
1380 if (!NT_STATUS_IS_OK(domain
->last_status
))
1381 return domain
->last_status
;
1383 /* Put the query_user_list() in a retry loop. There appears to be
1384 * some bug either with Windows 2000 or Samba's handling of large
1385 * rpc replies. This manifests itself as sudden disconnection
1386 * at a random point in the enumeration of a large (60k) user list.
1387 * The retry loop simply tries the operation again. )-: It's not
1388 * pretty but an acceptable workaround until we work out what the
1389 * real problem is. */
1394 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1397 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
1398 if (!NT_STATUS_IS_OK(status
)) {
1399 DEBUG(3, ("query_user_list: returned 0x%08x, "
1400 "retrying\n", NT_STATUS_V(status
)));
1402 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1403 DEBUG(3, ("query_user_list: flushing "
1404 "connection cache\n"));
1405 invalidate_cm_connection(&domain
->conn
);
1408 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1412 refresh_sequence_number(domain
, false);
1413 centry
= centry_start(domain
, status
);
1416 centry_put_uint32(centry
, *num_entries
);
1417 for (i
=0; i
<(*num_entries
); i
++) {
1418 centry_put_string(centry
, (*info
)[i
].acct_name
);
1419 centry_put_string(centry
, (*info
)[i
].full_name
);
1420 centry_put_string(centry
, (*info
)[i
].homedir
);
1421 centry_put_string(centry
, (*info
)[i
].shell
);
1422 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1423 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1424 if (domain
->backend
&& domain
->backend
->consistent
) {
1425 /* when the backend is consistent we can pre-prime some mappings */
1426 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1428 (*info
)[i
].acct_name
,
1429 &(*info
)[i
].user_sid
,
1431 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1432 &(*info
)[i
].user_sid
,
1434 (*info
)[i
].acct_name
,
1436 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1439 centry_end(centry
, "UL/%s", domain
->name
);
1440 centry_free(centry
);
1446 /* list all domain groups */
1447 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
1448 TALLOC_CTX
*mem_ctx
,
1449 uint32
*num_entries
,
1450 struct acct_info
**info
)
1452 struct winbind_cache
*cache
= get_cache(domain
);
1453 struct cache_entry
*centry
= NULL
;
1460 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1464 *num_entries
= centry_uint32(centry
);
1466 if (*num_entries
== 0)
1469 (*info
) = TALLOC_ARRAY(mem_ctx
, struct acct_info
, *num_entries
);
1471 smb_panic_fn("enum_dom_groups out of memory");
1473 for (i
=0; i
<(*num_entries
); i
++) {
1474 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1475 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1476 (*info
)[i
].rid
= centry_uint32(centry
);
1480 status
= centry
->status
;
1482 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1483 domain
->name
, nt_errstr(status
) ));
1485 centry_free(centry
);
1492 /* Return status value returned by seq number check */
1494 if (!NT_STATUS_IS_OK(domain
->last_status
))
1495 return domain
->last_status
;
1497 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1500 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1503 refresh_sequence_number(domain
, false);
1504 centry
= centry_start(domain
, status
);
1507 centry_put_uint32(centry
, *num_entries
);
1508 for (i
=0; i
<(*num_entries
); i
++) {
1509 centry_put_string(centry
, (*info
)[i
].acct_name
);
1510 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1511 centry_put_uint32(centry
, (*info
)[i
].rid
);
1513 centry_end(centry
, "GL/%s/domain", domain
->name
);
1514 centry_free(centry
);
1520 /* list all domain groups */
1521 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
1522 TALLOC_CTX
*mem_ctx
,
1523 uint32
*num_entries
,
1524 struct acct_info
**info
)
1526 struct winbind_cache
*cache
= get_cache(domain
);
1527 struct cache_entry
*centry
= NULL
;
1534 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1538 *num_entries
= centry_uint32(centry
);
1540 if (*num_entries
== 0)
1543 (*info
) = TALLOC_ARRAY(mem_ctx
, struct acct_info
, *num_entries
);
1545 smb_panic_fn("enum_dom_groups out of memory");
1547 for (i
=0; i
<(*num_entries
); i
++) {
1548 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1549 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1550 (*info
)[i
].rid
= centry_uint32(centry
);
1555 /* If we are returning cached data and the domain controller
1556 is down then we don't know whether the data is up to date
1557 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1560 if (wcache_server_down(domain
)) {
1561 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1562 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1564 status
= centry
->status
;
1566 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1567 domain
->name
, nt_errstr(status
) ));
1569 centry_free(centry
);
1576 /* Return status value returned by seq number check */
1578 if (!NT_STATUS_IS_OK(domain
->last_status
))
1579 return domain
->last_status
;
1581 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1584 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1587 refresh_sequence_number(domain
, false);
1588 centry
= centry_start(domain
, status
);
1591 centry_put_uint32(centry
, *num_entries
);
1592 for (i
=0; i
<(*num_entries
); i
++) {
1593 centry_put_string(centry
, (*info
)[i
].acct_name
);
1594 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1595 centry_put_uint32(centry
, (*info
)[i
].rid
);
1597 centry_end(centry
, "GL/%s/local", domain
->name
);
1598 centry_free(centry
);
1604 /* convert a single name to a sid in a domain */
1605 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
1606 TALLOC_CTX
*mem_ctx
,
1607 enum winbindd_cmd orig_cmd
,
1608 const char *domain_name
,
1611 enum lsa_SidType
*type
)
1613 struct winbind_cache
*cache
= get_cache(domain
);
1614 struct cache_entry
*centry
= NULL
;
1621 fstrcpy(uname
, name
);
1623 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1627 status
= centry
->status
;
1628 if (NT_STATUS_IS_OK(status
)) {
1629 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1630 centry_sid(centry
, mem_ctx
, sid
);
1633 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: %s\n",
1634 domain
->name
, nt_errstr(status
) ));
1636 centry_free(centry
);
1642 /* If the seq number check indicated that there is a problem
1643 * with this DC, then return that status... except for
1644 * access_denied. This is special because the dc may be in
1645 * "restrict anonymous = 1" mode, in which case it will deny
1646 * most unauthenticated operations, but *will* allow the LSA
1647 * name-to-sid that we try as a fallback. */
1649 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1650 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1651 return domain
->last_status
;
1653 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1656 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, orig_cmd
,
1657 domain_name
, name
, sid
, type
);
1660 refresh_sequence_number(domain
, false);
1662 if (domain
->online
&&
1663 (NT_STATUS_IS_OK(status
) || NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
))) {
1664 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1666 /* Only save the reverse mapping if this was not a UPN */
1667 if (!strchr(name
, '@')) {
1668 strupper_m(CONST_DISCARD(char *,domain_name
));
1669 strlower_m(CONST_DISCARD(char *,name
));
1670 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1677 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1679 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1680 TALLOC_CTX
*mem_ctx
,
1684 enum lsa_SidType
*type
)
1686 struct winbind_cache
*cache
= get_cache(domain
);
1687 struct cache_entry
*centry
= NULL
;
1694 centry
= wcache_fetch(cache
, domain
, "SN/%s",
1695 sid_to_fstring(sid_string
, sid
));
1699 status
= centry
->status
;
1700 if (NT_STATUS_IS_OK(status
)) {
1701 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1702 *domain_name
= centry_string(centry
, mem_ctx
);
1703 *name
= centry_string(centry
, mem_ctx
);
1706 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: %s\n",
1707 domain
->name
, nt_errstr(status
) ));
1709 centry_free(centry
);
1714 *domain_name
= NULL
;
1716 /* If the seq number check indicated that there is a problem
1717 * with this DC, then return that status... except for
1718 * access_denied. This is special because the dc may be in
1719 * "restrict anonymous = 1" mode, in which case it will deny
1720 * most unauthenticated operations, but *will* allow the LSA
1721 * sid-to-name that we try as a fallback. */
1723 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1724 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1725 return domain
->last_status
;
1727 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1730 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1733 refresh_sequence_number(domain
, false);
1734 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
1736 /* We can't save the name to sid mapping here, as with sid history a
1737 * later name2sid would give the wrong sid. */
1742 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
1743 TALLOC_CTX
*mem_ctx
,
1744 const DOM_SID
*domain_sid
,
1749 enum lsa_SidType
**types
)
1751 struct winbind_cache
*cache
= get_cache(domain
);
1753 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1757 *domain_name
= NULL
;
1765 if (num_rids
== 0) {
1766 return NT_STATUS_OK
;
1769 *names
= TALLOC_ARRAY(mem_ctx
, char *, num_rids
);
1770 *types
= TALLOC_ARRAY(mem_ctx
, enum lsa_SidType
, num_rids
);
1772 if ((*names
== NULL
) || (*types
== NULL
)) {
1773 result
= NT_STATUS_NO_MEMORY
;
1777 have_mapped
= have_unmapped
= false;
1779 for (i
=0; i
<num_rids
; i
++) {
1781 struct cache_entry
*centry
;
1784 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
1785 result
= NT_STATUS_INTERNAL_ERROR
;
1789 centry
= wcache_fetch(cache
, domain
, "SN/%s",
1790 sid_to_fstring(tmp
, &sid
));
1795 (*types
)[i
] = SID_NAME_UNKNOWN
;
1796 (*names
)[i
] = talloc_strdup(*names
, "");
1798 if (NT_STATUS_IS_OK(centry
->status
)) {
1801 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
1803 dom
= centry_string(centry
, mem_ctx
);
1804 if (*domain_name
== NULL
) {
1810 (*names
)[i
] = centry_string(centry
, *names
);
1812 } else if (NT_STATUS_EQUAL(centry
->status
, NT_STATUS_NONE_MAPPED
)) {
1813 have_unmapped
= true;
1816 /* something's definitely wrong */
1817 result
= centry
->status
;
1821 centry_free(centry
);
1825 return NT_STATUS_NONE_MAPPED
;
1827 if (!have_unmapped
) {
1828 return NT_STATUS_OK
;
1830 return STATUS_SOME_UNMAPPED
;
1834 TALLOC_FREE(*names
);
1835 TALLOC_FREE(*types
);
1837 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
1838 rids
, num_rids
, domain_name
,
1842 None of the queried rids has been found so save all negative entries
1844 if (NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
)) {
1845 for (i
= 0; i
< num_rids
; i
++) {
1847 const char *name
= "";
1848 const enum lsa_SidType type
= SID_NAME_UNKNOWN
;
1849 NTSTATUS status
= NT_STATUS_NONE_MAPPED
;
1851 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
1852 return NT_STATUS_INTERNAL_ERROR
;
1855 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
1863 Some or all of the queried rids have been found.
1865 if (!NT_STATUS_IS_OK(result
) &&
1866 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
1870 refresh_sequence_number(domain
, false);
1872 for (i
=0; i
<num_rids
; i
++) {
1876 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
1877 result
= NT_STATUS_INTERNAL_ERROR
;
1881 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
1882 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
1884 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
1885 (*names
)[i
], (*types
)[i
]);
1892 TALLOC_FREE(*names
);
1893 TALLOC_FREE(*types
);
1897 /* Lookup user information from a rid */
1898 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
1899 TALLOC_CTX
*mem_ctx
,
1900 const DOM_SID
*user_sid
,
1901 WINBIND_USERINFO
*info
)
1903 struct winbind_cache
*cache
= get_cache(domain
);
1904 struct cache_entry
*centry
= NULL
;
1911 centry
= wcache_fetch(cache
, domain
, "U/%s",
1912 sid_to_fstring(tmp
, user_sid
));
1914 /* If we have an access denied cache entry and a cached info3 in the
1915 samlogon cache then do a query. This will force the rpc back end
1916 to return the info3 data. */
1918 if (NT_STATUS_V(domain
->last_status
) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED
) &&
1919 netsamlogon_cache_have(user_sid
)) {
1920 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1921 domain
->last_status
= NT_STATUS_OK
;
1922 centry_free(centry
);
1929 /* if status is not ok then this is a negative hit
1930 and the rest of the data doesn't matter */
1931 status
= centry
->status
;
1932 if (NT_STATUS_IS_OK(status
)) {
1933 info
->acct_name
= centry_string(centry
, mem_ctx
);
1934 info
->full_name
= centry_string(centry
, mem_ctx
);
1935 info
->homedir
= centry_string(centry
, mem_ctx
);
1936 info
->shell
= centry_string(centry
, mem_ctx
);
1937 info
->primary_gid
= centry_uint32(centry
);
1938 centry_sid(centry
, mem_ctx
, &info
->user_sid
);
1939 centry_sid(centry
, mem_ctx
, &info
->group_sid
);
1942 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: %s\n",
1943 domain
->name
, nt_errstr(status
) ));
1945 centry_free(centry
);
1951 /* Return status value returned by seq number check */
1953 if (!NT_STATUS_IS_OK(domain
->last_status
))
1954 return domain
->last_status
;
1956 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
1959 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
1962 refresh_sequence_number(domain
, false);
1963 wcache_save_user(domain
, status
, info
);
1969 /* Lookup groups a user is a member of. */
1970 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
1971 TALLOC_CTX
*mem_ctx
,
1972 const DOM_SID
*user_sid
,
1973 uint32
*num_groups
, DOM_SID
**user_gids
)
1975 struct winbind_cache
*cache
= get_cache(domain
);
1976 struct cache_entry
*centry
= NULL
;
1984 centry
= wcache_fetch(cache
, domain
, "UG/%s",
1985 sid_to_fstring(sid_string
, user_sid
));
1987 /* If we have an access denied cache entry and a cached info3 in the
1988 samlogon cache then do a query. This will force the rpc back end
1989 to return the info3 data. */
1991 if (NT_STATUS_V(domain
->last_status
) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED
) &&
1992 netsamlogon_cache_have(user_sid
)) {
1993 DEBUG(10, ("lookup_usergroups: cached access denied and have cached info3\n"));
1994 domain
->last_status
= NT_STATUS_OK
;
1995 centry_free(centry
);
2002 *num_groups
= centry_uint32(centry
);
2004 if (*num_groups
== 0)
2007 (*user_gids
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_groups
);
2008 if (! (*user_gids
)) {
2009 smb_panic_fn("lookup_usergroups out of memory");
2011 for (i
=0; i
<(*num_groups
); i
++) {
2012 centry_sid(centry
, mem_ctx
, &(*user_gids
)[i
]);
2016 status
= centry
->status
;
2018 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status: %s\n",
2019 domain
->name
, nt_errstr(status
) ));
2021 centry_free(centry
);
2026 (*user_gids
) = NULL
;
2028 /* Return status value returned by seq number check */
2030 if (!NT_STATUS_IS_OK(domain
->last_status
))
2031 return domain
->last_status
;
2033 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
2036 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
2038 if ( NT_STATUS_EQUAL(status
, NT_STATUS_SYNCHRONIZATION_REQUIRED
) )
2042 refresh_sequence_number(domain
, false);
2043 centry
= centry_start(domain
, status
);
2047 centry_put_uint32(centry
, *num_groups
);
2048 for (i
=0; i
<(*num_groups
); i
++) {
2049 centry_put_sid(centry
, &(*user_gids
)[i
]);
2052 centry_end(centry
, "UG/%s", sid_to_fstring(sid_string
, user_sid
));
2053 centry_free(centry
);
2059 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
2060 TALLOC_CTX
*mem_ctx
,
2061 uint32 num_sids
, const DOM_SID
*sids
,
2062 uint32
*num_aliases
, uint32
**alias_rids
)
2064 struct winbind_cache
*cache
= get_cache(domain
);
2065 struct cache_entry
*centry
= NULL
;
2067 char *sidlist
= talloc_strdup(mem_ctx
, "");
2073 if (num_sids
== 0) {
2076 return NT_STATUS_OK
;
2079 /* We need to cache indexed by the whole list of SIDs, the aliases
2080 * resulting might come from any of the SIDs. */
2082 for (i
=0; i
<num_sids
; i
++) {
2084 sidlist
= talloc_asprintf(mem_ctx
, "%s/%s", sidlist
,
2085 sid_to_fstring(tmp
, &sids
[i
]));
2086 if (sidlist
== NULL
)
2087 return NT_STATUS_NO_MEMORY
;
2090 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
2095 *num_aliases
= centry_uint32(centry
);
2099 (*alias_rids
) = TALLOC_ARRAY(mem_ctx
, uint32
, *num_aliases
);
2101 if ((*alias_rids
) == NULL
) {
2102 centry_free(centry
);
2103 return NT_STATUS_NO_MEMORY
;
2106 (*alias_rids
) = NULL
;
2109 for (i
=0; i
<(*num_aliases
); i
++)
2110 (*alias_rids
)[i
] = centry_uint32(centry
);
2112 status
= centry
->status
;
2114 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
2115 "status %s\n", domain
->name
, nt_errstr(status
)));
2117 centry_free(centry
);
2122 (*alias_rids
) = NULL
;
2124 if (!NT_STATUS_IS_OK(domain
->last_status
))
2125 return domain
->last_status
;
2127 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
2128 "for domain %s\n", domain
->name
));
2130 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
2132 num_aliases
, alias_rids
);
2135 refresh_sequence_number(domain
, false);
2136 centry
= centry_start(domain
, status
);
2139 centry_put_uint32(centry
, *num_aliases
);
2140 for (i
=0; i
<(*num_aliases
); i
++)
2141 centry_put_uint32(centry
, (*alias_rids
)[i
]);
2142 centry_end(centry
, "UA%s", sidlist
);
2143 centry_free(centry
);
2150 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
2151 TALLOC_CTX
*mem_ctx
,
2152 const DOM_SID
*group_sid
, uint32
*num_names
,
2153 DOM_SID
**sid_mem
, char ***names
,
2154 uint32
**name_types
)
2156 struct winbind_cache
*cache
= get_cache(domain
);
2157 struct cache_entry
*centry
= NULL
;
2165 centry
= wcache_fetch(cache
, domain
, "GM/%s",
2166 sid_to_fstring(sid_string
, group_sid
));
2170 *num_names
= centry_uint32(centry
);
2172 if (*num_names
== 0)
2175 (*sid_mem
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_names
);
2176 (*names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_names
);
2177 (*name_types
) = TALLOC_ARRAY(mem_ctx
, uint32
, *num_names
);
2179 if (! (*sid_mem
) || ! (*names
) || ! (*name_types
)) {
2180 smb_panic_fn("lookup_groupmem out of memory");
2183 for (i
=0; i
<(*num_names
); i
++) {
2184 centry_sid(centry
, mem_ctx
, &(*sid_mem
)[i
]);
2185 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2186 (*name_types
)[i
] = centry_uint32(centry
);
2190 status
= centry
->status
;
2192 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status: %s\n",
2193 domain
->name
, nt_errstr(status
)));
2195 centry_free(centry
);
2202 (*name_types
) = NULL
;
2204 /* Return status value returned by seq number check */
2206 if (!NT_STATUS_IS_OK(domain
->last_status
))
2207 return domain
->last_status
;
2209 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
2212 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
2213 sid_mem
, names
, name_types
);
2216 refresh_sequence_number(domain
, false);
2217 centry
= centry_start(domain
, status
);
2220 centry_put_uint32(centry
, *num_names
);
2221 for (i
=0; i
<(*num_names
); i
++) {
2222 centry_put_sid(centry
, &(*sid_mem
)[i
]);
2223 centry_put_string(centry
, (*names
)[i
]);
2224 centry_put_uint32(centry
, (*name_types
)[i
]);
2226 centry_end(centry
, "GM/%s", sid_to_fstring(sid_string
, group_sid
));
2227 centry_free(centry
);
2233 /* find the sequence number for a domain */
2234 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
2236 refresh_sequence_number(domain
, false);
2238 *seq
= domain
->sequence_number
;
2240 return NT_STATUS_OK
;
2243 /* enumerate trusted domains
2244 * (we need to have the list of trustdoms in the cache when we go offline) -
2246 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
2247 TALLOC_CTX
*mem_ctx
,
2248 uint32
*num_domains
,
2253 struct winbind_cache
*cache
= get_cache(domain
);
2254 struct cache_entry
*centry
= NULL
;
2261 centry
= wcache_fetch(cache
, domain
, "TRUSTDOMS/%s", domain
->name
);
2267 *num_domains
= centry_uint32(centry
);
2270 (*names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
2271 (*alt_names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
2272 (*dom_sids
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_domains
);
2274 if (! (*dom_sids
) || ! (*names
) || ! (*alt_names
)) {
2275 smb_panic_fn("trusted_domains out of memory");
2279 (*alt_names
) = NULL
;
2283 for (i
=0; i
<(*num_domains
); i
++) {
2284 (*names
)[i
] = centry_string(centry
, mem_ctx
);
2285 (*alt_names
)[i
] = centry_string(centry
, mem_ctx
);
2286 if (!centry_sid(centry
, mem_ctx
, &(*dom_sids
)[i
])) {
2287 sid_copy(&(*dom_sids
)[i
], &global_sid_NULL
);
2291 status
= centry
->status
;
2293 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
2294 domain
->name
, *num_domains
, nt_errstr(status
) ));
2296 centry_free(centry
);
2303 (*alt_names
) = NULL
;
2305 /* Return status value returned by seq number check */
2307 if (!NT_STATUS_IS_OK(domain
->last_status
))
2308 return domain
->last_status
;
2310 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
2313 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, num_domains
,
2314 names
, alt_names
, dom_sids
);
2316 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
2317 * so that the generic centry handling still applies correctly -
2320 if (!NT_STATUS_IS_ERR(status
)) {
2321 status
= NT_STATUS_OK
;
2325 #if 0 /* Disabled as we want the trust dom list to be managed by
2326 the main parent and always to make the query. --jerry */
2329 refresh_sequence_number(domain
, false);
2331 centry
= centry_start(domain
, status
);
2335 centry_put_uint32(centry
, *num_domains
);
2337 for (i
=0; i
<(*num_domains
); i
++) {
2338 centry_put_string(centry
, (*names
)[i
]);
2339 centry_put_string(centry
, (*alt_names
)[i
]);
2340 centry_put_sid(centry
, &(*dom_sids
)[i
]);
2343 centry_end(centry
, "TRUSTDOMS/%s", domain
->name
);
2345 centry_free(centry
);
2353 /* get lockout policy */
2354 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
2355 TALLOC_CTX
*mem_ctx
,
2356 struct samr_DomInfo12
*policy
)
2358 struct winbind_cache
*cache
= get_cache(domain
);
2359 struct cache_entry
*centry
= NULL
;
2365 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2370 policy
->lockout_duration
= centry_nttime(centry
);
2371 policy
->lockout_window
= centry_nttime(centry
);
2372 policy
->lockout_threshold
= centry_uint16(centry
);
2374 status
= centry
->status
;
2376 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2377 domain
->name
, nt_errstr(status
) ));
2379 centry_free(centry
);
2383 ZERO_STRUCTP(policy
);
2385 /* Return status value returned by seq number check */
2387 if (!NT_STATUS_IS_OK(domain
->last_status
))
2388 return domain
->last_status
;
2390 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2393 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2396 refresh_sequence_number(domain
, false);
2397 wcache_save_lockout_policy(domain
, status
, policy
);
2402 /* get password policy */
2403 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
2404 TALLOC_CTX
*mem_ctx
,
2405 struct samr_DomInfo1
*policy
)
2407 struct winbind_cache
*cache
= get_cache(domain
);
2408 struct cache_entry
*centry
= NULL
;
2414 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2419 policy
->min_password_length
= centry_uint16(centry
);
2420 policy
->password_history_length
= centry_uint16(centry
);
2421 policy
->password_properties
= centry_uint32(centry
);
2422 policy
->max_password_age
= centry_nttime(centry
);
2423 policy
->min_password_age
= centry_nttime(centry
);
2425 status
= centry
->status
;
2427 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2428 domain
->name
, nt_errstr(status
) ));
2430 centry_free(centry
);
2434 ZERO_STRUCTP(policy
);
2436 /* Return status value returned by seq number check */
2438 if (!NT_STATUS_IS_OK(domain
->last_status
))
2439 return domain
->last_status
;
2441 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2444 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
2447 refresh_sequence_number(domain
, false);
2448 if (NT_STATUS_IS_OK(status
)) {
2449 wcache_save_password_policy(domain
, status
, policy
);
2456 /* Invalidate cached user and group lists coherently */
2458 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2461 if (strncmp((const char *)kbuf
.dptr
, "UL/", 3) == 0 ||
2462 strncmp((const char *)kbuf
.dptr
, "GL/", 3) == 0)
2463 tdb_delete(the_tdb
, kbuf
);
2468 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2470 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
2471 struct netr_SamInfo3
*info3
)
2474 fstring key_str
, sid_string
;
2475 struct winbind_cache
*cache
;
2477 /* dont clear cached U/SID and UG/SID entries when we want to logon
2480 if (lp_winbind_offline_logon()) {
2487 cache
= get_cache(domain
);
2493 sid_copy(&sid
, info3
->base
.domain_sid
);
2494 sid_append_rid(&sid
, info3
->base
.rid
);
2496 /* Clear U/SID cache entry */
2497 fstr_sprintf(key_str
, "U/%s", sid_to_fstring(sid_string
, &sid
));
2498 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
2499 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
2501 /* Clear UG/SID cache entry */
2502 fstr_sprintf(key_str
, "UG/%s", sid_to_fstring(sid_string
, &sid
));
2503 DEBUG(10, ("wcache_invalidate_samlogon: clearing %s\n", key_str
));
2504 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
2506 /* Samba/winbindd never needs this. */
2507 netsamlogon_clear_cached_user(info3
);
2510 bool wcache_invalidate_cache(void)
2512 struct winbindd_domain
*domain
;
2514 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
2515 struct winbind_cache
*cache
= get_cache(domain
);
2517 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2518 "entries for %s\n", domain
->name
));
2521 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
2530 bool init_wcache(void)
2532 if (wcache
== NULL
) {
2533 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
2534 ZERO_STRUCTP(wcache
);
2537 if (wcache
->tdb
!= NULL
)
2540 /* when working offline we must not clear the cache on restart */
2541 wcache
->tdb
= tdb_open_log(cache_path("winbindd_cache.tdb"),
2542 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
2543 lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
2544 O_RDWR
|O_CREAT
, 0600);
2546 if (wcache
->tdb
== NULL
) {
2547 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2554 /************************************************************************
2555 This is called by the parent to initialize the cache file.
2556 We don't need sophisticated locking here as we know we're the
2558 ************************************************************************/
2560 bool initialize_winbindd_cache(void)
2562 bool cache_bad
= true;
2565 if (!init_wcache()) {
2566 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
2570 /* Check version number. */
2571 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
2572 vers
== WINBINDD_CACHE_VERSION
) {
2577 DEBUG(0,("initialize_winbindd_cache: clearing cache "
2578 "and re-creating with version number %d\n",
2579 WINBINDD_CACHE_VERSION
));
2581 tdb_close(wcache
->tdb
);
2584 if (unlink(cache_path("winbindd_cache.tdb")) == -1) {
2585 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
2586 cache_path("winbindd_cache.tdb"),
2590 if (!init_wcache()) {
2591 DEBUG(0,("initialize_winbindd_cache: re-initialization "
2592 "init_wcache failed.\n"));
2596 /* Write the version. */
2597 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
2598 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
2599 tdb_errorstr(wcache
->tdb
) ));
2604 tdb_close(wcache
->tdb
);
2609 void close_winbindd_cache(void)
2615 tdb_close(wcache
->tdb
);
2620 void cache_store_response(pid_t pid
, struct winbindd_response
*response
)
2627 DEBUG(10, ("Storing response for pid %d, len %d\n",
2628 (int)pid
, response
->length
));
2630 fstr_sprintf(key_str
, "DR/%d", (int)pid
);
2631 if (tdb_store(wcache
->tdb
, string_tdb_data(key_str
),
2632 make_tdb_data((uint8
*)response
, sizeof(*response
)),
2636 if (response
->length
== sizeof(*response
))
2639 /* There's extra data */
2641 DEBUG(10, ("Storing extra data: len=%d\n",
2642 (int)(response
->length
- sizeof(*response
))));
2644 fstr_sprintf(key_str
, "DE/%d", (int)pid
);
2645 if (tdb_store(wcache
->tdb
, string_tdb_data(key_str
),
2646 make_tdb_data((uint8
*)response
->extra_data
.data
,
2647 response
->length
- sizeof(*response
)),
2651 /* We could not store the extra data, make sure the tdb does not
2652 * contain a main record with wrong dangling extra data */
2654 fstr_sprintf(key_str
, "DR/%d", (int)pid
);
2655 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2660 bool cache_retrieve_response(pid_t pid
, struct winbindd_response
* response
)
2668 DEBUG(10, ("Retrieving response for pid %d\n", (int)pid
));
2670 fstr_sprintf(key_str
, "DR/%d", (int)pid
);
2671 data
= tdb_fetch(wcache
->tdb
, string_tdb_data(key_str
));
2673 if (data
.dptr
== NULL
)
2676 if (data
.dsize
!= sizeof(*response
))
2679 memcpy(response
, data
.dptr
, data
.dsize
);
2680 SAFE_FREE(data
.dptr
);
2682 if (response
->length
== sizeof(*response
)) {
2683 response
->extra_data
.data
= NULL
;
2687 /* There's extra data */
2689 DEBUG(10, ("Retrieving extra data length=%d\n",
2690 (int)(response
->length
- sizeof(*response
))));
2692 fstr_sprintf(key_str
, "DE/%d", (int)pid
);
2693 data
= tdb_fetch(wcache
->tdb
, string_tdb_data(key_str
));
2695 if (data
.dptr
== NULL
) {
2696 DEBUG(0, ("Did not find extra data\n"));
2700 if (data
.dsize
!= (response
->length
- sizeof(*response
))) {
2701 DEBUG(0, ("Invalid extra data length: %d\n", (int)data
.dsize
));
2702 SAFE_FREE(data
.dptr
);
2706 dump_data(11, (uint8
*)data
.dptr
, data
.dsize
);
2708 response
->extra_data
.data
= data
.dptr
;
2712 void cache_cleanup_response(pid_t pid
)
2719 fstr_sprintf(key_str
, "DR/%d", (int)pid
);
2720 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2722 fstr_sprintf(key_str
, "DE/%d", (int)pid
);
2723 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2729 bool lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const DOM_SID
*sid
,
2730 char **domain_name
, char **name
,
2731 enum lsa_SidType
*type
)
2733 struct winbindd_domain
*domain
;
2734 struct winbind_cache
*cache
;
2735 struct cache_entry
*centry
= NULL
;
2739 domain
= find_lookup_domain_from_sid(sid
);
2740 if (domain
== NULL
) {
2744 cache
= get_cache(domain
);
2746 if (cache
->tdb
== NULL
) {
2750 centry
= wcache_fetch(cache
, domain
, "SN/%s",
2751 sid_to_fstring(tmp
, sid
));
2752 if (centry
== NULL
) {
2756 if (NT_STATUS_IS_OK(centry
->status
)) {
2757 *type
= (enum lsa_SidType
)centry_uint32(centry
);
2758 *domain_name
= centry_string(centry
, mem_ctx
);
2759 *name
= centry_string(centry
, mem_ctx
);
2762 status
= centry
->status
;
2763 centry_free(centry
);
2764 return NT_STATUS_IS_OK(status
);
2767 bool lookup_cached_name(TALLOC_CTX
*mem_ctx
,
2768 const char *domain_name
,
2771 enum lsa_SidType
*type
)
2773 struct winbindd_domain
*domain
;
2774 struct winbind_cache
*cache
;
2775 struct cache_entry
*centry
= NULL
;
2778 bool original_online_state
;
2780 domain
= find_lookup_domain_from_name(domain_name
);
2781 if (domain
== NULL
) {
2785 cache
= get_cache(domain
);
2787 if (cache
->tdb
== NULL
) {
2791 fstrcpy(uname
, name
);
2794 /* If we are doing a cached logon, temporarily set the domain
2795 offline so the cache won't expire the entry */
2797 original_online_state
= domain
->online
;
2798 domain
->online
= false;
2799 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
2800 domain
->online
= original_online_state
;
2802 if (centry
== NULL
) {
2806 if (NT_STATUS_IS_OK(centry
->status
)) {
2807 *type
= (enum lsa_SidType
)centry_uint32(centry
);
2808 centry_sid(centry
, mem_ctx
, sid
);
2811 status
= centry
->status
;
2812 centry_free(centry
);
2814 return NT_STATUS_IS_OK(status
);
2817 void cache_name2sid(struct winbindd_domain
*domain
,
2818 const char *domain_name
, const char *name
,
2819 enum lsa_SidType type
, const DOM_SID
*sid
)
2821 refresh_sequence_number(domain
, false);
2822 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
2827 * The original idea that this cache only contains centries has
2828 * been blurred - now other stuff gets put in here. Ensure we
2829 * ignore these things on cleanup.
2832 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
2833 TDB_DATA dbuf
, void *state
)
2835 struct cache_entry
*centry
;
2837 if (is_non_centry_key(kbuf
)) {
2841 centry
= wcache_fetch_raw((char *)kbuf
.dptr
);
2846 if (!NT_STATUS_IS_OK(centry
->status
)) {
2847 DEBUG(10,("deleting centry %s\n", (const char *)kbuf
.dptr
));
2848 tdb_delete(the_tdb
, kbuf
);
2851 centry_free(centry
);
2855 /* flush the cache */
2856 void wcache_flush_cache(void)
2861 tdb_close(wcache
->tdb
);
2864 if (!winbindd_use_cache()) {
2868 /* when working offline we must not clear the cache on restart */
2869 wcache
->tdb
= tdb_open_log(cache_path("winbindd_cache.tdb"),
2870 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
2871 lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
2872 O_RDWR
|O_CREAT
, 0600);
2875 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2879 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
2881 DEBUG(10,("wcache_flush_cache success\n"));
2884 /* Count cached creds */
2886 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2889 int *cred_count
= (int*)state
;
2891 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
2897 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
2899 struct winbind_cache
*cache
= get_cache(domain
);
2904 return NT_STATUS_INTERNAL_DB_ERROR
;
2907 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
2909 return NT_STATUS_OK
;
2913 struct cred_list
*prev
, *next
;
2918 static struct cred_list
*wcache_cred_list
;
2920 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2923 struct cred_list
*cred
;
2925 if (strncmp((const char *)kbuf
.dptr
, "CRED/", 5) == 0) {
2927 cred
= SMB_MALLOC_P(struct cred_list
);
2929 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2935 /* save a copy of the key */
2937 fstrcpy(cred
->name
, (const char *)kbuf
.dptr
);
2938 DLIST_ADD(wcache_cred_list
, cred
);
2944 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const DOM_SID
*sid
)
2946 struct winbind_cache
*cache
= get_cache(domain
);
2949 struct cred_list
*cred
, *oldest
= NULL
;
2952 return NT_STATUS_INTERNAL_DB_ERROR
;
2955 /* we possibly already have an entry */
2956 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
2958 fstring key_str
, tmp
;
2960 DEBUG(11,("we already have an entry, deleting that\n"));
2962 fstr_sprintf(key_str
, "CRED/%s", sid_to_fstring(tmp
, sid
));
2964 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
2966 return NT_STATUS_OK
;
2969 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
2971 return NT_STATUS_OK
;
2972 } else if ((ret
== -1) || (wcache_cred_list
== NULL
)) {
2973 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2976 ZERO_STRUCTP(oldest
);
2978 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
2983 data
= tdb_fetch(cache
->tdb
, string_tdb_data(cred
->name
));
2985 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
2987 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2991 t
= IVAL(data
.dptr
, 0);
2992 SAFE_FREE(data
.dptr
);
2995 oldest
= SMB_MALLOC_P(struct cred_list
);
2996 if (oldest
== NULL
) {
2997 status
= NT_STATUS_NO_MEMORY
;
3001 fstrcpy(oldest
->name
, cred
->name
);
3002 oldest
->created
= t
;
3006 if (t
< oldest
->created
) {
3007 fstrcpy(oldest
->name
, cred
->name
);
3008 oldest
->created
= t
;
3012 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
3013 status
= NT_STATUS_OK
;
3015 status
= NT_STATUS_UNSUCCESSFUL
;
3018 SAFE_FREE(wcache_cred_list
);
3024 /* Change the global online/offline state. */
3025 bool set_global_winbindd_state_offline(void)
3029 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
3031 /* Only go offline if someone has created
3032 the key "WINBINDD_OFFLINE" in the cache tdb. */
3034 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3035 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
3039 if (!lp_winbind_offline_logon()) {
3040 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
3044 if (global_winbindd_offline_state
) {
3045 /* Already offline. */
3049 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
3051 if (!data
.dptr
|| data
.dsize
!= 4) {
3052 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
3053 SAFE_FREE(data
.dptr
);
3056 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
3057 global_winbindd_offline_state
= true;
3058 SAFE_FREE(data
.dptr
);
3063 void set_global_winbindd_state_online(void)
3065 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
3067 if (!lp_winbind_offline_logon()) {
3068 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
3072 if (!global_winbindd_offline_state
) {
3073 /* Already online. */
3076 global_winbindd_offline_state
= false;
3082 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
3083 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
3086 bool get_global_winbindd_state_offline(void)
3088 return global_winbindd_offline_state
;
3091 /***********************************************************************
3092 Validate functions for all possible cache tdb keys.
3093 ***********************************************************************/
3095 static struct cache_entry
*create_centry_validate(const char *kstr
, TDB_DATA data
,
3096 struct tdb_validation_status
*state
)
3098 struct cache_entry
*centry
;
3100 centry
= SMB_XMALLOC_P(struct cache_entry
);
3101 centry
->data
= (unsigned char *)memdup(data
.dptr
, data
.dsize
);
3102 if (!centry
->data
) {
3106 centry
->len
= data
.dsize
;
3109 if (centry
->len
< 8) {
3110 /* huh? corrupt cache? */
3111 DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr
));
3112 centry_free(centry
);
3113 state
->bad_entry
= true;
3114 state
->success
= false;
3118 centry
->status
= NT_STATUS(centry_uint32(centry
));
3119 centry
->sequence_number
= centry_uint32(centry
);
3123 static int validate_seqnum(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3124 struct tdb_validation_status
*state
)
3126 if (dbuf
.dsize
!= 8) {
3127 DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
3128 keystr
, (unsigned int)dbuf
.dsize
));
3129 state
->bad_entry
= true;
3135 static int validate_ns(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
);
3143 (void)centry_uint32(centry
);
3144 if (NT_STATUS_IS_OK(centry
->status
)) {
3146 (void)centry_sid(centry
, mem_ctx
, &sid
);
3149 centry_free(centry
);
3151 if (!(state
->success
)) {
3154 DEBUG(10,("validate_ns: %s ok\n", keystr
));
3158 static int validate_sn(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3159 struct tdb_validation_status
*state
)
3161 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3166 if (NT_STATUS_IS_OK(centry
->status
)) {
3167 (void)centry_uint32(centry
);
3168 (void)centry_string(centry
, mem_ctx
);
3169 (void)centry_string(centry
, mem_ctx
);
3172 centry_free(centry
);
3174 if (!(state
->success
)) {
3177 DEBUG(10,("validate_sn: %s ok\n", keystr
));
3181 static int validate_u(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3182 struct tdb_validation_status
*state
)
3184 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3191 (void)centry_string(centry
, mem_ctx
);
3192 (void)centry_string(centry
, mem_ctx
);
3193 (void)centry_string(centry
, mem_ctx
);
3194 (void)centry_string(centry
, mem_ctx
);
3195 (void)centry_uint32(centry
);
3196 (void)centry_sid(centry
, mem_ctx
, &sid
);
3197 (void)centry_sid(centry
, mem_ctx
, &sid
);
3199 centry_free(centry
);
3201 if (!(state
->success
)) {
3204 DEBUG(10,("validate_u: %s ok\n", keystr
));
3208 static int validate_loc_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3209 struct tdb_validation_status
*state
)
3211 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3217 (void)centry_nttime(centry
);
3218 (void)centry_nttime(centry
);
3219 (void)centry_uint16(centry
);
3221 centry_free(centry
);
3223 if (!(state
->success
)) {
3226 DEBUG(10,("validate_loc_pol: %s ok\n", keystr
));
3230 static int validate_pwd_pol(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3231 struct tdb_validation_status
*state
)
3233 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3239 (void)centry_uint16(centry
);
3240 (void)centry_uint16(centry
);
3241 (void)centry_uint32(centry
);
3242 (void)centry_nttime(centry
);
3243 (void)centry_nttime(centry
);
3245 centry_free(centry
);
3247 if (!(state
->success
)) {
3250 DEBUG(10,("validate_pwd_pol: %s ok\n", keystr
));
3254 static int validate_cred(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3255 struct tdb_validation_status
*state
)
3257 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3263 (void)centry_time(centry
);
3264 (void)centry_hash16(centry
, mem_ctx
);
3266 /* We only have 17 bytes more data in the salted cred case. */
3267 if (centry
->len
- centry
->ofs
== 17) {
3268 (void)centry_hash16(centry
, mem_ctx
);
3271 centry_free(centry
);
3273 if (!(state
->success
)) {
3276 DEBUG(10,("validate_cred: %s ok\n", keystr
));
3280 static int validate_ul(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3281 struct tdb_validation_status
*state
)
3283 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3284 int32 num_entries
, i
;
3290 num_entries
= (int32
)centry_uint32(centry
);
3292 for (i
=0; i
< num_entries
; i
++) {
3294 (void)centry_string(centry
, mem_ctx
);
3295 (void)centry_string(centry
, mem_ctx
);
3296 (void)centry_string(centry
, mem_ctx
);
3297 (void)centry_string(centry
, mem_ctx
);
3298 (void)centry_sid(centry
, mem_ctx
, &sid
);
3299 (void)centry_sid(centry
, mem_ctx
, &sid
);
3302 centry_free(centry
);
3304 if (!(state
->success
)) {
3307 DEBUG(10,("validate_ul: %s ok\n", keystr
));
3311 static int validate_gl(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3312 struct tdb_validation_status
*state
)
3314 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3315 int32 num_entries
, i
;
3321 num_entries
= centry_uint32(centry
);
3323 for (i
=0; i
< num_entries
; i
++) {
3324 (void)centry_string(centry
, mem_ctx
);
3325 (void)centry_string(centry
, mem_ctx
);
3326 (void)centry_uint32(centry
);
3329 centry_free(centry
);
3331 if (!(state
->success
)) {
3334 DEBUG(10,("validate_gl: %s ok\n", keystr
));
3338 static int validate_ug(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3339 struct tdb_validation_status
*state
)
3341 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3342 int32 num_groups
, i
;
3348 num_groups
= centry_uint32(centry
);
3350 for (i
=0; i
< num_groups
; i
++) {
3352 centry_sid(centry
, mem_ctx
, &sid
);
3355 centry_free(centry
);
3357 if (!(state
->success
)) {
3360 DEBUG(10,("validate_ug: %s ok\n", keystr
));
3364 static int validate_ua(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3365 struct tdb_validation_status
*state
)
3367 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3368 int32 num_aliases
, i
;
3374 num_aliases
= centry_uint32(centry
);
3376 for (i
=0; i
< num_aliases
; i
++) {
3377 (void)centry_uint32(centry
);
3380 centry_free(centry
);
3382 if (!(state
->success
)) {
3385 DEBUG(10,("validate_ua: %s ok\n", keystr
));
3389 static int validate_gm(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3390 struct tdb_validation_status
*state
)
3392 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3399 num_names
= centry_uint32(centry
);
3401 for (i
=0; i
< num_names
; i
++) {
3403 centry_sid(centry
, mem_ctx
, &sid
);
3404 (void)centry_string(centry
, mem_ctx
);
3405 (void)centry_uint32(centry
);
3408 centry_free(centry
);
3410 if (!(state
->success
)) {
3413 DEBUG(10,("validate_gm: %s ok\n", keystr
));
3417 static int validate_dr(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3418 struct tdb_validation_status
*state
)
3420 /* Can't say anything about this other than must be nonzero. */
3421 if (dbuf
.dsize
== 0) {
3422 DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n",
3424 state
->bad_entry
= true;
3425 state
->success
= false;
3429 DEBUG(10,("validate_dr: %s ok\n", keystr
));
3433 static int validate_de(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3434 struct tdb_validation_status
*state
)
3436 /* Can't say anything about this other than must be nonzero. */
3437 if (dbuf
.dsize
== 0) {
3438 DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n",
3440 state
->bad_entry
= true;
3441 state
->success
= false;
3445 DEBUG(10,("validate_de: %s ok\n", keystr
));
3449 static int validate_pwinfo(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3450 TDB_DATA dbuf
, struct tdb_validation_status
*state
)
3452 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3458 (void)centry_string(centry
, mem_ctx
);
3459 (void)centry_string(centry
, mem_ctx
);
3460 (void)centry_string(centry
, mem_ctx
);
3461 (void)centry_uint32(centry
);
3463 centry_free(centry
);
3465 if (!(state
->success
)) {
3468 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3472 static int validate_nss_an(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3474 struct tdb_validation_status
*state
)
3476 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3482 (void)centry_string( centry
, mem_ctx
);
3484 centry_free(centry
);
3486 if (!(state
->success
)) {
3489 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3493 static int validate_nss_na(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3495 struct tdb_validation_status
*state
)
3497 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3503 (void)centry_string( centry
, mem_ctx
);
3505 centry_free(centry
);
3507 if (!(state
->success
)) {
3510 DEBUG(10,("validate_pwinfo: %s ok\n", keystr
));
3514 static int validate_trustdoms(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3515 struct tdb_validation_status
*state
)
3517 struct cache_entry
*centry
= create_centry_validate(keystr
, dbuf
, state
);
3518 int32 num_domains
, i
;
3524 num_domains
= centry_uint32(centry
);
3526 for (i
=0; i
< num_domains
; i
++) {
3528 (void)centry_string(centry
, mem_ctx
);
3529 (void)centry_string(centry
, mem_ctx
);
3530 (void)centry_sid(centry
, mem_ctx
, &sid
);
3533 centry_free(centry
);
3535 if (!(state
->success
)) {
3538 DEBUG(10,("validate_trustdoms: %s ok\n", keystr
));
3542 static int validate_trustdomcache(TALLOC_CTX
*mem_ctx
, const char *keystr
,
3544 struct tdb_validation_status
*state
)
3546 if (dbuf
.dsize
== 0) {
3547 DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
3548 "key %s (len ==0) ?\n", keystr
));
3549 state
->bad_entry
= true;
3550 state
->success
= false;
3554 DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr
));
3555 DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n"));
3559 static int validate_offline(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3560 struct tdb_validation_status
*state
)
3562 if (dbuf
.dsize
!= 4) {
3563 DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
3564 keystr
, (unsigned int)dbuf
.dsize
));
3565 state
->bad_entry
= true;
3566 state
->success
= false;
3569 DEBUG(10,("validate_offline: %s ok\n", keystr
));
3573 static int validate_cache_version(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
,
3574 struct tdb_validation_status
*state
)
3576 if (dbuf
.dsize
!= 4) {
3577 DEBUG(0, ("validate_cache_version: Corrupt cache for "
3578 "key %s (len %u != 4) ?\n",
3579 keystr
, (unsigned int)dbuf
.dsize
));
3580 state
->bad_entry
= true;
3581 state
->success
= false;
3585 DEBUG(10, ("validate_cache_version: %s ok\n", keystr
));
3589 /***********************************************************************
3590 A list of all possible cache tdb keys with associated validation
3592 ***********************************************************************/
3594 struct key_val_struct
{
3595 const char *keyname
;
3596 int (*validate_data_fn
)(TALLOC_CTX
*mem_ctx
, const char *keystr
, TDB_DATA dbuf
, struct tdb_validation_status
* state
);
3598 {"SEQNUM/", validate_seqnum
},
3599 {"NS/", validate_ns
},
3600 {"SN/", validate_sn
},
3602 {"LOC_POL/", validate_loc_pol
},
3603 {"PWD_POL/", validate_pwd_pol
},
3604 {"CRED/", validate_cred
},
3605 {"UL/", validate_ul
},
3606 {"GL/", validate_gl
},
3607 {"UG/", validate_ug
},
3608 {"UA", validate_ua
},
3609 {"GM/", validate_gm
},
3610 {"DR/", validate_dr
},
3611 {"DE/", validate_de
},
3612 {"NSS/PWINFO/", validate_pwinfo
},
3613 {"TRUSTDOMS/", validate_trustdoms
},
3614 {"TRUSTDOMCACHE/", validate_trustdomcache
},
3615 {"NSS/NA/", validate_nss_na
},
3616 {"NSS/AN/", validate_nss_an
},
3617 {"WINBINDD_OFFLINE", validate_offline
},
3618 {WINBINDD_CACHE_VERSION_KEYSTR
, validate_cache_version
},
3622 /***********************************************************************
3623 Function to look at every entry in the tdb and validate it as far as
3625 ***********************************************************************/
3627 static int cache_traverse_validate_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
3630 unsigned int max_key_len
= 1024;
3631 struct tdb_validation_status
*v_state
= (struct tdb_validation_status
*)state
;
3633 /* Paranoia check. */
3634 if (strncmp("UA/", (const char *)kbuf
.dptr
, 3) == 0) {
3635 max_key_len
= 1024 * 1024;
3637 if (kbuf
.dsize
> max_key_len
) {
3638 DEBUG(0, ("cache_traverse_validate_fn: key length too large: "
3640 (unsigned int)kbuf
.dsize
, (unsigned int)max_key_len
));
3644 for (i
= 0; key_val
[i
].keyname
; i
++) {
3645 size_t namelen
= strlen(key_val
[i
].keyname
);
3646 if (kbuf
.dsize
>= namelen
&& (
3647 strncmp(key_val
[i
].keyname
, (const char *)kbuf
.dptr
, namelen
)) == 0) {
3648 TALLOC_CTX
*mem_ctx
;
3652 keystr
= SMB_MALLOC_ARRAY(char, kbuf
.dsize
+1);
3656 memcpy(keystr
, kbuf
.dptr
, kbuf
.dsize
);
3657 keystr
[kbuf
.dsize
] = '\0';
3659 mem_ctx
= talloc_init("validate_ctx");
3665 ret
= key_val
[i
].validate_data_fn(mem_ctx
, keystr
, dbuf
,
3669 talloc_destroy(mem_ctx
);
3674 DEBUG(0,("cache_traverse_validate_fn: unknown cache entry\nkey :\n"));
3675 dump_data(0, (uint8
*)kbuf
.dptr
, kbuf
.dsize
);
3676 DEBUG(0,("data :\n"));
3677 dump_data(0, (uint8
*)dbuf
.dptr
, dbuf
.dsize
);
3678 v_state
->unknown_key
= true;
3679 v_state
->success
= false;
3680 return 1; /* terminate. */
3683 static void validate_panic(const char *const why
)
3685 DEBUG(0,("validating cache: would panic %s\n", why
));
3686 DEBUGADD(0, ("exiting instead (cache validation mode)\n"));
3690 /***********************************************************************
3691 Try and validate every entry in the winbindd cache. If we fail here,
3692 delete the cache tdb and return non-zero.
3693 ***********************************************************************/
3695 int winbindd_validate_cache(void)
3698 const char *tdb_path
= cache_path("winbindd_cache.tdb");
3699 TDB_CONTEXT
*tdb
= NULL
;
3701 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3702 smb_panic_fn
= validate_panic
;
3705 tdb
= tdb_open_log(tdb_path
,
3706 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
3707 ( lp_winbind_offline_logon()
3709 : TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
3713 DEBUG(0, ("winbindd_validate_cache: "
3714 "error opening/initializing tdb\n"));
3719 ret
= tdb_validate_and_backup(tdb_path
, cache_traverse_validate_fn
);
3722 DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
3723 DEBUGADD(10, ("removing tdb %s.\n", tdb_path
));
3728 DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
3729 smb_panic_fn
= smb_panic
;
3733 /***********************************************************************
3734 Try and validate every entry in the winbindd cache.
3735 ***********************************************************************/
3737 int winbindd_validate_cache_nobackup(void)
3740 const char *tdb_path
= cache_path("winbindd_cache.tdb");
3742 DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
3743 smb_panic_fn
= validate_panic
;
3746 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
3747 ret
= tdb_validate_open(tdb_path
, cache_traverse_validate_fn
);
3749 ret
= tdb_validate(wcache
->tdb
, cache_traverse_validate_fn
);
3753 DEBUG(10, ("winbindd_validate_cache_nobackup: validation not "
3757 DEBUG(10, ("winbindd_validate_cache_nobackup: restoring panic "
3759 smb_panic_fn
= smb_panic
;
3763 bool winbindd_cache_validate_and_initialize(void)
3765 close_winbindd_cache();
3767 if (lp_winbind_offline_logon()) {
3768 if (winbindd_validate_cache() < 0) {
3769 DEBUG(0, ("winbindd cache tdb corrupt and no backup "
3770 "could be restored.\n"));
3774 return initialize_winbindd_cache();
3777 /*********************************************************************
3778 ********************************************************************/
3780 static bool add_wbdomain_to_tdc_array( struct winbindd_domain
*new_dom
,
3781 struct winbindd_tdc_domain
**domains
,
3782 size_t *num_domains
)
3784 struct winbindd_tdc_domain
*list
= NULL
;
3787 bool set_only
= false;
3789 /* don't allow duplicates */
3794 for ( i
=0; i
< (*num_domains
); i
++ ) {
3795 if ( strequal( new_dom
->name
, list
[i
].domain_name
) ) {
3796 DEBUG(10,("add_wbdomain_to_tdc_array: Found existing record for %s\n",
3807 list
= TALLOC_ARRAY( NULL
, struct winbindd_tdc_domain
, 1 );
3810 list
= TALLOC_REALLOC_ARRAY( *domains
, *domains
,
3811 struct winbindd_tdc_domain
,
3816 ZERO_STRUCT( list
[idx
] );
3822 list
[idx
].domain_name
= talloc_strdup( list
, new_dom
->name
);
3823 list
[idx
].dns_name
= talloc_strdup( list
, new_dom
->alt_name
);
3825 if ( !is_null_sid( &new_dom
->sid
) ) {
3826 sid_copy( &list
[idx
].sid
, &new_dom
->sid
);
3828 sid_copy(&list
[idx
].sid
, &global_sid_NULL
);
3831 if ( new_dom
->domain_flags
!= 0x0 )
3832 list
[idx
].trust_flags
= new_dom
->domain_flags
;
3834 if ( new_dom
->domain_type
!= 0x0 )
3835 list
[idx
].trust_type
= new_dom
->domain_type
;
3837 if ( new_dom
->domain_trust_attribs
!= 0x0 )
3838 list
[idx
].trust_attribs
= new_dom
->domain_trust_attribs
;
3842 *num_domains
= idx
+ 1;
3848 /*********************************************************************
3849 ********************************************************************/
3851 static TDB_DATA
make_tdc_key( const char *domain_name
)
3853 char *keystr
= NULL
;
3854 TDB_DATA key
= { NULL
, 0 };
3856 if ( !domain_name
) {
3857 DEBUG(5,("make_tdc_key: Keyname workgroup is NULL!\n"));
3862 if (asprintf( &keystr
, "TRUSTDOMCACHE/%s", domain_name
) == -1) {
3865 key
= string_term_tdb_data(keystr
);
3870 /*********************************************************************
3871 ********************************************************************/
3873 static int pack_tdc_domains( struct winbindd_tdc_domain
*domains
,
3875 unsigned char **buf
)
3877 unsigned char *buffer
= NULL
;
3882 DEBUG(10,("pack_tdc_domains: Packing %d trusted domains\n",
3890 /* Store the number of array items first */
3891 len
+= tdb_pack( buffer
+len
, buflen
-len
, "d",
3894 /* now pack each domain trust record */
3895 for ( i
=0; i
<num_domains
; i
++ ) {
3900 DEBUG(10,("pack_tdc_domains: Packing domain %s (%s)\n",
3901 domains
[i
].domain_name
,
3902 domains
[i
].dns_name
? domains
[i
].dns_name
: "UNKNOWN" ));
3905 len
+= tdb_pack( buffer
+len
, buflen
-len
, "fffddd",
3906 domains
[i
].domain_name
,
3907 domains
[i
].dns_name
,
3908 sid_to_fstring(tmp
, &domains
[i
].sid
),
3909 domains
[i
].trust_flags
,
3910 domains
[i
].trust_attribs
,
3911 domains
[i
].trust_type
);
3914 if ( buflen
< len
) {
3916 if ( (buffer
= SMB_MALLOC_ARRAY(unsigned char, len
)) == NULL
) {
3917 DEBUG(0,("pack_tdc_domains: failed to alloc buffer!\n"));
3931 /*********************************************************************
3932 ********************************************************************/
3934 static size_t unpack_tdc_domains( unsigned char *buf
, int buflen
,
3935 struct winbindd_tdc_domain
**domains
)
3937 fstring domain_name
, dns_name
, sid_string
;
3938 uint32 type
, attribs
, flags
;
3942 struct winbindd_tdc_domain
*list
= NULL
;
3944 /* get the number of domains */
3945 len
+= tdb_unpack( buf
+len
, buflen
-len
, "d", &num_domains
);
3947 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3951 list
= TALLOC_ARRAY( NULL
, struct winbindd_tdc_domain
, num_domains
);
3953 DEBUG(0,("unpack_tdc_domains: Failed to talloc() domain list!\n"));
3957 for ( i
=0; i
<num_domains
; i
++ ) {
3958 len
+= tdb_unpack( buf
+len
, buflen
-len
, "fffddd",
3967 DEBUG(5,("unpack_tdc_domains: Failed to unpack domain array\n"));
3968 TALLOC_FREE( list
);
3972 DEBUG(11,("unpack_tdc_domains: Unpacking domain %s (%s) "
3973 "SID %s, flags = 0x%x, attribs = 0x%x, type = 0x%x\n",
3974 domain_name
, dns_name
, sid_string
,
3975 flags
, attribs
, type
));
3977 list
[i
].domain_name
= talloc_strdup( list
, domain_name
);
3978 list
[i
].dns_name
= talloc_strdup( list
, dns_name
);
3979 if ( !string_to_sid( &(list
[i
].sid
), sid_string
) ) {
3980 DEBUG(10,("unpack_tdc_domains: no SID for domain %s\n",
3983 list
[i
].trust_flags
= flags
;
3984 list
[i
].trust_attribs
= attribs
;
3985 list
[i
].trust_type
= type
;
3993 /*********************************************************************
3994 ********************************************************************/
3996 static bool wcache_tdc_store_list( struct winbindd_tdc_domain
*domains
, size_t num_domains
)
3998 TDB_DATA key
= make_tdc_key( lp_workgroup() );
3999 TDB_DATA data
= { NULL
, 0 };
4005 /* See if we were asked to delete the cache entry */
4008 ret
= tdb_delete( wcache
->tdb
, key
);
4012 data
.dsize
= pack_tdc_domains( domains
, num_domains
, &data
.dptr
);
4019 ret
= tdb_store( wcache
->tdb
, key
, data
, 0 );
4022 SAFE_FREE( data
.dptr
);
4023 SAFE_FREE( key
.dptr
);
4025 return ( ret
!= -1 );
4028 /*********************************************************************
4029 ********************************************************************/
4031 bool wcache_tdc_fetch_list( struct winbindd_tdc_domain
**domains
, size_t *num_domains
)
4033 TDB_DATA key
= make_tdc_key( lp_workgroup() );
4034 TDB_DATA data
= { NULL
, 0 };
4042 data
= tdb_fetch( wcache
->tdb
, key
);
4044 SAFE_FREE( key
.dptr
);
4049 *num_domains
= unpack_tdc_domains( data
.dptr
, data
.dsize
, domains
);
4051 SAFE_FREE( data
.dptr
);
4059 /*********************************************************************
4060 ********************************************************************/
4062 bool wcache_tdc_add_domain( struct winbindd_domain
*domain
)
4064 struct winbindd_tdc_domain
*dom_list
= NULL
;
4065 size_t num_domains
= 0;
4068 DEBUG(10,("wcache_tdc_add_domain: Adding domain %s (%s), SID %s, "
4069 "flags = 0x%x, attributes = 0x%x, type = 0x%x\n",
4070 domain
->name
, domain
->alt_name
,
4071 sid_string_dbg(&domain
->sid
),
4072 domain
->domain_flags
,
4073 domain
->domain_trust_attribs
,
4074 domain
->domain_type
));
4076 if ( !init_wcache() ) {
4080 /* fetch the list */
4082 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4084 /* add the new domain */
4086 if ( !add_wbdomain_to_tdc_array( domain
, &dom_list
, &num_domains
) ) {
4090 /* pack the domain */
4092 if ( !wcache_tdc_store_list( dom_list
, num_domains
) ) {
4100 TALLOC_FREE( dom_list
);
4105 /*********************************************************************
4106 ********************************************************************/
4108 struct winbindd_tdc_domain
* wcache_tdc_fetch_domain( TALLOC_CTX
*ctx
, const char *name
)
4110 struct winbindd_tdc_domain
*dom_list
= NULL
;
4111 size_t num_domains
= 0;
4113 struct winbindd_tdc_domain
*d
= NULL
;
4115 DEBUG(10,("wcache_tdc_fetch_domain: Searching for domain %s\n", name
));
4117 if ( !init_wcache() ) {
4121 /* fetch the list */
4123 wcache_tdc_fetch_list( &dom_list
, &num_domains
);
4125 for ( i
=0; i
<num_domains
; i
++ ) {
4126 if ( strequal(name
, dom_list
[i
].domain_name
) ||
4127 strequal(name
, dom_list
[i
].dns_name
) )
4129 DEBUG(10,("wcache_tdc_fetch_domain: Found domain %s\n",
4132 d
= TALLOC_P( ctx
, struct winbindd_tdc_domain
);
4136 d
->domain_name
= talloc_strdup( d
, dom_list
[i
].domain_name
);
4137 d
->dns_name
= talloc_strdup( d
, dom_list
[i
].dns_name
);
4138 sid_copy( &d
->sid
, &dom_list
[i
].sid
);
4139 d
->trust_flags
= dom_list
[i
].trust_flags
;
4140 d
->trust_type
= dom_list
[i
].trust_type
;
4141 d
->trust_attribs
= dom_list
[i
].trust_attribs
;
4147 TALLOC_FREE( dom_list
);
4153 /*********************************************************************
4154 ********************************************************************/
4156 void wcache_tdc_clear( void )
4158 if ( !init_wcache() )
4161 wcache_tdc_store_list( NULL
, 0 );
4167 /*********************************************************************
4168 ********************************************************************/
4170 static void wcache_save_user_pwinfo(struct winbindd_domain
*domain
,
4172 const DOM_SID
*user_sid
,
4173 const char *homedir
,
4178 struct cache_entry
*centry
;
4181 if ( (centry
= centry_start(domain
, status
)) == NULL
)
4184 centry_put_string( centry
, homedir
);
4185 centry_put_string( centry
, shell
);
4186 centry_put_string( centry
, gecos
);
4187 centry_put_uint32( centry
, gid
);
4189 centry_end(centry
, "NSS/PWINFO/%s", sid_to_fstring(tmp
, user_sid
) );
4191 DEBUG(10,("wcache_save_user_pwinfo: %s\n", sid_string_dbg(user_sid
) ));
4193 centry_free(centry
);
4196 NTSTATUS
nss_get_info_cached( struct winbindd_domain
*domain
,
4197 const DOM_SID
*user_sid
,
4199 ADS_STRUCT
*ads
, LDAPMessage
*msg
,
4200 char **homedir
, char **shell
, char **gecos
,
4203 struct winbind_cache
*cache
= get_cache(domain
);
4204 struct cache_entry
*centry
= NULL
;
4211 centry
= wcache_fetch(cache
, domain
, "NSS/PWINFO/%s",
4212 sid_to_fstring(tmp
, user_sid
));
4217 *homedir
= centry_string( centry
, ctx
);
4218 *shell
= centry_string( centry
, ctx
);
4219 *gecos
= centry_string( centry
, ctx
);
4220 *p_gid
= centry_uint32( centry
);
4222 centry_free(centry
);
4224 DEBUG(10,("nss_get_info_cached: [Cached] - user_sid %s\n",
4225 sid_string_dbg(user_sid
)));
4227 return NT_STATUS_OK
;
4231 nt_status
= nss_get_info( domain
->name
, user_sid
, ctx
, ads
, msg
,
4232 homedir
, shell
, gecos
, p_gid
);
4234 DEBUG(10, ("nss_get_info returned %s\n", nt_errstr(nt_status
)));
4236 if ( NT_STATUS_IS_OK(nt_status
) ) {
4237 DEBUG(10, ("result:\n\thomedir = '%s'\n", *homedir
));
4238 DEBUGADD(10, ("\tshell = '%s'\n", *shell
));
4239 DEBUGADD(10, ("\tgecos = '%s'\n", *gecos
));
4240 DEBUGADD(10, ("\tgid = '%u'\n", (unsigned int)*p_gid
));
4242 wcache_save_user_pwinfo( domain
, nt_status
, user_sid
,
4243 *homedir
, *shell
, *gecos
, *p_gid
);
4246 if ( NT_STATUS_EQUAL( nt_status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) ) {
4247 DEBUG(5,("nss_get_info_cached: Setting domain %s offline\n",
4249 set_domain_offline( domain
);
4256 /* the cache backend methods are exposed via this structure */
4257 struct winbindd_methods cache_methods
= {