2 Unix SMB/CIFS implementation.
4 Winbind cache backend functions
6 Copyright (C) Andrew Tridgell 2001
7 Copyright (C) Gerald Carter 2003
8 Copyright (C) Volker Lendecke 2005
9 Copyright (C) Guenther Deschner 2005
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30 #define DBGC_CLASS DBGC_WINBIND
32 /* Global online/offline state - False when online. winbindd starts up online
33 and sets this to true if the first query fails and there's an entry in
34 the cache tdb telling us to stay offline. */
36 static BOOL global_winbindd_offline_state
;
38 struct winbind_cache
{
44 uint32 sequence_number
;
49 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
51 static struct winbind_cache
*wcache
;
53 void winbindd_check_cache_size(time_t t
)
55 static time_t last_check_time
;
58 if (last_check_time
== (time_t)0)
61 if (t
- last_check_time
< 60 && t
- last_check_time
> 0)
64 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
65 DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
69 if (fstat(tdb_fd(wcache
->tdb
), &st
) == -1) {
70 DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno
) ));
74 if (st
.st_size
> WINBINDD_MAX_CACHE_SIZE
) {
75 DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
76 (unsigned long)st
.st_size
,
77 (unsigned long)WINBINDD_MAX_CACHE_SIZE
));
82 /* get the winbind_cache structure */
83 static struct winbind_cache
*get_cache(struct winbindd_domain
*domain
)
85 struct winbind_cache
*ret
= wcache
;
87 struct winbindd_domain
*our_domain
= domain
;
90 /* we have to know what type of domain we are dealing with first */
92 if ( !domain
->initialized
)
93 init_dc_connection( domain
);
96 OK. listen up becasue I'm only going to say this once.
97 We have the following scenarios to consider
98 (a) trusted AD domains on a Samba DC,
99 (b) trusted AD domains and we are joined to a non-kerberos domain
100 (c) trusted AD domains and we are joined to a kerberos (AD) domain
102 For (a) we can always contact the trusted domain using krb5
103 since we have the domain trust account password
105 For (b) we can only use RPC since we have no way of
106 getting a krb5 ticket in our own domain
108 For (c) we can always use krb5 since we have a kerberos trust
113 if (!domain
->backend
) {
114 extern struct winbindd_methods reconnect_methods
;
116 extern struct winbindd_methods ads_methods
;
118 /* find our domain first so we can figure out if we
119 are joined to a kerberized domain */
121 if ( !domain
->primary
)
122 our_domain
= find_our_domain();
124 if ( (our_domain
->active_directory
|| IS_DC
) && domain
->active_directory
) {
125 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain
->name
));
126 domain
->backend
= &ads_methods
;
128 #endif /* HAVE_ADS */
129 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain
->name
));
130 domain
->backend
= &reconnect_methods
;
133 #endif /* HAVE_ADS */
139 ret
= SMB_XMALLOC_P(struct winbind_cache
);
143 wcache_flush_cache();
149 free a centry structure
151 static void centry_free(struct cache_entry
*centry
)
155 SAFE_FREE(centry
->data
);
160 pull a uint32 from a cache entry
162 static uint32
centry_uint32(struct cache_entry
*centry
)
165 if (centry
->len
- centry
->ofs
< 4) {
166 DEBUG(0,("centry corruption? needed 4 bytes, have %d\n",
167 centry
->len
- centry
->ofs
));
168 smb_panic("centry_uint32");
170 ret
= IVAL(centry
->data
, centry
->ofs
);
176 pull a uint16 from a cache entry
178 static uint16
centry_uint16(struct cache_entry
*centry
)
181 if (centry
->len
- centry
->ofs
< 2) {
182 DEBUG(0,("centry corruption? needed 2 bytes, have %d\n",
183 centry
->len
- centry
->ofs
));
184 smb_panic("centry_uint16");
186 ret
= CVAL(centry
->data
, centry
->ofs
);
192 pull a uint8 from a cache entry
194 static uint8
centry_uint8(struct cache_entry
*centry
)
197 if (centry
->len
- centry
->ofs
< 1) {
198 DEBUG(0,("centry corruption? needed 1 bytes, have %d\n",
199 centry
->len
- centry
->ofs
));
200 smb_panic("centry_uint32");
202 ret
= CVAL(centry
->data
, centry
->ofs
);
208 pull a NTTIME from a cache entry
210 static NTTIME
centry_nttime(struct cache_entry
*centry
)
213 if (centry
->len
- centry
->ofs
< 8) {
214 DEBUG(0,("centry corruption? needed 8 bytes, have %d\n",
215 centry
->len
- centry
->ofs
));
216 smb_panic("centry_nttime");
218 ret
= IVAL(centry
->data
, centry
->ofs
);
220 ret
+= (uint64_t)IVAL(centry
->data
, centry
->ofs
) << 32;
226 pull a time_t from a cache entry
228 static time_t centry_time(struct cache_entry
*centry
)
231 if (centry
->len
- centry
->ofs
< sizeof(time_t)) {
232 DEBUG(0,("centry corruption? needed %u bytes, have %u\n",
233 (unsigned int)sizeof(time_t), (unsigned int)(centry
->len
- centry
->ofs
)));
234 smb_panic("centry_time");
236 ret
= IVAL(centry
->data
, centry
->ofs
); /* FIXME: correct ? */
237 centry
->ofs
+= sizeof(time_t);
241 /* pull a string from a cache entry, using the supplied
244 static char *centry_string(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
249 len
= centry_uint8(centry
);
252 /* a deliberate NULL string */
256 if (centry
->len
- centry
->ofs
< len
) {
257 DEBUG(0,("centry corruption? needed %d bytes, have %d\n",
258 len
, centry
->len
- centry
->ofs
));
259 smb_panic("centry_string");
262 ret
= TALLOC_ARRAY(mem_ctx
, char, len
+1);
264 smb_panic("centry_string out of memory\n");
266 memcpy(ret
,centry
->data
+ centry
->ofs
, len
);
272 /* pull a hash16 from a cache entry, using the supplied
275 static char *centry_hash16(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
280 len
= centry_uint8(centry
);
283 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
288 if (centry
->len
- centry
->ofs
< 16) {
289 DEBUG(0,("centry corruption? needed 16 bytes, have %d\n",
290 centry
->len
- centry
->ofs
));
294 ret
= TALLOC_ARRAY(mem_ctx
, char, 16);
296 smb_panic("centry_hash out of memory\n");
298 memcpy(ret
,centry
->data
+ centry
->ofs
, 16);
303 /* pull a sid from a cache entry, using the supplied
306 static BOOL
centry_sid(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
, DOM_SID
*sid
)
309 sid_string
= centry_string(centry
, mem_ctx
);
310 if ((sid_string
== NULL
) || (!string_to_sid(sid
, sid_string
))) {
316 /* the server is considered down if it can't give us a sequence number */
317 static BOOL
wcache_server_down(struct winbindd_domain
*domain
)
324 ret
= (domain
->sequence_number
== DOM_SEQUENCE_NONE
);
327 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
332 static NTSTATUS
fetch_cache_seqnum( struct winbindd_domain
*domain
, time_t now
)
339 DEBUG(10,("fetch_cache_seqnum: tdb == NULL\n"));
340 return NT_STATUS_UNSUCCESSFUL
;
343 fstr_sprintf( key
, "SEQNUM/%s", domain
->name
);
345 data
= tdb_fetch_bystring( wcache
->tdb
, key
);
346 if ( !data
.dptr
|| data
.dsize
!=8 ) {
347 DEBUG(10,("fetch_cache_seqnum: invalid data size key [%s]\n", key
));
348 return NT_STATUS_UNSUCCESSFUL
;
351 domain
->sequence_number
= IVAL(data
.dptr
, 0);
352 domain
->last_seq_check
= IVAL(data
.dptr
, 4);
354 SAFE_FREE(data
.dptr
);
356 /* have we expired? */
358 time_diff
= now
- domain
->last_seq_check
;
359 if ( time_diff
> lp_winbind_cache_time() ) {
360 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
361 domain
->name
, domain
->sequence_number
,
362 (uint32
)domain
->last_seq_check
));
363 return NT_STATUS_UNSUCCESSFUL
;
366 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
367 domain
->name
, domain
->sequence_number
,
368 (uint32
)domain
->last_seq_check
));
373 static NTSTATUS
store_cache_seqnum( struct winbindd_domain
*domain
)
380 DEBUG(10,("store_cache_seqnum: tdb == NULL\n"));
381 return NT_STATUS_UNSUCCESSFUL
;
384 fstr_sprintf( key_str
, "SEQNUM/%s", domain
->name
);
386 key
.dsize
= strlen(key_str
)+1;
388 SIVAL(buf
, 0, domain
->sequence_number
);
389 SIVAL(buf
, 4, domain
->last_seq_check
);
393 if ( tdb_store( wcache
->tdb
, key
, data
, TDB_REPLACE
) == -1 ) {
394 DEBUG(10,("store_cache_seqnum: tdb_store fail key [%s]\n", key_str
));
395 return NT_STATUS_UNSUCCESSFUL
;
398 DEBUG(10,("store_cache_seqnum: success [%s][%u @ %u]\n",
399 domain
->name
, domain
->sequence_number
,
400 (uint32
)domain
->last_seq_check
));
406 refresh the domain sequence number. If force is True
407 then always refresh it, no matter how recently we fetched it
410 static void refresh_sequence_number(struct winbindd_domain
*domain
, BOOL force
)
414 time_t t
= time(NULL
);
415 unsigned cache_time
= lp_winbind_cache_time();
419 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
420 /* trying to reconnect is expensive, don't do it too often */
421 if (domain
->sequence_number
== DOM_SEQUENCE_NONE
) {
426 time_diff
= t
- domain
->last_seq_check
;
428 /* see if we have to refetch the domain sequence number */
429 if (!force
&& (time_diff
< cache_time
)) {
430 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain
->name
));
434 /* try to get the sequence number from the tdb cache first */
435 /* this will update the timestamp as well */
437 status
= fetch_cache_seqnum( domain
, t
);
438 if ( NT_STATUS_IS_OK(status
) )
441 /* important! make sure that we know if this is a native
442 mode domain or not */
444 status
= domain
->backend
->sequence_number(domain
, &domain
->sequence_number
);
446 if (!NT_STATUS_IS_OK(status
)) {
447 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status
)));
448 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
451 domain
->last_status
= status
;
452 domain
->last_seq_check
= time(NULL
);
454 /* save the new sequence number ni the cache */
455 store_cache_seqnum( domain
);
458 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
459 domain
->name
, domain
->sequence_number
));
465 decide if a cache entry has expired
467 static BOOL
centry_expired(struct winbindd_domain
*domain
, const char *keystr
, struct cache_entry
*centry
)
469 /* If we've been told to be offline - stay in that state... */
470 if (lp_winbind_offline_logon() && global_winbindd_offline_state
) {
471 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
472 keystr
, domain
->name
));
476 /* when the domain is offline return the cached entry.
477 * This deals with transient offline states... */
479 if (!domain
->online
) {
480 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
481 keystr
, domain
->name
));
485 /* if the server is OK and our cache entry came from when it was down then
486 the entry is invalid */
487 if ((domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
488 (centry
->sequence_number
== DOM_SEQUENCE_NONE
)) {
489 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
490 keystr
, domain
->name
));
494 /* if the server is down or the cache entry is not older than the
495 current sequence number then it is OK */
496 if (wcache_server_down(domain
) ||
497 centry
->sequence_number
== domain
->sequence_number
) {
498 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
499 keystr
, domain
->name
));
503 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
504 keystr
, domain
->name
));
510 static struct cache_entry
*wcache_fetch_raw(char *kstr
)
513 struct cache_entry
*centry
;
517 key
.dsize
= strlen(kstr
);
518 data
= tdb_fetch(wcache
->tdb
, key
);
524 centry
= SMB_XMALLOC_P(struct cache_entry
);
525 centry
->data
= (unsigned char *)data
.dptr
;
526 centry
->len
= data
.dsize
;
529 if (centry
->len
< 8) {
530 /* huh? corrupt cache? */
531 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr
));
536 centry
->status
= NT_STATUS(centry_uint32(centry
));
537 centry
->sequence_number
= centry_uint32(centry
);
543 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
544 number and return status
546 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
547 struct winbindd_domain
*domain
,
548 const char *format
, ...) PRINTF_ATTRIBUTE(3,4);
549 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
550 struct winbindd_domain
*domain
,
551 const char *format
, ...)
555 struct cache_entry
*centry
;
557 extern BOOL opt_nocache
;
563 refresh_sequence_number(domain
, False
);
565 va_start(ap
, format
);
566 smb_xvasprintf(&kstr
, format
, ap
);
569 centry
= wcache_fetch_raw(kstr
);
570 if (centry
== NULL
) {
575 if (centry_expired(domain
, kstr
, centry
)) {
577 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
578 kstr
, domain
->name
));
585 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
586 kstr
, domain
->name
));
592 static void wcache_delete(const char *format
, ...) PRINTF_ATTRIBUTE(1,2);
593 static void wcache_delete(const char *format
, ...)
599 va_start(ap
, format
);
600 smb_xvasprintf(&kstr
, format
, ap
);
604 key
.dsize
= strlen(kstr
);
606 tdb_delete(wcache
->tdb
, key
);
611 make sure we have at least len bytes available in a centry
613 static void centry_expand(struct cache_entry
*centry
, uint32 len
)
615 if (centry
->len
- centry
->ofs
>= len
)
618 centry
->data
= SMB_REALLOC_ARRAY(centry
->data
, unsigned char,
621 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry
->len
));
622 smb_panic("out of memory in centry_expand");
627 push a uint32 into a centry
629 static void centry_put_uint32(struct cache_entry
*centry
, uint32 v
)
631 centry_expand(centry
, 4);
632 SIVAL(centry
->data
, centry
->ofs
, v
);
637 push a uint16 into a centry
639 static void centry_put_uint16(struct cache_entry
*centry
, uint16 v
)
641 centry_expand(centry
, 2);
642 SIVAL(centry
->data
, centry
->ofs
, v
);
647 push a uint8 into a centry
649 static void centry_put_uint8(struct cache_entry
*centry
, uint8 v
)
651 centry_expand(centry
, 1);
652 SCVAL(centry
->data
, centry
->ofs
, v
);
657 push a string into a centry
659 static void centry_put_string(struct cache_entry
*centry
, const char *s
)
664 /* null strings are marked as len 0xFFFF */
665 centry_put_uint8(centry
, 0xFF);
670 /* can't handle more than 254 char strings. Truncating is probably best */
672 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len
));
675 centry_put_uint8(centry
, len
);
676 centry_expand(centry
, len
);
677 memcpy(centry
->data
+ centry
->ofs
, s
, len
);
682 push a 16 byte hash into a centry - treat as 16 byte string.
684 static void centry_put_hash16(struct cache_entry
*centry
, const uint8 val
[16])
686 centry_put_uint8(centry
, 16);
687 centry_expand(centry
, 16);
688 memcpy(centry
->data
+ centry
->ofs
, val
, 16);
692 static void centry_put_sid(struct cache_entry
*centry
, const DOM_SID
*sid
)
695 centry_put_string(centry
, sid_to_string(sid_string
, sid
));
699 push a NTTIME into a centry
701 static void centry_put_nttime(struct cache_entry
*centry
, NTTIME nt
)
703 centry_expand(centry
, 8);
704 SIVAL(centry
->data
, centry
->ofs
, nt
& 0xFFFFFFFF);
706 SIVAL(centry
->data
, centry
->ofs
, nt
>> 32);
711 push a time_t into a centry
713 static void centry_put_time(struct cache_entry
*centry
, time_t t
)
715 centry_expand(centry
, sizeof(time_t));
716 SIVAL(centry
->data
, centry
->ofs
, t
); /* FIXME: is this correct ?? */
717 centry
->ofs
+= sizeof(time_t);
721 start a centry for output. When finished, call centry_end()
723 struct cache_entry
*centry_start(struct winbindd_domain
*domain
, NTSTATUS status
)
725 struct cache_entry
*centry
;
730 centry
= SMB_XMALLOC_P(struct cache_entry
);
732 centry
->len
= 8192; /* reasonable default */
733 centry
->data
= SMB_XMALLOC_ARRAY(uint8
, centry
->len
);
735 centry
->sequence_number
= domain
->sequence_number
;
736 centry_put_uint32(centry
, NT_STATUS_V(status
));
737 centry_put_uint32(centry
, centry
->sequence_number
);
742 finish a centry and write it to the tdb
744 static void centry_end(struct cache_entry
*centry
, const char *format
, ...) PRINTF_ATTRIBUTE(2,3);
745 static void centry_end(struct cache_entry
*centry
, const char *format
, ...)
751 va_start(ap
, format
);
752 smb_xvasprintf(&kstr
, format
, ap
);
756 key
.dsize
= strlen(kstr
);
757 data
.dptr
= (char *)centry
->data
;
758 data
.dsize
= centry
->ofs
;
760 tdb_store(wcache
->tdb
, key
, data
, TDB_REPLACE
);
764 static void wcache_save_name_to_sid(struct winbindd_domain
*domain
,
765 NTSTATUS status
, const char *domain_name
,
766 const char *name
, const DOM_SID
*sid
,
767 enum lsa_SidType type
)
769 struct cache_entry
*centry
;
772 centry
= centry_start(domain
, status
);
775 centry_put_uint32(centry
, type
);
776 centry_put_sid(centry
, sid
);
777 fstrcpy(uname
, name
);
779 centry_end(centry
, "NS/%s/%s", domain_name
, uname
);
780 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s\n", domain_name
, uname
,
781 sid_string_static(sid
)));
785 static void wcache_save_sid_to_name(struct winbindd_domain
*domain
, NTSTATUS status
,
786 const DOM_SID
*sid
, const char *domain_name
, const char *name
, enum lsa_SidType type
)
788 struct cache_entry
*centry
;
791 if (is_null_sid(sid
)) {
795 centry
= centry_start(domain
, status
);
798 if (NT_STATUS_IS_OK(status
)) {
799 centry_put_uint32(centry
, type
);
800 centry_put_string(centry
, domain_name
);
801 centry_put_string(centry
, name
);
803 centry_end(centry
, "SN/%s", sid_to_string(sid_string
, sid
));
804 DEBUG(10,("wcache_save_sid_to_name: %s -> %s\n", sid_string
, name
));
809 static void wcache_save_user(struct winbindd_domain
*domain
, NTSTATUS status
, WINBIND_USERINFO
*info
)
811 struct cache_entry
*centry
;
814 if (is_null_sid(&info
->user_sid
)) {
818 centry
= centry_start(domain
, status
);
821 centry_put_string(centry
, info
->acct_name
);
822 centry_put_string(centry
, info
->full_name
);
823 centry_put_string(centry
, info
->homedir
);
824 centry_put_string(centry
, info
->shell
);
825 centry_put_sid(centry
, &info
->user_sid
);
826 centry_put_sid(centry
, &info
->group_sid
);
827 centry_end(centry
, "U/%s", sid_to_string(sid_string
, &info
->user_sid
));
828 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string
, info
->acct_name
));
832 static void wcache_save_lockout_policy(struct winbindd_domain
*domain
, NTSTATUS status
, SAM_UNK_INFO_12
*lockout_policy
)
834 struct cache_entry
*centry
;
836 centry
= centry_start(domain
, status
);
840 centry_put_nttime(centry
, lockout_policy
->duration
);
841 centry_put_nttime(centry
, lockout_policy
->reset_count
);
842 centry_put_uint16(centry
, lockout_policy
->bad_attempt_lockout
);
844 centry_end(centry
, "LOC_POL/%s", domain
->name
);
846 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain
->name
));
851 static void wcache_save_password_policy(struct winbindd_domain
*domain
, NTSTATUS status
, SAM_UNK_INFO_1
*policy
)
853 struct cache_entry
*centry
;
855 centry
= centry_start(domain
, status
);
859 centry_put_uint16(centry
, policy
->min_length_password
);
860 centry_put_uint16(centry
, policy
->password_history
);
861 centry_put_uint32(centry
, policy
->password_properties
);
862 centry_put_nttime(centry
, policy
->expire
);
863 centry_put_nttime(centry
, policy
->min_passwordage
);
865 centry_end(centry
, "PWD_POL/%s", domain
->name
);
867 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
872 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const DOM_SID
*sid
)
874 struct winbind_cache
*cache
= get_cache(domain
);
880 return NT_STATUS_INTERNAL_DB_ERROR
;
883 if (is_null_sid(sid
)) {
884 return NT_STATUS_INVALID_SID
;
887 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
888 return NT_STATUS_INVALID_SID
;
891 fstr_sprintf(key_str
, "CRED/%s", sid_string_static(sid
));
893 data
= tdb_fetch(cache
->tdb
, make_tdb_data(key_str
, strlen(key_str
)));
895 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
898 SAFE_FREE(data
.dptr
);
902 /* Lookup creds for a SID - copes with old (unsalted) creds as well
903 as new salted ones. */
905 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
908 const uint8
**cached_nt_pass
,
909 const uint8
**cached_salt
)
911 struct winbind_cache
*cache
= get_cache(domain
);
912 struct cache_entry
*centry
= NULL
;
918 return NT_STATUS_INTERNAL_DB_ERROR
;
921 if (is_null_sid(sid
)) {
922 return NT_STATUS_INVALID_SID
;
925 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
926 return NT_STATUS_INVALID_SID
;
929 /* Try and get a salted cred first. If we can't
930 fall back to an unsalted cred. */
932 centry
= wcache_fetch(cache
, domain
, "CRED/%s", sid_string_static(sid
));
934 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
935 sid_string_static(sid
)));
936 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
939 t
= centry_time(centry
);
941 /* In the salted case this isn't actually the nt_hash itself,
942 but the MD5 of the salt + nt_hash. Let the caller
943 sort this out. It can tell as we only return the cached_salt
944 if we are returning a salted cred. */
946 *cached_nt_pass
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
947 if (*cached_nt_pass
== NULL
) {
948 const char *sidstr
= sid_string_static(sid
);
950 /* Bad (old) cred cache. Delete and pretend we
952 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
954 wcache_delete("CRED/%s", sidstr
);
956 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
959 /* We only have 17 bytes more data in the salted cred case. */
960 if (centry
->len
- centry
->ofs
== 17) {
961 *cached_salt
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
967 dump_data(100, (const char *)*cached_nt_pass
, NT_HASH_LEN
);
969 dump_data(100, (const char *)*cached_salt
, NT_HASH_LEN
);
972 status
= centry
->status
;
974 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
975 sid_string_static(sid
), nt_errstr(status
) ));
981 /* Store creds for a SID - only writes out new salted ones. */
983 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
986 const uint8 nt_pass
[NT_HASH_LEN
])
988 struct cache_entry
*centry
;
991 uint8 cred_salt
[NT_HASH_LEN
];
992 uint8 salted_hash
[NT_HASH_LEN
];
994 if (is_null_sid(sid
)) {
995 return NT_STATUS_INVALID_SID
;
998 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
999 return NT_STATUS_INVALID_SID
;
1002 centry
= centry_start(domain
, NT_STATUS_OK
);
1004 return NT_STATUS_INTERNAL_DB_ERROR
;
1008 dump_data(100, (const char *)nt_pass
, NT_HASH_LEN
);
1011 centry_put_time(centry
, time(NULL
));
1013 /* Create a salt and then salt the hash. */
1014 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1015 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1017 centry_put_hash16(centry
, salted_hash
);
1018 centry_put_hash16(centry
, cred_salt
);
1019 centry_end(centry
, "CRED/%s", sid_to_string(sid_string
, sid
));
1021 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1023 centry_free(centry
);
1025 return NT_STATUS_OK
;
1029 /* Query display info. This is the basic user list fn */
1030 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
1031 TALLOC_CTX
*mem_ctx
,
1032 uint32
*num_entries
,
1033 WINBIND_USERINFO
**info
)
1035 struct winbind_cache
*cache
= get_cache(domain
);
1036 struct cache_entry
*centry
= NULL
;
1038 unsigned int i
, retry
;
1043 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1047 *num_entries
= centry_uint32(centry
);
1049 if (*num_entries
== 0)
1052 (*info
) = TALLOC_ARRAY(mem_ctx
, WINBIND_USERINFO
, *num_entries
);
1054 smb_panic("query_user_list out of memory");
1055 for (i
=0; i
<(*num_entries
); i
++) {
1056 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
1057 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
1058 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
1059 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
1060 centry_sid(centry
, mem_ctx
, &(*info
)[i
].user_sid
);
1061 centry_sid(centry
, mem_ctx
, &(*info
)[i
].group_sid
);
1065 status
= centry
->status
;
1067 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1068 domain
->name
, nt_errstr(status
) ));
1070 centry_free(centry
);
1077 /* Return status value returned by seq number check */
1079 if (!NT_STATUS_IS_OK(domain
->last_status
))
1080 return domain
->last_status
;
1082 /* Put the query_user_list() in a retry loop. There appears to be
1083 * some bug either with Windows 2000 or Samba's handling of large
1084 * rpc replies. This manifests itself as sudden disconnection
1085 * at a random point in the enumeration of a large (60k) user list.
1086 * The retry loop simply tries the operation again. )-: It's not
1087 * pretty but an acceptable workaround until we work out what the
1088 * real problem is. */
1093 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1096 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
1097 if (!NT_STATUS_IS_OK(status
))
1098 DEBUG(3, ("query_user_list: returned 0x%08x, "
1099 "retrying\n", NT_STATUS_V(status
)));
1100 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1101 DEBUG(3, ("query_user_list: flushing "
1102 "connection cache\n"));
1103 invalidate_cm_connection(&domain
->conn
);
1106 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1110 refresh_sequence_number(domain
, False
);
1111 centry
= centry_start(domain
, status
);
1114 centry_put_uint32(centry
, *num_entries
);
1115 for (i
=0; i
<(*num_entries
); i
++) {
1116 centry_put_string(centry
, (*info
)[i
].acct_name
);
1117 centry_put_string(centry
, (*info
)[i
].full_name
);
1118 centry_put_string(centry
, (*info
)[i
].homedir
);
1119 centry_put_string(centry
, (*info
)[i
].shell
);
1120 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1121 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1122 if (domain
->backend
->consistent
) {
1123 /* when the backend is consistent we can pre-prime some mappings */
1124 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1126 (*info
)[i
].acct_name
,
1127 &(*info
)[i
].user_sid
,
1129 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1130 &(*info
)[i
].user_sid
,
1132 (*info
)[i
].acct_name
,
1134 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1137 centry_end(centry
, "UL/%s", domain
->name
);
1138 centry_free(centry
);
1144 /* list all domain groups */
1145 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
1146 TALLOC_CTX
*mem_ctx
,
1147 uint32
*num_entries
,
1148 struct acct_info
**info
)
1150 struct winbind_cache
*cache
= get_cache(domain
);
1151 struct cache_entry
*centry
= NULL
;
1158 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1162 *num_entries
= centry_uint32(centry
);
1164 if (*num_entries
== 0)
1167 (*info
) = TALLOC_ARRAY(mem_ctx
, struct acct_info
, *num_entries
);
1169 smb_panic("enum_dom_groups out of memory");
1170 for (i
=0; i
<(*num_entries
); i
++) {
1171 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1172 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1173 (*info
)[i
].rid
= centry_uint32(centry
);
1177 status
= centry
->status
;
1179 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1180 domain
->name
, nt_errstr(status
) ));
1182 centry_free(centry
);
1189 /* Return status value returned by seq number check */
1191 if (!NT_STATUS_IS_OK(domain
->last_status
))
1192 return domain
->last_status
;
1194 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1197 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1200 refresh_sequence_number(domain
, False
);
1201 centry
= centry_start(domain
, status
);
1204 centry_put_uint32(centry
, *num_entries
);
1205 for (i
=0; i
<(*num_entries
); i
++) {
1206 centry_put_string(centry
, (*info
)[i
].acct_name
);
1207 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1208 centry_put_uint32(centry
, (*info
)[i
].rid
);
1210 centry_end(centry
, "GL/%s/domain", domain
->name
);
1211 centry_free(centry
);
1217 /* list all domain groups */
1218 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
1219 TALLOC_CTX
*mem_ctx
,
1220 uint32
*num_entries
,
1221 struct acct_info
**info
)
1223 struct winbind_cache
*cache
= get_cache(domain
);
1224 struct cache_entry
*centry
= NULL
;
1231 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1235 *num_entries
= centry_uint32(centry
);
1237 if (*num_entries
== 0)
1240 (*info
) = TALLOC_ARRAY(mem_ctx
, struct acct_info
, *num_entries
);
1242 smb_panic("enum_dom_groups out of memory");
1243 for (i
=0; i
<(*num_entries
); i
++) {
1244 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1245 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1246 (*info
)[i
].rid
= centry_uint32(centry
);
1251 /* If we are returning cached data and the domain controller
1252 is down then we don't know whether the data is up to date
1253 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1256 if (wcache_server_down(domain
)) {
1257 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1258 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1260 status
= centry
->status
;
1262 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1263 domain
->name
, nt_errstr(status
) ));
1265 centry_free(centry
);
1272 /* Return status value returned by seq number check */
1274 if (!NT_STATUS_IS_OK(domain
->last_status
))
1275 return domain
->last_status
;
1277 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1280 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1283 refresh_sequence_number(domain
, False
);
1284 centry
= centry_start(domain
, status
);
1287 centry_put_uint32(centry
, *num_entries
);
1288 for (i
=0; i
<(*num_entries
); i
++) {
1289 centry_put_string(centry
, (*info
)[i
].acct_name
);
1290 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1291 centry_put_uint32(centry
, (*info
)[i
].rid
);
1293 centry_end(centry
, "GL/%s/local", domain
->name
);
1294 centry_free(centry
);
1300 /* convert a single name to a sid in a domain */
1301 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
1302 TALLOC_CTX
*mem_ctx
,
1303 const char *domain_name
,
1306 enum lsa_SidType
*type
)
1308 struct winbind_cache
*cache
= get_cache(domain
);
1309 struct cache_entry
*centry
= NULL
;
1316 fstrcpy(uname
, name
);
1318 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1321 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1322 status
= centry
->status
;
1323 if (NT_STATUS_IS_OK(status
)) {
1324 centry_sid(centry
, mem_ctx
, sid
);
1327 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: %s\n",
1328 domain
->name
, nt_errstr(status
) ));
1330 centry_free(centry
);
1336 /* If the seq number check indicated that there is a problem
1337 * with this DC, then return that status... except for
1338 * access_denied. This is special because the dc may be in
1339 * "restrict anonymous = 1" mode, in which case it will deny
1340 * most unauthenticated operations, but *will* allow the LSA
1341 * name-to-sid that we try as a fallback. */
1343 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1344 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1345 return domain
->last_status
;
1347 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1350 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
, name
, sid
, type
);
1353 if (domain
->online
&& !is_null_sid(sid
)) {
1354 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1357 if (NT_STATUS_IS_OK(status
)) {
1358 strupper_m(CONST_DISCARD(char *,domain_name
));
1359 strlower_m(CONST_DISCARD(char *,name
));
1360 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1366 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1368 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1369 TALLOC_CTX
*mem_ctx
,
1373 enum lsa_SidType
*type
)
1375 struct winbind_cache
*cache
= get_cache(domain
);
1376 struct cache_entry
*centry
= NULL
;
1383 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_to_string(sid_string
, sid
));
1386 if (NT_STATUS_IS_OK(centry
->status
)) {
1387 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1388 *domain_name
= centry_string(centry
, mem_ctx
);
1389 *name
= centry_string(centry
, mem_ctx
);
1391 status
= centry
->status
;
1393 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: %s\n",
1394 domain
->name
, nt_errstr(status
) ));
1396 centry_free(centry
);
1401 *domain_name
= NULL
;
1403 /* If the seq number check indicated that there is a problem
1404 * with this DC, then return that status... except for
1405 * access_denied. This is special because the dc may be in
1406 * "restrict anonymous = 1" mode, in which case it will deny
1407 * most unauthenticated operations, but *will* allow the LSA
1408 * sid-to-name that we try as a fallback. */
1410 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1411 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1412 return domain
->last_status
;
1414 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1417 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1420 refresh_sequence_number(domain
, False
);
1421 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
1423 /* We can't save the name to sid mapping here, as with sid history a
1424 * later name2sid would give the wrong sid. */
1429 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
1430 TALLOC_CTX
*mem_ctx
,
1431 const DOM_SID
*domain_sid
,
1436 enum lsa_SidType
**types
)
1438 struct winbind_cache
*cache
= get_cache(domain
);
1440 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1444 *domain_name
= NULL
;
1452 if (num_rids
== 0) {
1453 return NT_STATUS_OK
;
1456 *names
= TALLOC_ARRAY(mem_ctx
, char *, num_rids
);
1457 *types
= TALLOC_ARRAY(mem_ctx
, enum lsa_SidType
, num_rids
);
1459 if ((*names
== NULL
) || (*types
== NULL
)) {
1460 result
= NT_STATUS_NO_MEMORY
;
1464 have_mapped
= have_unmapped
= False
;
1466 for (i
=0; i
<num_rids
; i
++) {
1468 struct cache_entry
*centry
;
1470 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
1471 result
= NT_STATUS_INTERNAL_ERROR
;
1475 centry
= wcache_fetch(cache
, domain
, "SN/%s",
1476 sid_string_static(&sid
));
1481 (*types
)[i
] = SID_NAME_UNKNOWN
;
1482 (*names
)[i
] = talloc_strdup(*names
, "");
1484 if (NT_STATUS_IS_OK(centry
->status
)) {
1487 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
1488 dom
= centry_string(centry
, mem_ctx
);
1489 if (*domain_name
== NULL
) {
1494 (*names
)[i
] = centry_string(centry
, *names
);
1496 have_unmapped
= True
;
1499 centry_free(centry
);
1503 return NT_STATUS_NONE_MAPPED
;
1505 if (!have_unmapped
) {
1506 return NT_STATUS_OK
;
1508 return STATUS_SOME_UNMAPPED
;
1512 TALLOC_FREE(*names
);
1513 TALLOC_FREE(*types
);
1515 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
1516 rids
, num_rids
, domain_name
,
1519 if (!NT_STATUS_IS_OK(result
) &&
1520 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
1524 refresh_sequence_number(domain
, False
);
1526 for (i
=0; i
<num_rids
; i
++) {
1530 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
1531 result
= NT_STATUS_INTERNAL_ERROR
;
1535 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
1536 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
1538 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
1539 (*names
)[i
], (*types
)[i
]);
1546 TALLOC_FREE(*names
);
1547 TALLOC_FREE(*types
);
1551 /* Lookup user information from a rid */
1552 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
1553 TALLOC_CTX
*mem_ctx
,
1554 const DOM_SID
*user_sid
,
1555 WINBIND_USERINFO
*info
)
1557 struct winbind_cache
*cache
= get_cache(domain
);
1558 struct cache_entry
*centry
= NULL
;
1564 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string_static(user_sid
));
1566 /* If we have an access denied cache entry and a cached info3 in the
1567 samlogon cache then do a query. This will force the rpc back end
1568 to return the info3 data. */
1570 if (NT_STATUS_V(domain
->last_status
) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED
) &&
1571 netsamlogon_cache_have(user_sid
)) {
1572 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1573 domain
->last_status
= NT_STATUS_OK
;
1574 centry_free(centry
);
1581 info
->acct_name
= centry_string(centry
, mem_ctx
);
1582 info
->full_name
= centry_string(centry
, mem_ctx
);
1583 info
->homedir
= centry_string(centry
, mem_ctx
);
1584 info
->shell
= centry_string(centry
, mem_ctx
);
1585 centry_sid(centry
, mem_ctx
, &info
->user_sid
);
1586 centry_sid(centry
, mem_ctx
, &info
->group_sid
);
1587 status
= centry
->status
;
1589 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: %s\n",
1590 domain
->name
, nt_errstr(status
) ));
1592 centry_free(centry
);
1598 /* Return status value returned by seq number check */
1600 if (!NT_STATUS_IS_OK(domain
->last_status
))
1601 return domain
->last_status
;
1603 DEBUG(10,("sid_to_name: [Cached] - doing backend query for info for domain %s\n",
1606 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
1609 refresh_sequence_number(domain
, False
);
1610 wcache_save_user(domain
, status
, info
);
1616 /* Lookup groups a user is a member of. */
1617 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
1618 TALLOC_CTX
*mem_ctx
,
1619 const DOM_SID
*user_sid
,
1620 uint32
*num_groups
, DOM_SID
**user_gids
)
1622 struct winbind_cache
*cache
= get_cache(domain
);
1623 struct cache_entry
*centry
= NULL
;
1631 centry
= wcache_fetch(cache
, domain
, "UG/%s", sid_to_string(sid_string
, user_sid
));
1633 /* If we have an access denied cache entry and a cached info3 in the
1634 samlogon cache then do a query. This will force the rpc back end
1635 to return the info3 data. */
1637 if (NT_STATUS_V(domain
->last_status
) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED
) &&
1638 netsamlogon_cache_have(user_sid
)) {
1639 DEBUG(10, ("lookup_usergroups: cached access denied and have cached info3\n"));
1640 domain
->last_status
= NT_STATUS_OK
;
1641 centry_free(centry
);
1648 *num_groups
= centry_uint32(centry
);
1650 if (*num_groups
== 0)
1653 (*user_gids
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_groups
);
1655 smb_panic("lookup_usergroups out of memory");
1656 for (i
=0; i
<(*num_groups
); i
++) {
1657 centry_sid(centry
, mem_ctx
, &(*user_gids
)[i
]);
1661 status
= centry
->status
;
1663 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status: %s\n",
1664 domain
->name
, nt_errstr(status
) ));
1666 centry_free(centry
);
1671 (*user_gids
) = NULL
;
1673 /* Return status value returned by seq number check */
1675 if (!NT_STATUS_IS_OK(domain
->last_status
))
1676 return domain
->last_status
;
1678 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
1681 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
1684 refresh_sequence_number(domain
, False
);
1685 centry
= centry_start(domain
, status
);
1688 centry_put_uint32(centry
, *num_groups
);
1689 for (i
=0; i
<(*num_groups
); i
++) {
1690 centry_put_sid(centry
, &(*user_gids
)[i
]);
1692 centry_end(centry
, "UG/%s", sid_to_string(sid_string
, user_sid
));
1693 centry_free(centry
);
1699 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
1700 TALLOC_CTX
*mem_ctx
,
1701 uint32 num_sids
, const DOM_SID
*sids
,
1702 uint32
*num_aliases
, uint32
**alias_rids
)
1704 struct winbind_cache
*cache
= get_cache(domain
);
1705 struct cache_entry
*centry
= NULL
;
1707 char *sidlist
= talloc_strdup(mem_ctx
, "");
1713 if (num_sids
== 0) {
1716 return NT_STATUS_OK
;
1719 /* We need to cache indexed by the whole list of SIDs, the aliases
1720 * resulting might come from any of the SIDs. */
1722 for (i
=0; i
<num_sids
; i
++) {
1723 sidlist
= talloc_asprintf(mem_ctx
, "%s/%s", sidlist
,
1724 sid_string_static(&sids
[i
]));
1725 if (sidlist
== NULL
)
1726 return NT_STATUS_NO_MEMORY
;
1729 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
1734 *num_aliases
= centry_uint32(centry
);
1737 (*alias_rids
) = TALLOC_ARRAY(mem_ctx
, uint32
, *num_aliases
);
1739 if ((*num_aliases
!= 0) && ((*alias_rids
) == NULL
)) {
1740 centry_free(centry
);
1741 return NT_STATUS_NO_MEMORY
;
1744 for (i
=0; i
<(*num_aliases
); i
++)
1745 (*alias_rids
)[i
] = centry_uint32(centry
);
1747 status
= centry
->status
;
1749 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
1750 "status %s\n", domain
->name
, nt_errstr(status
)));
1752 centry_free(centry
);
1757 (*alias_rids
) = NULL
;
1759 if (!NT_STATUS_IS_OK(domain
->last_status
))
1760 return domain
->last_status
;
1762 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
1763 "for domain %s\n", domain
->name
));
1765 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
1767 num_aliases
, alias_rids
);
1770 refresh_sequence_number(domain
, False
);
1771 centry
= centry_start(domain
, status
);
1774 centry_put_uint32(centry
, *num_aliases
);
1775 for (i
=0; i
<(*num_aliases
); i
++)
1776 centry_put_uint32(centry
, (*alias_rids
)[i
]);
1777 centry_end(centry
, "UA%s", sidlist
);
1778 centry_free(centry
);
1785 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
1786 TALLOC_CTX
*mem_ctx
,
1787 const DOM_SID
*group_sid
, uint32
*num_names
,
1788 DOM_SID
**sid_mem
, char ***names
,
1789 uint32
**name_types
)
1791 struct winbind_cache
*cache
= get_cache(domain
);
1792 struct cache_entry
*centry
= NULL
;
1800 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_to_string(sid_string
, group_sid
));
1804 *num_names
= centry_uint32(centry
);
1806 if (*num_names
== 0)
1809 (*sid_mem
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_names
);
1810 (*names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_names
);
1811 (*name_types
) = TALLOC_ARRAY(mem_ctx
, uint32
, *num_names
);
1813 if (! (*sid_mem
) || ! (*names
) || ! (*name_types
)) {
1814 smb_panic("lookup_groupmem out of memory");
1817 for (i
=0; i
<(*num_names
); i
++) {
1818 centry_sid(centry
, mem_ctx
, &(*sid_mem
)[i
]);
1819 (*names
)[i
] = centry_string(centry
, mem_ctx
);
1820 (*name_types
)[i
] = centry_uint32(centry
);
1824 status
= centry
->status
;
1826 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status: %s\n",
1827 domain
->name
, nt_errstr(status
)));
1829 centry_free(centry
);
1836 (*name_types
) = NULL
;
1838 /* Return status value returned by seq number check */
1840 if (!NT_STATUS_IS_OK(domain
->last_status
))
1841 return domain
->last_status
;
1843 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
1846 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
1847 sid_mem
, names
, name_types
);
1850 refresh_sequence_number(domain
, False
);
1851 centry
= centry_start(domain
, status
);
1854 centry_put_uint32(centry
, *num_names
);
1855 for (i
=0; i
<(*num_names
); i
++) {
1856 centry_put_sid(centry
, &(*sid_mem
)[i
]);
1857 centry_put_string(centry
, (*names
)[i
]);
1858 centry_put_uint32(centry
, (*name_types
)[i
]);
1860 centry_end(centry
, "GM/%s", sid_to_string(sid_string
, group_sid
));
1861 centry_free(centry
);
1867 /* find the sequence number for a domain */
1868 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
1870 refresh_sequence_number(domain
, False
);
1872 *seq
= domain
->sequence_number
;
1874 return NT_STATUS_OK
;
1877 /* enumerate trusted domains
1878 * (we need to have the list of trustdoms in the cache when we go offline) -
1880 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
1881 TALLOC_CTX
*mem_ctx
,
1882 uint32
*num_domains
,
1887 struct winbind_cache
*cache
= get_cache(domain
);
1888 struct cache_entry
*centry
= NULL
;
1895 centry
= wcache_fetch(cache
, domain
, "TRUSTDOMS/%s", domain
->name
);
1901 *num_domains
= centry_uint32(centry
);
1903 (*names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
1904 (*alt_names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
1905 (*dom_sids
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_domains
);
1907 if (! (*dom_sids
) || ! (*names
) || ! (*alt_names
)) {
1908 smb_panic("trusted_domains out of memory");
1911 for (i
=0; i
<(*num_domains
); i
++) {
1912 (*names
)[i
] = centry_string(centry
, mem_ctx
);
1913 (*alt_names
)[i
] = centry_string(centry
, mem_ctx
);
1914 centry_sid(centry
, mem_ctx
, &(*dom_sids
)[i
]);
1917 status
= centry
->status
;
1919 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
1920 domain
->name
, *num_domains
, nt_errstr(status
) ));
1922 centry_free(centry
);
1929 (*alt_names
) = NULL
;
1931 /* Return status value returned by seq number check */
1933 if (!NT_STATUS_IS_OK(domain
->last_status
))
1934 return domain
->last_status
;
1936 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
1939 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, num_domains
,
1940 names
, alt_names
, dom_sids
);
1942 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
1943 * so that the generic centry handling still applies correctly -
1946 if (!NT_STATUS_IS_ERR(status
)) {
1947 status
= NT_STATUS_OK
;
1951 refresh_sequence_number(domain
, False
);
1953 centry
= centry_start(domain
, status
);
1957 centry_put_uint32(centry
, *num_domains
);
1959 for (i
=0; i
<(*num_domains
); i
++) {
1960 centry_put_string(centry
, (*names
)[i
]);
1961 centry_put_string(centry
, (*alt_names
)[i
]);
1962 centry_put_sid(centry
, &(*dom_sids
)[i
]);
1965 centry_end(centry
, "TRUSTDOMS/%s", domain
->name
);
1967 centry_free(centry
);
1973 /* get lockout policy */
1974 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
1975 TALLOC_CTX
*mem_ctx
,
1976 SAM_UNK_INFO_12
*policy
){
1977 struct winbind_cache
*cache
= get_cache(domain
);
1978 struct cache_entry
*centry
= NULL
;
1984 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
1989 policy
->duration
= centry_nttime(centry
);
1990 policy
->reset_count
= centry_nttime(centry
);
1991 policy
->bad_attempt_lockout
= centry_uint16(centry
);
1993 status
= centry
->status
;
1995 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
1996 domain
->name
, nt_errstr(status
) ));
1998 centry_free(centry
);
2002 ZERO_STRUCTP(policy
);
2004 /* Return status value returned by seq number check */
2006 if (!NT_STATUS_IS_OK(domain
->last_status
))
2007 return domain
->last_status
;
2009 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2012 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2015 refresh_sequence_number(domain
, False
);
2016 wcache_save_lockout_policy(domain
, status
, policy
);
2021 /* get password policy */
2022 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
2023 TALLOC_CTX
*mem_ctx
,
2024 SAM_UNK_INFO_1
*policy
)
2026 struct winbind_cache
*cache
= get_cache(domain
);
2027 struct cache_entry
*centry
= NULL
;
2033 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2038 policy
->min_length_password
= centry_uint16(centry
);
2039 policy
->password_history
= centry_uint16(centry
);
2040 policy
->password_properties
= centry_uint32(centry
);
2041 policy
->expire
= centry_nttime(centry
);
2042 policy
->min_passwordage
= centry_nttime(centry
);
2044 status
= centry
->status
;
2046 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2047 domain
->name
, nt_errstr(status
) ));
2049 centry_free(centry
);
2053 ZERO_STRUCTP(policy
);
2055 /* Return status value returned by seq number check */
2057 if (!NT_STATUS_IS_OK(domain
->last_status
))
2058 return domain
->last_status
;
2060 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2063 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
2066 refresh_sequence_number(domain
, False
);
2067 wcache_save_password_policy(domain
, status
, policy
);
2073 /* Invalidate cached user and group lists coherently */
2075 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2078 if (strncmp(kbuf
.dptr
, "UL/", 3) == 0 ||
2079 strncmp(kbuf
.dptr
, "GL/", 3) == 0)
2080 tdb_delete(the_tdb
, kbuf
);
2085 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2087 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
2088 NET_USER_INFO_3
*info3
)
2090 struct winbind_cache
*cache
;
2095 cache
= get_cache(domain
);
2096 netsamlogon_clear_cached_user(cache
->tdb
, info3
);
2099 void wcache_invalidate_cache(void)
2101 struct winbindd_domain
*domain
;
2103 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
2104 struct winbind_cache
*cache
= get_cache(domain
);
2106 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2107 "entries for %s\n", domain
->name
));
2109 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
2113 static BOOL
init_wcache(void)
2115 if (wcache
== NULL
) {
2116 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
2117 ZERO_STRUCTP(wcache
);
2120 if (wcache
->tdb
!= NULL
)
2123 /* when working offline we must not clear the cache on restart */
2124 wcache
->tdb
= tdb_open_log(lock_path("winbindd_cache.tdb"),
2125 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
2126 lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
2127 O_RDWR
|O_CREAT
, 0600);
2129 if (wcache
->tdb
== NULL
) {
2130 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2137 void cache_store_response(pid_t pid
, struct winbindd_response
*response
)
2144 DEBUG(10, ("Storing response for pid %d, len %d\n",
2145 pid
, response
->length
));
2147 fstr_sprintf(key_str
, "DR/%d", pid
);
2148 if (tdb_store(wcache
->tdb
, string_tdb_data(key_str
),
2149 make_tdb_data((const char *)response
, sizeof(*response
)),
2153 if (response
->length
== sizeof(*response
))
2156 /* There's extra data */
2158 DEBUG(10, ("Storing extra data: len=%d\n",
2159 (int)(response
->length
- sizeof(*response
))));
2161 fstr_sprintf(key_str
, "DE/%d", pid
);
2162 if (tdb_store(wcache
->tdb
, string_tdb_data(key_str
),
2163 make_tdb_data((const char *)response
->extra_data
.data
,
2164 response
->length
- sizeof(*response
)),
2168 /* We could not store the extra data, make sure the tdb does not
2169 * contain a main record with wrong dangling extra data */
2171 fstr_sprintf(key_str
, "DR/%d", pid
);
2172 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2177 BOOL
cache_retrieve_response(pid_t pid
, struct winbindd_response
* response
)
2185 DEBUG(10, ("Retrieving response for pid %d\n", pid
));
2187 fstr_sprintf(key_str
, "DR/%d", pid
);
2188 data
= tdb_fetch(wcache
->tdb
, string_tdb_data(key_str
));
2190 if (data
.dptr
== NULL
)
2193 if (data
.dsize
!= sizeof(*response
))
2196 memcpy(response
, data
.dptr
, data
.dsize
);
2197 SAFE_FREE(data
.dptr
);
2199 if (response
->length
== sizeof(*response
)) {
2200 response
->extra_data
.data
= NULL
;
2204 /* There's extra data */
2206 DEBUG(10, ("Retrieving extra data length=%d\n",
2207 (int)(response
->length
- sizeof(*response
))));
2209 fstr_sprintf(key_str
, "DE/%d", pid
);
2210 data
= tdb_fetch(wcache
->tdb
, string_tdb_data(key_str
));
2212 if (data
.dptr
== NULL
) {
2213 DEBUG(0, ("Did not find extra data\n"));
2217 if (data
.dsize
!= (response
->length
- sizeof(*response
))) {
2218 DEBUG(0, ("Invalid extra data length: %d\n", (int)data
.dsize
));
2219 SAFE_FREE(data
.dptr
);
2223 dump_data(11, data
.dptr
, data
.dsize
);
2225 response
->extra_data
.data
= data
.dptr
;
2229 void cache_cleanup_response(pid_t pid
)
2236 fstr_sprintf(key_str
, "DR/%d", pid
);
2237 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2239 fstr_sprintf(key_str
, "DE/%d", pid
);
2240 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2246 BOOL
lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const DOM_SID
*sid
,
2247 const char **domain_name
, const char **name
,
2248 enum lsa_SidType
*type
)
2250 struct winbindd_domain
*domain
;
2251 struct winbind_cache
*cache
;
2252 struct cache_entry
*centry
= NULL
;
2255 domain
= find_lookup_domain_from_sid(sid
);
2256 if (domain
== NULL
) {
2260 cache
= get_cache(domain
);
2262 if (cache
->tdb
== NULL
) {
2266 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_string_static(sid
));
2267 if (centry
== NULL
) {
2271 if (NT_STATUS_IS_OK(centry
->status
)) {
2272 *type
= (enum lsa_SidType
)centry_uint32(centry
);
2273 *domain_name
= centry_string(centry
, mem_ctx
);
2274 *name
= centry_string(centry
, mem_ctx
);
2277 status
= centry
->status
;
2278 centry_free(centry
);
2279 return NT_STATUS_IS_OK(status
);
2282 BOOL
lookup_cached_name(TALLOC_CTX
*mem_ctx
,
2283 const char *domain_name
,
2286 enum lsa_SidType
*type
)
2288 struct winbindd_domain
*domain
;
2289 struct winbind_cache
*cache
;
2290 struct cache_entry
*centry
= NULL
;
2294 domain
= find_lookup_domain_from_name(domain_name
);
2295 if (domain
== NULL
) {
2299 cache
= get_cache(domain
);
2301 if (cache
->tdb
== NULL
) {
2305 fstrcpy(uname
, name
);
2308 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
2309 if (centry
== NULL
) {
2313 if (NT_STATUS_IS_OK(centry
->status
)) {
2314 *type
= (enum lsa_SidType
)centry_uint32(centry
);
2315 centry_sid(centry
, mem_ctx
, sid
);
2318 status
= centry
->status
;
2319 centry_free(centry
);
2321 return NT_STATUS_IS_OK(status
);
2324 void cache_name2sid(struct winbindd_domain
*domain
,
2325 const char *domain_name
, const char *name
,
2326 enum lsa_SidType type
, const DOM_SID
*sid
)
2328 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
2332 /* delete all centries that don't have NT_STATUS_OK set */
2333 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
2334 TDB_DATA dbuf
, void *state
)
2336 struct cache_entry
*centry
;
2338 centry
= wcache_fetch_raw(kbuf
.dptr
);
2343 if (!NT_STATUS_IS_OK(centry
->status
)) {
2344 DEBUG(10,("deleting centry %s\n", kbuf
.dptr
));
2345 tdb_delete(the_tdb
, kbuf
);
2348 centry_free(centry
);
2352 /* flush the cache */
2353 void wcache_flush_cache(void)
2355 extern BOOL opt_nocache
;
2360 tdb_close(wcache
->tdb
);
2366 /* when working offline we must not clear the cache on restart */
2367 wcache
->tdb
= tdb_open_log(lock_path("winbindd_cache.tdb"),
2368 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
2369 lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
2370 O_RDWR
|O_CREAT
, 0600);
2373 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2377 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
2379 DEBUG(10,("wcache_flush_cache success\n"));
2382 /* Count cached creds */
2384 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2387 int *cred_count
= (int*)state
;
2389 if (strncmp(kbuf
.dptr
, "CRED/", 5) == 0) {
2395 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
2397 struct winbind_cache
*cache
= get_cache(domain
);
2402 return NT_STATUS_INTERNAL_DB_ERROR
;
2405 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
2407 return NT_STATUS_OK
;
2411 struct cred_list
*prev
, *next
;
2416 static struct cred_list
*wcache_cred_list
;
2418 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2421 struct cred_list
*cred
;
2423 if (strncmp(kbuf
.dptr
, "CRED/", 5) == 0) {
2425 cred
= SMB_MALLOC_P(struct cred_list
);
2427 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2433 /* save a copy of the key */
2435 fstrcpy(cred
->name
, kbuf
.dptr
);
2436 DLIST_ADD(wcache_cred_list
, cred
);
2442 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const DOM_SID
*sid
)
2444 struct winbind_cache
*cache
= get_cache(domain
);
2447 struct cred_list
*cred
, *oldest
= NULL
;
2450 return NT_STATUS_INTERNAL_DB_ERROR
;
2453 /* we possibly already have an entry */
2454 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
2458 DEBUG(11,("we already have an entry, deleting that\n"));
2460 fstr_sprintf(key_str
, "CRED/%s", sid_string_static(sid
));
2462 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
2464 return NT_STATUS_OK
;
2467 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
2469 return NT_STATUS_OK
;
2470 } else if ((ret
== -1) || (wcache_cred_list
== NULL
)) {
2471 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2474 ZERO_STRUCTP(oldest
);
2476 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
2481 data
= tdb_fetch(cache
->tdb
, make_tdb_data(cred
->name
, strlen(cred
->name
)));
2483 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
2485 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2489 t
= IVAL(data
.dptr
, 0);
2490 SAFE_FREE(data
.dptr
);
2493 oldest
= SMB_MALLOC_P(struct cred_list
);
2494 if (oldest
== NULL
) {
2495 status
= NT_STATUS_NO_MEMORY
;
2499 fstrcpy(oldest
->name
, cred
->name
);
2500 oldest
->created
= t
;
2504 if (t
< oldest
->created
) {
2505 fstrcpy(oldest
->name
, cred
->name
);
2506 oldest
->created
= t
;
2510 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
2511 status
= NT_STATUS_OK
;
2513 status
= NT_STATUS_UNSUCCESSFUL
;
2516 SAFE_FREE(wcache_cred_list
);
2522 /* Change the global online/offline state. */
2523 BOOL
set_global_winbindd_state_offline(void)
2528 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
2530 /* Only go offline if someone has created
2531 the key "WINBINDD_OFFLINE" in the cache tdb. */
2533 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
2534 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
2538 if (!lp_winbind_offline_logon()) {
2539 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
2543 if (global_winbindd_offline_state
) {
2544 /* Already offline. */
2548 /* wcache->tdb->ecode = 0; */
2550 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
2552 /* As this is a key with no data we don't need to free, we
2553 check for existence by looking at tdb_err. */
2555 err
= tdb_error(wcache
->tdb
);
2557 if (err
== TDB_ERR_NOEXIST
) {
2558 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
2561 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
2562 global_winbindd_offline_state
= True
;
2567 void set_global_winbindd_state_online(void)
2569 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
2571 if (!lp_winbind_offline_logon()) {
2572 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
2576 if (!global_winbindd_offline_state
) {
2577 /* Already online. */
2580 global_winbindd_offline_state
= False
;
2586 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
2587 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
2590 BOOL
get_global_winbindd_state_offline(void)
2592 return global_winbindd_offline_state
;
2595 /* the cache backend methods are exposed via this structure */
2596 struct winbindd_methods cache_methods
= {