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 #define WINBINDD_CACHE_VERSION 1
33 #define WINBINDD_CACHE_VERSION_KEYSTR "WINBINDD_CACHE_VERSION"
35 extern struct winbindd_methods reconnect_methods
;
36 extern BOOL opt_nocache
;
38 extern struct winbindd_methods ads_methods
;
42 * JRA. KEEP THIS LIST UP TO DATE IF YOU ADD CACHE ENTRIES.
43 * Here are the list of entry types that are *not* stored
44 * as form struct cache_entry in the cache.
47 static const char *non_centry_keys
[] = {
52 WINBINDD_CACHE_VERSION_KEYSTR
,
56 /************************************************************************
57 Is this key a non-centry type ?
58 ************************************************************************/
60 static BOOL
is_non_centry_key(TDB_DATA kbuf
)
64 if (kbuf
.dptr
== NULL
|| kbuf
.dsize
== 0) {
67 for (i
= 0; non_centry_keys
[i
] != NULL
; i
++) {
68 size_t namelen
= strlen(non_centry_keys
[i
]);
69 if (kbuf
.dsize
< namelen
) {
72 if (strncmp(non_centry_keys
[i
], (const char *)kbuf
.dptr
, namelen
) == 0) {
79 /* Global online/offline state - False when online. winbindd starts up online
80 and sets this to true if the first query fails and there's an entry in
81 the cache tdb telling us to stay offline. */
83 static BOOL global_winbindd_offline_state
;
85 struct winbind_cache
{
91 uint32 sequence_number
;
96 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
98 static struct winbind_cache
*wcache
;
100 void winbindd_check_cache_size(time_t t
)
102 static time_t last_check_time
;
105 if (last_check_time
== (time_t)0)
108 if (t
- last_check_time
< 60 && t
- last_check_time
> 0)
111 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
112 DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
116 if (fstat(tdb_fd(wcache
->tdb
), &st
) == -1) {
117 DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno
) ));
121 if (st
.st_size
> WINBINDD_MAX_CACHE_SIZE
) {
122 DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
123 (unsigned long)st
.st_size
,
124 (unsigned long)WINBINDD_MAX_CACHE_SIZE
));
125 wcache_flush_cache();
129 /* get the winbind_cache structure */
130 static struct winbind_cache
*get_cache(struct winbindd_domain
*domain
)
132 struct winbind_cache
*ret
= wcache
;
134 struct winbindd_domain
*our_domain
= domain
;
137 /* We have to know what type of domain we are dealing with first. */
139 if ( !domain
->initialized
) {
140 init_dc_connection( domain
);
144 OK. listen up becasue I'm only going to say this once.
145 We have the following scenarios to consider
146 (a) trusted AD domains on a Samba DC,
147 (b) trusted AD domains and we are joined to a non-kerberos domain
148 (c) trusted AD domains and we are joined to a kerberos (AD) domain
150 For (a) we can always contact the trusted domain using krb5
151 since we have the domain trust account password
153 For (b) we can only use RPC since we have no way of
154 getting a krb5 ticket in our own domain
156 For (c) we can always use krb5 since we have a kerberos trust
161 if (!domain
->backend
) {
163 /* find our domain first so we can figure out if we
164 are joined to a kerberized domain */
166 if ( !domain
->primary
)
167 our_domain
= find_our_domain();
169 if ( (our_domain
->active_directory
|| IS_DC
) && domain
->active_directory
) {
170 DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain
->name
));
171 domain
->backend
= &ads_methods
;
173 #endif /* HAVE_ADS */
174 DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain
->name
));
175 domain
->backend
= &reconnect_methods
;
178 #endif /* HAVE_ADS */
184 ret
= SMB_XMALLOC_P(struct winbind_cache
);
188 wcache_flush_cache();
194 free a centry structure
196 static void centry_free(struct cache_entry
*centry
)
200 SAFE_FREE(centry
->data
);
205 pull a uint32 from a cache entry
207 static uint32
centry_uint32(struct cache_entry
*centry
)
210 if (centry
->len
- centry
->ofs
< 4) {
211 DEBUG(0,("centry corruption? needed 4 bytes, have %d\n",
212 centry
->len
- centry
->ofs
));
213 smb_panic("centry_uint32");
215 ret
= IVAL(centry
->data
, centry
->ofs
);
221 pull a uint16 from a cache entry
223 static uint16
centry_uint16(struct cache_entry
*centry
)
226 if (centry
->len
- centry
->ofs
< 2) {
227 DEBUG(0,("centry corruption? needed 2 bytes, have %d\n",
228 centry
->len
- centry
->ofs
));
229 smb_panic("centry_uint16");
231 ret
= CVAL(centry
->data
, centry
->ofs
);
237 pull a uint8 from a cache entry
239 static uint8
centry_uint8(struct cache_entry
*centry
)
242 if (centry
->len
- centry
->ofs
< 1) {
243 DEBUG(0,("centry corruption? needed 1 bytes, have %d\n",
244 centry
->len
- centry
->ofs
));
245 smb_panic("centry_uint32");
247 ret
= CVAL(centry
->data
, centry
->ofs
);
253 pull a NTTIME from a cache entry
255 static NTTIME
centry_nttime(struct cache_entry
*centry
)
258 if (centry
->len
- centry
->ofs
< 8) {
259 DEBUG(0,("centry corruption? needed 8 bytes, have %d\n",
260 centry
->len
- centry
->ofs
));
261 smb_panic("centry_nttime");
263 ret
= IVAL(centry
->data
, centry
->ofs
);
265 ret
+= (uint64_t)IVAL(centry
->data
, centry
->ofs
) << 32;
271 pull a time_t from a cache entry. time_t stored portably as a 64-bit time.
273 static time_t centry_time(struct cache_entry
*centry
)
275 return (time_t)centry_nttime(centry
);
278 /* pull a string from a cache entry, using the supplied
281 static char *centry_string(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
286 len
= centry_uint8(centry
);
289 /* a deliberate NULL string */
293 if (centry
->len
- centry
->ofs
< len
) {
294 DEBUG(0,("centry corruption? needed %d bytes, have %d\n",
295 len
, centry
->len
- centry
->ofs
));
296 smb_panic("centry_string");
299 ret
= TALLOC_ARRAY(mem_ctx
, char, len
+1);
301 smb_panic("centry_string out of memory\n");
303 memcpy(ret
,centry
->data
+ centry
->ofs
, len
);
309 /* pull a hash16 from a cache entry, using the supplied
312 static char *centry_hash16(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
)
317 len
= centry_uint8(centry
);
320 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
325 if (centry
->len
- centry
->ofs
< 16) {
326 DEBUG(0,("centry corruption? needed 16 bytes, have %d\n",
327 centry
->len
- centry
->ofs
));
331 ret
= TALLOC_ARRAY(mem_ctx
, char, 16);
333 smb_panic("centry_hash out of memory\n");
335 memcpy(ret
,centry
->data
+ centry
->ofs
, 16);
340 /* pull a sid from a cache entry, using the supplied
343 static BOOL
centry_sid(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
, DOM_SID
*sid
)
346 sid_string
= centry_string(centry
, mem_ctx
);
347 if ((sid_string
== NULL
) || (!string_to_sid(sid
, sid_string
))) {
353 /* the server is considered down if it can't give us a sequence number */
354 static BOOL
wcache_server_down(struct winbindd_domain
*domain
)
361 ret
= (domain
->sequence_number
== DOM_SEQUENCE_NONE
);
364 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
369 static NTSTATUS
fetch_cache_seqnum( struct winbindd_domain
*domain
, time_t now
)
376 DEBUG(10,("fetch_cache_seqnum: tdb == NULL\n"));
377 return NT_STATUS_UNSUCCESSFUL
;
380 fstr_sprintf( key
, "SEQNUM/%s", domain
->name
);
382 data
= tdb_fetch_bystring( wcache
->tdb
, key
);
383 if ( !data
.dptr
|| data
.dsize
!=8 ) {
384 DEBUG(10,("fetch_cache_seqnum: invalid data size key [%s]\n", key
));
385 return NT_STATUS_UNSUCCESSFUL
;
388 domain
->sequence_number
= IVAL(data
.dptr
, 0);
389 domain
->last_seq_check
= IVAL(data
.dptr
, 4);
391 SAFE_FREE(data
.dptr
);
393 /* have we expired? */
395 time_diff
= now
- domain
->last_seq_check
;
396 if ( time_diff
> lp_winbind_cache_time() ) {
397 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
398 domain
->name
, domain
->sequence_number
,
399 (uint32
)domain
->last_seq_check
));
400 return NT_STATUS_UNSUCCESSFUL
;
403 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
404 domain
->name
, domain
->sequence_number
,
405 (uint32
)domain
->last_seq_check
));
410 static NTSTATUS
store_cache_seqnum( struct winbindd_domain
*domain
)
417 DEBUG(10,("store_cache_seqnum: tdb == NULL\n"));
418 return NT_STATUS_UNSUCCESSFUL
;
421 fstr_sprintf( key_str
, "SEQNUM/%s", domain
->name
);
423 SIVAL(buf
, 0, domain
->sequence_number
);
424 SIVAL(buf
, 4, domain
->last_seq_check
);
428 if ( tdb_store_bystring( wcache
->tdb
, key_str
, data
, TDB_REPLACE
) == -1 ) {
429 DEBUG(10,("store_cache_seqnum: tdb_store fail key [%s]\n", key_str
));
430 return NT_STATUS_UNSUCCESSFUL
;
433 DEBUG(10,("store_cache_seqnum: success [%s][%u @ %u]\n",
434 domain
->name
, domain
->sequence_number
,
435 (uint32
)domain
->last_seq_check
));
441 refresh the domain sequence number. If force is True
442 then always refresh it, no matter how recently we fetched it
445 static void refresh_sequence_number(struct winbindd_domain
*domain
, BOOL force
)
449 time_t t
= time(NULL
);
450 unsigned cache_time
= lp_winbind_cache_time();
454 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
455 /* trying to reconnect is expensive, don't do it too often */
456 if (domain
->sequence_number
== DOM_SEQUENCE_NONE
) {
461 time_diff
= t
- domain
->last_seq_check
;
463 /* see if we have to refetch the domain sequence number */
464 if (!force
&& (time_diff
< cache_time
)) {
465 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain
->name
));
469 /* try to get the sequence number from the tdb cache first */
470 /* this will update the timestamp as well */
472 status
= fetch_cache_seqnum( domain
, t
);
473 if ( NT_STATUS_IS_OK(status
) )
476 /* important! make sure that we know if this is a native
477 mode domain or not */
479 status
= domain
->backend
->sequence_number(domain
, &domain
->sequence_number
);
481 /* the above call could have set our domain->backend to NULL when
482 * coming from offline to online mode, make sure to reinitialize the
483 * backend - Guenther */
486 if (!NT_STATUS_IS_OK(status
)) {
487 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status
)));
488 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
491 domain
->last_status
= status
;
492 domain
->last_seq_check
= time(NULL
);
494 /* save the new sequence number ni the cache */
495 store_cache_seqnum( domain
);
498 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
499 domain
->name
, domain
->sequence_number
));
505 decide if a cache entry has expired
507 static BOOL
centry_expired(struct winbindd_domain
*domain
, const char *keystr
, struct cache_entry
*centry
)
509 /* If we've been told to be offline - stay in that state... */
510 if (lp_winbind_offline_logon() && global_winbindd_offline_state
) {
511 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
512 keystr
, domain
->name
));
516 /* when the domain is offline return the cached entry.
517 * This deals with transient offline states... */
519 if (!domain
->online
) {
520 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
521 keystr
, domain
->name
));
525 /* if the server is OK and our cache entry came from when it was down then
526 the entry is invalid */
527 if ((domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
528 (centry
->sequence_number
== DOM_SEQUENCE_NONE
)) {
529 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
530 keystr
, domain
->name
));
534 /* if the server is down or the cache entry is not older than the
535 current sequence number then it is OK */
536 if (wcache_server_down(domain
) ||
537 centry
->sequence_number
== domain
->sequence_number
) {
538 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
539 keystr
, domain
->name
));
543 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
544 keystr
, domain
->name
));
550 static struct cache_entry
*wcache_fetch_raw(char *kstr
)
553 struct cache_entry
*centry
;
557 key
.dsize
= strlen(kstr
);
558 data
= tdb_fetch(wcache
->tdb
, key
);
564 centry
= SMB_XMALLOC_P(struct cache_entry
);
565 centry
->data
= (unsigned char *)data
.dptr
;
566 centry
->len
= data
.dsize
;
569 if (centry
->len
< 8) {
570 /* huh? corrupt cache? */
571 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr
));
576 centry
->status
= NT_STATUS(centry_uint32(centry
));
577 centry
->sequence_number
= centry_uint32(centry
);
583 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
584 number and return status
586 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
587 struct winbindd_domain
*domain
,
588 const char *format
, ...) PRINTF_ATTRIBUTE(3,4);
589 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
590 struct winbindd_domain
*domain
,
591 const char *format
, ...)
595 struct cache_entry
*centry
;
601 refresh_sequence_number(domain
, False
);
603 va_start(ap
, format
);
604 smb_xvasprintf(&kstr
, format
, ap
);
607 centry
= wcache_fetch_raw(kstr
);
608 if (centry
== NULL
) {
613 if (centry_expired(domain
, kstr
, centry
)) {
615 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
616 kstr
, domain
->name
));
623 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
624 kstr
, domain
->name
));
630 static void wcache_delete(const char *format
, ...) PRINTF_ATTRIBUTE(1,2);
631 static void wcache_delete(const char *format
, ...)
637 va_start(ap
, format
);
638 smb_xvasprintf(&kstr
, format
, ap
);
642 key
.dsize
= strlen(kstr
);
644 tdb_delete(wcache
->tdb
, key
);
649 make sure we have at least len bytes available in a centry
651 static void centry_expand(struct cache_entry
*centry
, uint32 len
)
653 if (centry
->len
- centry
->ofs
>= len
)
656 centry
->data
= SMB_REALLOC_ARRAY(centry
->data
, unsigned char,
659 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry
->len
));
660 smb_panic("out of memory in centry_expand");
665 push a uint32 into a centry
667 static void centry_put_uint32(struct cache_entry
*centry
, uint32 v
)
669 centry_expand(centry
, 4);
670 SIVAL(centry
->data
, centry
->ofs
, v
);
675 push a uint16 into a centry
677 static void centry_put_uint16(struct cache_entry
*centry
, uint16 v
)
679 centry_expand(centry
, 2);
680 SIVAL(centry
->data
, centry
->ofs
, v
);
685 push a uint8 into a centry
687 static void centry_put_uint8(struct cache_entry
*centry
, uint8 v
)
689 centry_expand(centry
, 1);
690 SCVAL(centry
->data
, centry
->ofs
, v
);
695 push a string into a centry
697 static void centry_put_string(struct cache_entry
*centry
, const char *s
)
702 /* null strings are marked as len 0xFFFF */
703 centry_put_uint8(centry
, 0xFF);
708 /* can't handle more than 254 char strings. Truncating is probably best */
710 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len
));
713 centry_put_uint8(centry
, len
);
714 centry_expand(centry
, len
);
715 memcpy(centry
->data
+ centry
->ofs
, s
, len
);
720 push a 16 byte hash into a centry - treat as 16 byte string.
722 static void centry_put_hash16(struct cache_entry
*centry
, const uint8 val
[16])
724 centry_put_uint8(centry
, 16);
725 centry_expand(centry
, 16);
726 memcpy(centry
->data
+ centry
->ofs
, val
, 16);
730 static void centry_put_sid(struct cache_entry
*centry
, const DOM_SID
*sid
)
733 centry_put_string(centry
, sid_to_string(sid_string
, sid
));
737 push a NTTIME into a centry
739 static void centry_put_nttime(struct cache_entry
*centry
, NTTIME nt
)
741 centry_expand(centry
, 8);
742 SIVAL(centry
->data
, centry
->ofs
, nt
& 0xFFFFFFFF);
744 SIVAL(centry
->data
, centry
->ofs
, nt
>> 32);
749 push a time_t into a centry - use a 64 bit size.
750 NTTIME here is being used as a convenient 64-bit size.
752 static void centry_put_time(struct cache_entry
*centry
, time_t t
)
754 NTTIME nt
= (NTTIME
)t
;
755 centry_put_nttime(centry
, nt
);
759 start a centry for output. When finished, call centry_end()
761 struct cache_entry
*centry_start(struct winbindd_domain
*domain
, NTSTATUS status
)
763 struct cache_entry
*centry
;
768 centry
= SMB_XMALLOC_P(struct cache_entry
);
770 centry
->len
= 8192; /* reasonable default */
771 centry
->data
= SMB_XMALLOC_ARRAY(uint8
, centry
->len
);
773 centry
->sequence_number
= domain
->sequence_number
;
774 centry_put_uint32(centry
, NT_STATUS_V(status
));
775 centry_put_uint32(centry
, centry
->sequence_number
);
780 finish a centry and write it to the tdb
782 static void centry_end(struct cache_entry
*centry
, const char *format
, ...) PRINTF_ATTRIBUTE(2,3);
783 static void centry_end(struct cache_entry
*centry
, const char *format
, ...)
789 va_start(ap
, format
);
790 smb_xvasprintf(&kstr
, format
, ap
);
794 key
.dsize
= strlen(kstr
);
795 data
.dptr
= (char *)centry
->data
;
796 data
.dsize
= centry
->ofs
;
798 tdb_store(wcache
->tdb
, key
, data
, TDB_REPLACE
);
802 static void wcache_save_name_to_sid(struct winbindd_domain
*domain
,
803 NTSTATUS status
, const char *domain_name
,
804 const char *name
, const DOM_SID
*sid
,
805 enum lsa_SidType type
)
807 struct cache_entry
*centry
;
810 centry
= centry_start(domain
, status
);
813 centry_put_uint32(centry
, type
);
814 centry_put_sid(centry
, sid
);
815 fstrcpy(uname
, name
);
817 centry_end(centry
, "NS/%s/%s", domain_name
, uname
);
818 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s\n", domain_name
, uname
,
819 sid_string_static(sid
)));
823 static void wcache_save_sid_to_name(struct winbindd_domain
*domain
, NTSTATUS status
,
824 const DOM_SID
*sid
, const char *domain_name
, const char *name
, enum lsa_SidType type
)
826 struct cache_entry
*centry
;
829 if (is_null_sid(sid
)) {
833 centry
= centry_start(domain
, status
);
836 if (NT_STATUS_IS_OK(status
)) {
837 centry_put_uint32(centry
, type
);
838 centry_put_string(centry
, domain_name
);
839 centry_put_string(centry
, name
);
841 centry_end(centry
, "SN/%s", sid_to_string(sid_string
, sid
));
842 DEBUG(10,("wcache_save_sid_to_name: %s -> %s\n", sid_string
, name
));
847 static void wcache_save_user(struct winbindd_domain
*domain
, NTSTATUS status
, WINBIND_USERINFO
*info
)
849 struct cache_entry
*centry
;
852 if (is_null_sid(&info
->user_sid
)) {
856 centry
= centry_start(domain
, status
);
859 centry_put_string(centry
, info
->acct_name
);
860 centry_put_string(centry
, info
->full_name
);
861 centry_put_string(centry
, info
->homedir
);
862 centry_put_string(centry
, info
->shell
);
863 centry_put_uint32(centry
, info
->primary_gid
);
864 centry_put_sid(centry
, &info
->user_sid
);
865 centry_put_sid(centry
, &info
->group_sid
);
866 centry_end(centry
, "U/%s", sid_to_string(sid_string
, &info
->user_sid
));
867 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string
, info
->acct_name
));
871 static void wcache_save_lockout_policy(struct winbindd_domain
*domain
, NTSTATUS status
, SAM_UNK_INFO_12
*lockout_policy
)
873 struct cache_entry
*centry
;
875 centry
= centry_start(domain
, status
);
879 centry_put_nttime(centry
, lockout_policy
->duration
);
880 centry_put_nttime(centry
, lockout_policy
->reset_count
);
881 centry_put_uint16(centry
, lockout_policy
->bad_attempt_lockout
);
883 centry_end(centry
, "LOC_POL/%s", domain
->name
);
885 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain
->name
));
890 static void wcache_save_password_policy(struct winbindd_domain
*domain
, NTSTATUS status
, SAM_UNK_INFO_1
*policy
)
892 struct cache_entry
*centry
;
894 centry
= centry_start(domain
, status
);
898 centry_put_uint16(centry
, policy
->min_length_password
);
899 centry_put_uint16(centry
, policy
->password_history
);
900 centry_put_uint32(centry
, policy
->password_properties
);
901 centry_put_nttime(centry
, policy
->expire
);
902 centry_put_nttime(centry
, policy
->min_passwordage
);
904 centry_end(centry
, "PWD_POL/%s", domain
->name
);
906 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
911 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const DOM_SID
*sid
)
913 struct winbind_cache
*cache
= get_cache(domain
);
919 return NT_STATUS_INTERNAL_DB_ERROR
;
922 if (is_null_sid(sid
)) {
923 return NT_STATUS_INVALID_SID
;
926 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
927 return NT_STATUS_INVALID_SID
;
930 fstr_sprintf(key_str
, "CRED/%s", sid_string_static(sid
));
932 data
= tdb_fetch(cache
->tdb
, make_tdb_data(key_str
, strlen(key_str
)));
934 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
937 SAFE_FREE(data
.dptr
);
941 /* Lookup creds for a SID - copes with old (unsalted) creds as well
942 as new salted ones. */
944 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
947 const uint8
**cached_nt_pass
,
948 const uint8
**cached_salt
)
950 struct winbind_cache
*cache
= get_cache(domain
);
951 struct cache_entry
*centry
= NULL
;
957 return NT_STATUS_INTERNAL_DB_ERROR
;
960 if (is_null_sid(sid
)) {
961 return NT_STATUS_INVALID_SID
;
964 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
965 return NT_STATUS_INVALID_SID
;
968 /* Try and get a salted cred first. If we can't
969 fall back to an unsalted cred. */
971 centry
= wcache_fetch(cache
, domain
, "CRED/%s", sid_string_static(sid
));
973 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
974 sid_string_static(sid
)));
975 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
978 t
= centry_time(centry
);
980 /* In the salted case this isn't actually the nt_hash itself,
981 but the MD5 of the salt + nt_hash. Let the caller
982 sort this out. It can tell as we only return the cached_salt
983 if we are returning a salted cred. */
985 *cached_nt_pass
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
986 if (*cached_nt_pass
== NULL
) {
987 const char *sidstr
= sid_string_static(sid
);
989 /* Bad (old) cred cache. Delete and pretend we
991 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
993 wcache_delete("CRED/%s", sidstr
);
995 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
998 /* We only have 17 bytes more data in the salted cred case. */
999 if (centry
->len
- centry
->ofs
== 17) {
1000 *cached_salt
= (const uint8
*)centry_hash16(centry
, mem_ctx
);
1002 *cached_salt
= NULL
;
1006 dump_data(100, (const char *)*cached_nt_pass
, NT_HASH_LEN
);
1008 dump_data(100, (const char *)*cached_salt
, NT_HASH_LEN
);
1011 status
= centry
->status
;
1013 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
1014 sid_string_static(sid
), nt_errstr(status
) ));
1016 centry_free(centry
);
1020 /* Store creds for a SID - only writes out new salted ones. */
1022 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
1023 TALLOC_CTX
*mem_ctx
,
1025 const uint8 nt_pass
[NT_HASH_LEN
])
1027 struct cache_entry
*centry
;
1030 uint8 cred_salt
[NT_HASH_LEN
];
1031 uint8 salted_hash
[NT_HASH_LEN
];
1033 if (is_null_sid(sid
)) {
1034 return NT_STATUS_INVALID_SID
;
1037 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
1038 return NT_STATUS_INVALID_SID
;
1041 centry
= centry_start(domain
, NT_STATUS_OK
);
1043 return NT_STATUS_INTERNAL_DB_ERROR
;
1047 dump_data(100, (const char *)nt_pass
, NT_HASH_LEN
);
1050 centry_put_time(centry
, time(NULL
));
1052 /* Create a salt and then salt the hash. */
1053 generate_random_buffer(cred_salt
, NT_HASH_LEN
);
1054 E_md5hash(cred_salt
, nt_pass
, salted_hash
);
1056 centry_put_hash16(centry
, salted_hash
);
1057 centry_put_hash16(centry
, cred_salt
);
1058 centry_end(centry
, "CRED/%s", sid_to_string(sid_string
, sid
));
1060 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
1062 centry_free(centry
);
1064 return NT_STATUS_OK
;
1068 /* Query display info. This is the basic user list fn */
1069 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
1070 TALLOC_CTX
*mem_ctx
,
1071 uint32
*num_entries
,
1072 WINBIND_USERINFO
**info
)
1074 struct winbind_cache
*cache
= get_cache(domain
);
1075 struct cache_entry
*centry
= NULL
;
1077 unsigned int i
, retry
;
1082 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
1086 *num_entries
= centry_uint32(centry
);
1088 if (*num_entries
== 0)
1091 (*info
) = TALLOC_ARRAY(mem_ctx
, WINBIND_USERINFO
, *num_entries
);
1093 smb_panic("query_user_list out of memory");
1094 for (i
=0; i
<(*num_entries
); i
++) {
1095 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
1096 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
1097 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
1098 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
1099 centry_sid(centry
, mem_ctx
, &(*info
)[i
].user_sid
);
1100 centry_sid(centry
, mem_ctx
, &(*info
)[i
].group_sid
);
1104 status
= centry
->status
;
1106 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1107 domain
->name
, nt_errstr(status
) ));
1109 centry_free(centry
);
1116 /* Return status value returned by seq number check */
1118 if (!NT_STATUS_IS_OK(domain
->last_status
))
1119 return domain
->last_status
;
1121 /* Put the query_user_list() in a retry loop. There appears to be
1122 * some bug either with Windows 2000 or Samba's handling of large
1123 * rpc replies. This manifests itself as sudden disconnection
1124 * at a random point in the enumeration of a large (60k) user list.
1125 * The retry loop simply tries the operation again. )-: It's not
1126 * pretty but an acceptable workaround until we work out what the
1127 * real problem is. */
1132 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1135 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
1136 if (!NT_STATUS_IS_OK(status
)) {
1137 DEBUG(3, ("query_user_list: returned 0x%08x, "
1138 "retrying\n", NT_STATUS_V(status
)));
1140 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
1141 DEBUG(3, ("query_user_list: flushing "
1142 "connection cache\n"));
1143 invalidate_cm_connection(&domain
->conn
);
1146 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
1150 refresh_sequence_number(domain
, False
);
1151 centry
= centry_start(domain
, status
);
1154 centry_put_uint32(centry
, *num_entries
);
1155 for (i
=0; i
<(*num_entries
); i
++) {
1156 centry_put_string(centry
, (*info
)[i
].acct_name
);
1157 centry_put_string(centry
, (*info
)[i
].full_name
);
1158 centry_put_string(centry
, (*info
)[i
].homedir
);
1159 centry_put_string(centry
, (*info
)[i
].shell
);
1160 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1161 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1162 if (domain
->backend
&& domain
->backend
->consistent
) {
1163 /* when the backend is consistent we can pre-prime some mappings */
1164 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1166 (*info
)[i
].acct_name
,
1167 &(*info
)[i
].user_sid
,
1169 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1170 &(*info
)[i
].user_sid
,
1172 (*info
)[i
].acct_name
,
1174 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1177 centry_end(centry
, "UL/%s", domain
->name
);
1178 centry_free(centry
);
1184 /* list all domain groups */
1185 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
1186 TALLOC_CTX
*mem_ctx
,
1187 uint32
*num_entries
,
1188 struct acct_info
**info
)
1190 struct winbind_cache
*cache
= get_cache(domain
);
1191 struct cache_entry
*centry
= NULL
;
1198 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1202 *num_entries
= centry_uint32(centry
);
1204 if (*num_entries
== 0)
1207 (*info
) = TALLOC_ARRAY(mem_ctx
, struct acct_info
, *num_entries
);
1209 smb_panic("enum_dom_groups out of memory");
1210 for (i
=0; i
<(*num_entries
); i
++) {
1211 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1212 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1213 (*info
)[i
].rid
= centry_uint32(centry
);
1217 status
= centry
->status
;
1219 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1220 domain
->name
, nt_errstr(status
) ));
1222 centry_free(centry
);
1229 /* Return status value returned by seq number check */
1231 if (!NT_STATUS_IS_OK(domain
->last_status
))
1232 return domain
->last_status
;
1234 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1237 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1240 refresh_sequence_number(domain
, False
);
1241 centry
= centry_start(domain
, status
);
1244 centry_put_uint32(centry
, *num_entries
);
1245 for (i
=0; i
<(*num_entries
); i
++) {
1246 centry_put_string(centry
, (*info
)[i
].acct_name
);
1247 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1248 centry_put_uint32(centry
, (*info
)[i
].rid
);
1250 centry_end(centry
, "GL/%s/domain", domain
->name
);
1251 centry_free(centry
);
1257 /* list all domain groups */
1258 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
1259 TALLOC_CTX
*mem_ctx
,
1260 uint32
*num_entries
,
1261 struct acct_info
**info
)
1263 struct winbind_cache
*cache
= get_cache(domain
);
1264 struct cache_entry
*centry
= NULL
;
1271 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1275 *num_entries
= centry_uint32(centry
);
1277 if (*num_entries
== 0)
1280 (*info
) = TALLOC_ARRAY(mem_ctx
, struct acct_info
, *num_entries
);
1282 smb_panic("enum_dom_groups out of memory");
1283 for (i
=0; i
<(*num_entries
); i
++) {
1284 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1285 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1286 (*info
)[i
].rid
= centry_uint32(centry
);
1291 /* If we are returning cached data and the domain controller
1292 is down then we don't know whether the data is up to date
1293 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1296 if (wcache_server_down(domain
)) {
1297 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1298 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1300 status
= centry
->status
;
1302 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1303 domain
->name
, nt_errstr(status
) ));
1305 centry_free(centry
);
1312 /* Return status value returned by seq number check */
1314 if (!NT_STATUS_IS_OK(domain
->last_status
))
1315 return domain
->last_status
;
1317 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1320 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1323 refresh_sequence_number(domain
, False
);
1324 centry
= centry_start(domain
, status
);
1327 centry_put_uint32(centry
, *num_entries
);
1328 for (i
=0; i
<(*num_entries
); i
++) {
1329 centry_put_string(centry
, (*info
)[i
].acct_name
);
1330 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1331 centry_put_uint32(centry
, (*info
)[i
].rid
);
1333 centry_end(centry
, "GL/%s/local", domain
->name
);
1334 centry_free(centry
);
1340 /* convert a single name to a sid in a domain */
1341 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
1342 TALLOC_CTX
*mem_ctx
,
1343 const char *domain_name
,
1346 enum lsa_SidType
*type
)
1348 struct winbind_cache
*cache
= get_cache(domain
);
1349 struct cache_entry
*centry
= NULL
;
1356 fstrcpy(uname
, name
);
1358 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1361 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1362 status
= centry
->status
;
1363 if (NT_STATUS_IS_OK(status
)) {
1364 centry_sid(centry
, mem_ctx
, sid
);
1367 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: %s\n",
1368 domain
->name
, nt_errstr(status
) ));
1370 centry_free(centry
);
1376 /* If the seq number check indicated that there is a problem
1377 * with this DC, then return that status... except for
1378 * access_denied. This is special because the dc may be in
1379 * "restrict anonymous = 1" mode, in which case it will deny
1380 * most unauthenticated operations, but *will* allow the LSA
1381 * name-to-sid that we try as a fallback. */
1383 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1384 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1385 return domain
->last_status
;
1387 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1390 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
, name
, sid
, type
);
1393 refresh_sequence_number(domain
, False
);
1395 if (domain
->online
&& !is_null_sid(sid
)) {
1396 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1399 if (NT_STATUS_IS_OK(status
)) {
1400 strupper_m(CONST_DISCARD(char *,domain_name
));
1401 strlower_m(CONST_DISCARD(char *,name
));
1402 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1408 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1410 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1411 TALLOC_CTX
*mem_ctx
,
1415 enum lsa_SidType
*type
)
1417 struct winbind_cache
*cache
= get_cache(domain
);
1418 struct cache_entry
*centry
= NULL
;
1425 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_to_string(sid_string
, sid
));
1428 if (NT_STATUS_IS_OK(centry
->status
)) {
1429 *type
= (enum lsa_SidType
)centry_uint32(centry
);
1430 *domain_name
= centry_string(centry
, mem_ctx
);
1431 *name
= centry_string(centry
, mem_ctx
);
1433 status
= centry
->status
;
1435 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: %s\n",
1436 domain
->name
, nt_errstr(status
) ));
1438 centry_free(centry
);
1443 *domain_name
= NULL
;
1445 /* If the seq number check indicated that there is a problem
1446 * with this DC, then return that status... except for
1447 * access_denied. This is special because the dc may be in
1448 * "restrict anonymous = 1" mode, in which case it will deny
1449 * most unauthenticated operations, but *will* allow the LSA
1450 * sid-to-name that we try as a fallback. */
1452 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1453 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1454 return domain
->last_status
;
1456 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1459 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1462 refresh_sequence_number(domain
, False
);
1463 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
1465 /* We can't save the name to sid mapping here, as with sid history a
1466 * later name2sid would give the wrong sid. */
1471 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
1472 TALLOC_CTX
*mem_ctx
,
1473 const DOM_SID
*domain_sid
,
1478 enum lsa_SidType
**types
)
1480 struct winbind_cache
*cache
= get_cache(domain
);
1482 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1486 *domain_name
= NULL
;
1494 if (num_rids
== 0) {
1495 return NT_STATUS_OK
;
1498 *names
= TALLOC_ARRAY(mem_ctx
, char *, num_rids
);
1499 *types
= TALLOC_ARRAY(mem_ctx
, enum lsa_SidType
, num_rids
);
1501 if ((*names
== NULL
) || (*types
== NULL
)) {
1502 result
= NT_STATUS_NO_MEMORY
;
1506 have_mapped
= have_unmapped
= False
;
1508 for (i
=0; i
<num_rids
; i
++) {
1510 struct cache_entry
*centry
;
1512 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
1513 result
= NT_STATUS_INTERNAL_ERROR
;
1517 centry
= wcache_fetch(cache
, domain
, "SN/%s",
1518 sid_string_static(&sid
));
1523 (*types
)[i
] = SID_NAME_UNKNOWN
;
1524 (*names
)[i
] = talloc_strdup(*names
, "");
1526 if (NT_STATUS_IS_OK(centry
->status
)) {
1529 (*types
)[i
] = (enum lsa_SidType
)centry_uint32(centry
);
1530 dom
= centry_string(centry
, mem_ctx
);
1531 if (*domain_name
== NULL
) {
1536 (*names
)[i
] = centry_string(centry
, *names
);
1538 have_unmapped
= True
;
1541 centry_free(centry
);
1545 return NT_STATUS_NONE_MAPPED
;
1547 if (!have_unmapped
) {
1548 return NT_STATUS_OK
;
1550 return STATUS_SOME_UNMAPPED
;
1554 TALLOC_FREE(*names
);
1555 TALLOC_FREE(*types
);
1557 result
= domain
->backend
->rids_to_names(domain
, mem_ctx
, domain_sid
,
1558 rids
, num_rids
, domain_name
,
1561 if (!NT_STATUS_IS_OK(result
) &&
1562 !NT_STATUS_EQUAL(result
, STATUS_SOME_UNMAPPED
)) {
1566 refresh_sequence_number(domain
, False
);
1568 for (i
=0; i
<num_rids
; i
++) {
1572 if (!sid_compose(&sid
, domain_sid
, rids
[i
])) {
1573 result
= NT_STATUS_INTERNAL_ERROR
;
1577 status
= (*types
)[i
] == SID_NAME_UNKNOWN
?
1578 NT_STATUS_NONE_MAPPED
: NT_STATUS_OK
;
1580 wcache_save_sid_to_name(domain
, status
, &sid
, *domain_name
,
1581 (*names
)[i
], (*types
)[i
]);
1588 TALLOC_FREE(*names
);
1589 TALLOC_FREE(*types
);
1593 /* Lookup user information from a rid */
1594 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
1595 TALLOC_CTX
*mem_ctx
,
1596 const DOM_SID
*user_sid
,
1597 WINBIND_USERINFO
*info
)
1599 struct winbind_cache
*cache
= get_cache(domain
);
1600 struct cache_entry
*centry
= NULL
;
1606 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string_static(user_sid
));
1608 /* If we have an access denied cache entry and a cached info3 in the
1609 samlogon cache then do a query. This will force the rpc back end
1610 to return the info3 data. */
1612 if (NT_STATUS_V(domain
->last_status
) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED
) &&
1613 netsamlogon_cache_have(user_sid
)) {
1614 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1615 domain
->last_status
= NT_STATUS_OK
;
1616 centry_free(centry
);
1623 info
->acct_name
= centry_string(centry
, mem_ctx
);
1624 info
->full_name
= centry_string(centry
, mem_ctx
);
1625 info
->homedir
= centry_string(centry
, mem_ctx
);
1626 info
->shell
= centry_string(centry
, mem_ctx
);
1627 info
->primary_gid
= centry_uint32(centry
);
1628 centry_sid(centry
, mem_ctx
, &info
->user_sid
);
1629 centry_sid(centry
, mem_ctx
, &info
->group_sid
);
1630 status
= centry
->status
;
1632 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: %s\n",
1633 domain
->name
, nt_errstr(status
) ));
1635 centry_free(centry
);
1641 /* Return status value returned by seq number check */
1643 if (!NT_STATUS_IS_OK(domain
->last_status
))
1644 return domain
->last_status
;
1646 DEBUG(10,("query_user: [Cached] - doing backend query for info for domain %s\n",
1649 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
1652 refresh_sequence_number(domain
, False
);
1653 wcache_save_user(domain
, status
, info
);
1659 /* Lookup groups a user is a member of. */
1660 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
1661 TALLOC_CTX
*mem_ctx
,
1662 const DOM_SID
*user_sid
,
1663 uint32
*num_groups
, DOM_SID
**user_gids
)
1665 struct winbind_cache
*cache
= get_cache(domain
);
1666 struct cache_entry
*centry
= NULL
;
1674 centry
= wcache_fetch(cache
, domain
, "UG/%s", sid_to_string(sid_string
, user_sid
));
1676 /* If we have an access denied cache entry and a cached info3 in the
1677 samlogon cache then do a query. This will force the rpc back end
1678 to return the info3 data. */
1680 if (NT_STATUS_V(domain
->last_status
) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED
) &&
1681 netsamlogon_cache_have(user_sid
)) {
1682 DEBUG(10, ("lookup_usergroups: cached access denied and have cached info3\n"));
1683 domain
->last_status
= NT_STATUS_OK
;
1684 centry_free(centry
);
1691 *num_groups
= centry_uint32(centry
);
1693 if (*num_groups
== 0)
1696 (*user_gids
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_groups
);
1698 smb_panic("lookup_usergroups out of memory");
1699 for (i
=0; i
<(*num_groups
); i
++) {
1700 centry_sid(centry
, mem_ctx
, &(*user_gids
)[i
]);
1704 status
= centry
->status
;
1706 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status: %s\n",
1707 domain
->name
, nt_errstr(status
) ));
1709 centry_free(centry
);
1714 (*user_gids
) = NULL
;
1716 /* Return status value returned by seq number check */
1718 if (!NT_STATUS_IS_OK(domain
->last_status
))
1719 return domain
->last_status
;
1721 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
1724 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
1727 refresh_sequence_number(domain
, False
);
1728 centry
= centry_start(domain
, status
);
1731 centry_put_uint32(centry
, *num_groups
);
1732 for (i
=0; i
<(*num_groups
); i
++) {
1733 centry_put_sid(centry
, &(*user_gids
)[i
]);
1735 centry_end(centry
, "UG/%s", sid_to_string(sid_string
, user_sid
));
1736 centry_free(centry
);
1742 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
1743 TALLOC_CTX
*mem_ctx
,
1744 uint32 num_sids
, const DOM_SID
*sids
,
1745 uint32
*num_aliases
, uint32
**alias_rids
)
1747 struct winbind_cache
*cache
= get_cache(domain
);
1748 struct cache_entry
*centry
= NULL
;
1750 char *sidlist
= talloc_strdup(mem_ctx
, "");
1756 if (num_sids
== 0) {
1759 return NT_STATUS_OK
;
1762 /* We need to cache indexed by the whole list of SIDs, the aliases
1763 * resulting might come from any of the SIDs. */
1765 for (i
=0; i
<num_sids
; i
++) {
1766 sidlist
= talloc_asprintf(mem_ctx
, "%s/%s", sidlist
,
1767 sid_string_static(&sids
[i
]));
1768 if (sidlist
== NULL
)
1769 return NT_STATUS_NO_MEMORY
;
1772 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
1777 *num_aliases
= centry_uint32(centry
);
1781 (*alias_rids
) = TALLOC_ARRAY(mem_ctx
, uint32
, *num_aliases
);
1783 if ((*alias_rids
) == NULL
) {
1784 centry_free(centry
);
1785 return NT_STATUS_NO_MEMORY
;
1788 (*alias_rids
) = NULL
;
1791 for (i
=0; i
<(*num_aliases
); i
++)
1792 (*alias_rids
)[i
] = centry_uint32(centry
);
1794 status
= centry
->status
;
1796 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
1797 "status %s\n", domain
->name
, nt_errstr(status
)));
1799 centry_free(centry
);
1804 (*alias_rids
) = NULL
;
1806 if (!NT_STATUS_IS_OK(domain
->last_status
))
1807 return domain
->last_status
;
1809 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
1810 "for domain %s\n", domain
->name
));
1812 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
1814 num_aliases
, alias_rids
);
1817 refresh_sequence_number(domain
, False
);
1818 centry
= centry_start(domain
, status
);
1821 centry_put_uint32(centry
, *num_aliases
);
1822 for (i
=0; i
<(*num_aliases
); i
++)
1823 centry_put_uint32(centry
, (*alias_rids
)[i
]);
1824 centry_end(centry
, "UA%s", sidlist
);
1825 centry_free(centry
);
1832 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
1833 TALLOC_CTX
*mem_ctx
,
1834 const DOM_SID
*group_sid
, uint32
*num_names
,
1835 DOM_SID
**sid_mem
, char ***names
,
1836 uint32
**name_types
)
1838 struct winbind_cache
*cache
= get_cache(domain
);
1839 struct cache_entry
*centry
= NULL
;
1847 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_to_string(sid_string
, group_sid
));
1851 *num_names
= centry_uint32(centry
);
1853 if (*num_names
== 0)
1856 (*sid_mem
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_names
);
1857 (*names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_names
);
1858 (*name_types
) = TALLOC_ARRAY(mem_ctx
, uint32
, *num_names
);
1860 if (! (*sid_mem
) || ! (*names
) || ! (*name_types
)) {
1861 smb_panic("lookup_groupmem out of memory");
1864 for (i
=0; i
<(*num_names
); i
++) {
1865 centry_sid(centry
, mem_ctx
, &(*sid_mem
)[i
]);
1866 (*names
)[i
] = centry_string(centry
, mem_ctx
);
1867 (*name_types
)[i
] = centry_uint32(centry
);
1871 status
= centry
->status
;
1873 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status: %s\n",
1874 domain
->name
, nt_errstr(status
)));
1876 centry_free(centry
);
1883 (*name_types
) = NULL
;
1885 /* Return status value returned by seq number check */
1887 if (!NT_STATUS_IS_OK(domain
->last_status
))
1888 return domain
->last_status
;
1890 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
1893 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
1894 sid_mem
, names
, name_types
);
1897 refresh_sequence_number(domain
, False
);
1898 centry
= centry_start(domain
, status
);
1901 centry_put_uint32(centry
, *num_names
);
1902 for (i
=0; i
<(*num_names
); i
++) {
1903 centry_put_sid(centry
, &(*sid_mem
)[i
]);
1904 centry_put_string(centry
, (*names
)[i
]);
1905 centry_put_uint32(centry
, (*name_types
)[i
]);
1907 centry_end(centry
, "GM/%s", sid_to_string(sid_string
, group_sid
));
1908 centry_free(centry
);
1914 /* find the sequence number for a domain */
1915 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
1917 refresh_sequence_number(domain
, False
);
1919 *seq
= domain
->sequence_number
;
1921 return NT_STATUS_OK
;
1924 /* enumerate trusted domains
1925 * (we need to have the list of trustdoms in the cache when we go offline) -
1927 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
1928 TALLOC_CTX
*mem_ctx
,
1929 uint32
*num_domains
,
1934 struct winbind_cache
*cache
= get_cache(domain
);
1935 struct cache_entry
*centry
= NULL
;
1942 centry
= wcache_fetch(cache
, domain
, "TRUSTDOMS/%s", domain
->name
);
1948 *num_domains
= centry_uint32(centry
);
1951 (*names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
1952 (*alt_names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
1953 (*dom_sids
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_domains
);
1955 if (! (*dom_sids
) || ! (*names
) || ! (*alt_names
)) {
1956 smb_panic("trusted_domains out of memory");
1960 (*alt_names
) = NULL
;
1964 for (i
=0; i
<(*num_domains
); i
++) {
1965 (*names
)[i
] = centry_string(centry
, mem_ctx
);
1966 (*alt_names
)[i
] = centry_string(centry
, mem_ctx
);
1967 centry_sid(centry
, mem_ctx
, &(*dom_sids
)[i
]);
1970 status
= centry
->status
;
1972 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
1973 domain
->name
, *num_domains
, nt_errstr(status
) ));
1975 centry_free(centry
);
1982 (*alt_names
) = NULL
;
1984 /* Return status value returned by seq number check */
1986 if (!NT_STATUS_IS_OK(domain
->last_status
))
1987 return domain
->last_status
;
1989 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
1992 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, num_domains
,
1993 names
, alt_names
, dom_sids
);
1995 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
1996 * so that the generic centry handling still applies correctly -
1999 if (!NT_STATUS_IS_ERR(status
)) {
2000 status
= NT_STATUS_OK
;
2004 refresh_sequence_number(domain
, False
);
2006 centry
= centry_start(domain
, status
);
2010 centry_put_uint32(centry
, *num_domains
);
2012 for (i
=0; i
<(*num_domains
); i
++) {
2013 centry_put_string(centry
, (*names
)[i
]);
2014 centry_put_string(centry
, (*alt_names
)[i
]);
2015 centry_put_sid(centry
, &(*dom_sids
)[i
]);
2018 centry_end(centry
, "TRUSTDOMS/%s", domain
->name
);
2020 centry_free(centry
);
2026 /* get lockout policy */
2027 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
2028 TALLOC_CTX
*mem_ctx
,
2029 SAM_UNK_INFO_12
*policy
){
2030 struct winbind_cache
*cache
= get_cache(domain
);
2031 struct cache_entry
*centry
= NULL
;
2037 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
2042 policy
->duration
= centry_nttime(centry
);
2043 policy
->reset_count
= centry_nttime(centry
);
2044 policy
->bad_attempt_lockout
= centry_uint16(centry
);
2046 status
= centry
->status
;
2048 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2049 domain
->name
, nt_errstr(status
) ));
2051 centry_free(centry
);
2055 ZERO_STRUCTP(policy
);
2057 /* Return status value returned by seq number check */
2059 if (!NT_STATUS_IS_OK(domain
->last_status
))
2060 return domain
->last_status
;
2062 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2065 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
2068 refresh_sequence_number(domain
, False
);
2069 wcache_save_lockout_policy(domain
, status
, policy
);
2074 /* get password policy */
2075 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
2076 TALLOC_CTX
*mem_ctx
,
2077 SAM_UNK_INFO_1
*policy
)
2079 struct winbind_cache
*cache
= get_cache(domain
);
2080 struct cache_entry
*centry
= NULL
;
2086 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
2091 policy
->min_length_password
= centry_uint16(centry
);
2092 policy
->password_history
= centry_uint16(centry
);
2093 policy
->password_properties
= centry_uint32(centry
);
2094 policy
->expire
= centry_nttime(centry
);
2095 policy
->min_passwordage
= centry_nttime(centry
);
2097 status
= centry
->status
;
2099 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2100 domain
->name
, nt_errstr(status
) ));
2102 centry_free(centry
);
2106 ZERO_STRUCTP(policy
);
2108 /* Return status value returned by seq number check */
2110 if (!NT_STATUS_IS_OK(domain
->last_status
))
2111 return domain
->last_status
;
2113 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2116 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
2119 refresh_sequence_number(domain
, False
);
2120 wcache_save_password_policy(domain
, status
, policy
);
2126 /* Invalidate cached user and group lists coherently */
2128 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2131 if (strncmp(kbuf
.dptr
, "UL/", 3) == 0 ||
2132 strncmp(kbuf
.dptr
, "GL/", 3) == 0)
2133 tdb_delete(the_tdb
, kbuf
);
2138 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2140 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
2141 NET_USER_INFO_3
*info3
)
2143 struct winbind_cache
*cache
;
2145 /* dont clear cached U/SID and UG/SID entries when we want to logon
2148 if (lp_winbind_offline_logon()) {
2155 cache
= get_cache(domain
);
2156 netsamlogon_clear_cached_user(cache
->tdb
, info3
);
2159 void wcache_invalidate_cache(void)
2161 struct winbindd_domain
*domain
;
2163 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
2164 struct winbind_cache
*cache
= get_cache(domain
);
2166 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2167 "entries for %s\n", domain
->name
));
2169 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
2173 static BOOL
init_wcache(void)
2175 if (wcache
== NULL
) {
2176 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
2177 ZERO_STRUCTP(wcache
);
2180 if (wcache
->tdb
!= NULL
)
2183 /* when working offline we must not clear the cache on restart */
2184 wcache
->tdb
= tdb_open_log(lock_path("winbindd_cache.tdb"),
2185 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
2186 lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
2187 O_RDWR
|O_CREAT
, 0600);
2189 if (wcache
->tdb
== NULL
) {
2190 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2197 /************************************************************************
2198 This is called by the parent to initialize the cache file.
2199 We don't need sophisticated locking here as we know we're the
2201 ************************************************************************/
2203 BOOL
initialize_winbindd_cache(void)
2205 BOOL cache_bad
= True
;
2208 if (!init_wcache()) {
2209 DEBUG(0,("initialize_winbindd_cache: init_wcache failed.\n"));
2213 /* Check version number. */
2214 if (tdb_fetch_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, &vers
) &&
2215 vers
== WINBINDD_CACHE_VERSION
) {
2220 DEBUG(0,("initialize_winbindd_cache: clearing cache "
2221 "and re-creating with version number %d\n",
2222 WINBINDD_CACHE_VERSION
));
2224 tdb_close(wcache
->tdb
);
2227 if (unlink(lock_path("winbindd_cache.tdb")) == -1) {
2228 DEBUG(0,("initialize_winbindd_cache: unlink %s failed %s ",
2229 lock_path("winbindd_cache.tdb"),
2233 if (!init_wcache()) {
2234 DEBUG(0,("initialize_winbindd_cache: re-initialization "
2235 "init_wcache failed.\n"));
2239 /* Write the version. */
2240 if (!tdb_store_uint32(wcache
->tdb
, WINBINDD_CACHE_VERSION_KEYSTR
, WINBINDD_CACHE_VERSION
)) {
2241 DEBUG(0,("initialize_winbindd_cache: version number store failed %s\n",
2242 tdb_errorstr(wcache
->tdb
) ));
2247 tdb_close(wcache
->tdb
);
2252 void cache_store_response(pid_t pid
, struct winbindd_response
*response
)
2259 DEBUG(10, ("Storing response for pid %d, len %d\n",
2260 pid
, response
->length
));
2262 fstr_sprintf(key_str
, "DR/%d", pid
);
2263 if (tdb_store(wcache
->tdb
, string_tdb_data(key_str
),
2264 make_tdb_data((const char *)response
, sizeof(*response
)),
2268 if (response
->length
== sizeof(*response
))
2271 /* There's extra data */
2273 DEBUG(10, ("Storing extra data: len=%d\n",
2274 (int)(response
->length
- sizeof(*response
))));
2276 fstr_sprintf(key_str
, "DE/%d", pid
);
2277 if (tdb_store(wcache
->tdb
, string_tdb_data(key_str
),
2278 make_tdb_data((const char *)response
->extra_data
.data
,
2279 response
->length
- sizeof(*response
)),
2283 /* We could not store the extra data, make sure the tdb does not
2284 * contain a main record with wrong dangling extra data */
2286 fstr_sprintf(key_str
, "DR/%d", pid
);
2287 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2292 BOOL
cache_retrieve_response(pid_t pid
, struct winbindd_response
* response
)
2300 DEBUG(10, ("Retrieving response for pid %d\n", pid
));
2302 fstr_sprintf(key_str
, "DR/%d", pid
);
2303 data
= tdb_fetch(wcache
->tdb
, string_tdb_data(key_str
));
2305 if (data
.dptr
== NULL
)
2308 if (data
.dsize
!= sizeof(*response
))
2311 memcpy(response
, data
.dptr
, data
.dsize
);
2312 SAFE_FREE(data
.dptr
);
2314 if (response
->length
== sizeof(*response
)) {
2315 response
->extra_data
.data
= NULL
;
2319 /* There's extra data */
2321 DEBUG(10, ("Retrieving extra data length=%d\n",
2322 (int)(response
->length
- sizeof(*response
))));
2324 fstr_sprintf(key_str
, "DE/%d", pid
);
2325 data
= tdb_fetch(wcache
->tdb
, string_tdb_data(key_str
));
2327 if (data
.dptr
== NULL
) {
2328 DEBUG(0, ("Did not find extra data\n"));
2332 if (data
.dsize
!= (response
->length
- sizeof(*response
))) {
2333 DEBUG(0, ("Invalid extra data length: %d\n", (int)data
.dsize
));
2334 SAFE_FREE(data
.dptr
);
2338 dump_data(11, data
.dptr
, data
.dsize
);
2340 response
->extra_data
.data
= data
.dptr
;
2344 void cache_cleanup_response(pid_t pid
)
2351 fstr_sprintf(key_str
, "DR/%d", pid
);
2352 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2354 fstr_sprintf(key_str
, "DE/%d", pid
);
2355 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2361 BOOL
lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const DOM_SID
*sid
,
2362 const char **domain_name
, const char **name
,
2363 enum lsa_SidType
*type
)
2365 struct winbindd_domain
*domain
;
2366 struct winbind_cache
*cache
;
2367 struct cache_entry
*centry
= NULL
;
2370 domain
= find_lookup_domain_from_sid(sid
);
2371 if (domain
== NULL
) {
2375 cache
= get_cache(domain
);
2377 if (cache
->tdb
== NULL
) {
2381 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_string_static(sid
));
2382 if (centry
== NULL
) {
2386 if (NT_STATUS_IS_OK(centry
->status
)) {
2387 *type
= (enum lsa_SidType
)centry_uint32(centry
);
2388 *domain_name
= centry_string(centry
, mem_ctx
);
2389 *name
= centry_string(centry
, mem_ctx
);
2392 status
= centry
->status
;
2393 centry_free(centry
);
2394 return NT_STATUS_IS_OK(status
);
2397 BOOL
lookup_cached_name(TALLOC_CTX
*mem_ctx
,
2398 const char *domain_name
,
2401 enum lsa_SidType
*type
)
2403 struct winbindd_domain
*domain
;
2404 struct winbind_cache
*cache
;
2405 struct cache_entry
*centry
= NULL
;
2409 domain
= find_lookup_domain_from_name(domain_name
);
2410 if (domain
== NULL
) {
2414 cache
= get_cache(domain
);
2416 if (cache
->tdb
== NULL
) {
2420 fstrcpy(uname
, name
);
2423 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
2424 if (centry
== NULL
) {
2428 if (NT_STATUS_IS_OK(centry
->status
)) {
2429 *type
= (enum lsa_SidType
)centry_uint32(centry
);
2430 centry_sid(centry
, mem_ctx
, sid
);
2433 status
= centry
->status
;
2434 centry_free(centry
);
2436 return NT_STATUS_IS_OK(status
);
2439 void cache_name2sid(struct winbindd_domain
*domain
,
2440 const char *domain_name
, const char *name
,
2441 enum lsa_SidType type
, const DOM_SID
*sid
)
2443 refresh_sequence_number(domain
, False
);
2444 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
2448 /* delete all centries that don't have NT_STATUS_OK set */
2450 * The original idea that this cache only contains centries has
2451 * been blurred - now other stuff gets put in here. Ensure we
2452 * ignore these things on cleanup.
2455 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
2456 TDB_DATA dbuf
, void *state
)
2458 struct cache_entry
*centry
;
2460 if (is_non_centry_key(kbuf
)) {
2464 centry
= wcache_fetch_raw(kbuf
.dptr
);
2469 if (!NT_STATUS_IS_OK(centry
->status
)) {
2470 DEBUG(10,("deleting centry %s\n", kbuf
.dptr
));
2471 tdb_delete(the_tdb
, kbuf
);
2474 centry_free(centry
);
2478 /* flush the cache */
2479 void wcache_flush_cache(void)
2484 tdb_close(wcache
->tdb
);
2490 /* when working offline we must not clear the cache on restart */
2491 wcache
->tdb
= tdb_open_log(lock_path("winbindd_cache.tdb"),
2492 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
2493 lp_winbind_offline_logon() ? TDB_DEFAULT
: (TDB_DEFAULT
| TDB_CLEAR_IF_FIRST
),
2494 O_RDWR
|O_CREAT
, 0600);
2497 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2501 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
2503 DEBUG(10,("wcache_flush_cache success\n"));
2506 /* Count cached creds */
2508 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2511 int *cred_count
= (int*)state
;
2513 if (strncmp(kbuf
.dptr
, "CRED/", 5) == 0) {
2519 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
2521 struct winbind_cache
*cache
= get_cache(domain
);
2526 return NT_STATUS_INTERNAL_DB_ERROR
;
2529 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
2531 return NT_STATUS_OK
;
2535 struct cred_list
*prev
, *next
;
2540 static struct cred_list
*wcache_cred_list
;
2542 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2545 struct cred_list
*cred
;
2547 if (strncmp(kbuf
.dptr
, "CRED/", 5) == 0) {
2549 cred
= SMB_MALLOC_P(struct cred_list
);
2551 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2557 /* save a copy of the key */
2559 fstrcpy(cred
->name
, kbuf
.dptr
);
2560 DLIST_ADD(wcache_cred_list
, cred
);
2566 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const DOM_SID
*sid
)
2568 struct winbind_cache
*cache
= get_cache(domain
);
2571 struct cred_list
*cred
, *oldest
= NULL
;
2574 return NT_STATUS_INTERNAL_DB_ERROR
;
2577 /* we possibly already have an entry */
2578 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
2582 DEBUG(11,("we already have an entry, deleting that\n"));
2584 fstr_sprintf(key_str
, "CRED/%s", sid_string_static(sid
));
2586 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
2588 return NT_STATUS_OK
;
2591 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
2593 return NT_STATUS_OK
;
2594 } else if ((ret
== -1) || (wcache_cred_list
== NULL
)) {
2595 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2598 ZERO_STRUCTP(oldest
);
2600 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
2605 data
= tdb_fetch(cache
->tdb
, make_tdb_data(cred
->name
, strlen(cred
->name
)));
2607 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
2609 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2613 t
= IVAL(data
.dptr
, 0);
2614 SAFE_FREE(data
.dptr
);
2617 oldest
= SMB_MALLOC_P(struct cred_list
);
2618 if (oldest
== NULL
) {
2619 status
= NT_STATUS_NO_MEMORY
;
2623 fstrcpy(oldest
->name
, cred
->name
);
2624 oldest
->created
= t
;
2628 if (t
< oldest
->created
) {
2629 fstrcpy(oldest
->name
, cred
->name
);
2630 oldest
->created
= t
;
2634 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
2635 status
= NT_STATUS_OK
;
2637 status
= NT_STATUS_UNSUCCESSFUL
;
2640 SAFE_FREE(wcache_cred_list
);
2646 /* Change the global online/offline state. */
2647 BOOL
set_global_winbindd_state_offline(void)
2651 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
2653 /* Only go offline if someone has created
2654 the key "WINBINDD_OFFLINE" in the cache tdb. */
2656 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
2657 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
2661 if (!lp_winbind_offline_logon()) {
2662 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
2666 if (global_winbindd_offline_state
) {
2667 /* Already offline. */
2671 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
2673 if (!data
.dptr
|| data
.dsize
!= 4) {
2674 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
2675 SAFE_FREE(data
.dptr
);
2678 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
2679 global_winbindd_offline_state
= True
;
2680 SAFE_FREE(data
.dptr
);
2685 void set_global_winbindd_state_online(void)
2687 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
2689 if (!lp_winbind_offline_logon()) {
2690 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
2694 if (!global_winbindd_offline_state
) {
2695 /* Already online. */
2698 global_winbindd_offline_state
= False
;
2704 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
2705 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
2708 BOOL
get_global_winbindd_state_offline(void)
2710 return global_winbindd_offline_state
;
2713 /* the cache backend methods are exposed via this structure */
2714 struct winbindd_methods cache_methods
= {