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(wcache
->tdb
->fd
, &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 set_dc_type_and_flags( 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
.low
= IVAL(centry
->data
, centry
->ofs
);
220 ret
.high
= IVAL(centry
->data
, centry
->ofs
);
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 %d bytes, have %d\n",
233 sizeof(time_t), 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(mem_ctx
, len
+1);
264 smb_panic("centry_string out of memory\n");
266 memcpy(ret
,centry
->data
+ centry
->ofs
, len
);
272 /* pull a string from a cache entry, using the supplied
275 static BOOL
centry_sid(struct cache_entry
*centry
, TALLOC_CTX
*mem_ctx
, DOM_SID
*sid
)
278 sid_string
= centry_string(centry
, mem_ctx
);
279 if (!string_to_sid(sid
, sid_string
)) {
285 /* the server is considered down if it can't give us a sequence number */
286 static BOOL
wcache_server_down(struct winbindd_domain
*domain
)
293 ret
= (domain
->sequence_number
== DOM_SEQUENCE_NONE
);
296 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
301 static NTSTATUS
fetch_cache_seqnum( struct winbindd_domain
*domain
, time_t now
)
308 DEBUG(10,("fetch_cache_seqnum: tdb == NULL\n"));
309 return NT_STATUS_UNSUCCESSFUL
;
312 fstr_sprintf( key
, "SEQNUM/%s", domain
->name
);
314 data
= tdb_fetch_bystring( wcache
->tdb
, key
);
315 if ( !data
.dptr
|| data
.dsize
!=8 ) {
316 DEBUG(10,("fetch_cache_seqnum: invalid data size key [%s]\n", key
));
317 return NT_STATUS_UNSUCCESSFUL
;
320 domain
->sequence_number
= IVAL(data
.dptr
, 0);
321 domain
->last_seq_check
= IVAL(data
.dptr
, 4);
323 SAFE_FREE(data
.dptr
);
325 /* have we expired? */
327 time_diff
= now
- domain
->last_seq_check
;
328 if ( time_diff
> lp_winbind_cache_time() ) {
329 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
330 domain
->name
, domain
->sequence_number
,
331 (uint32
)domain
->last_seq_check
));
332 return NT_STATUS_UNSUCCESSFUL
;
335 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
336 domain
->name
, domain
->sequence_number
,
337 (uint32
)domain
->last_seq_check
));
342 static NTSTATUS
store_cache_seqnum( struct winbindd_domain
*domain
)
349 DEBUG(10,("store_cache_seqnum: tdb == NULL\n"));
350 return NT_STATUS_UNSUCCESSFUL
;
353 fstr_sprintf( key_str
, "SEQNUM/%s", domain
->name
);
355 key
.dsize
= strlen(key_str
)+1;
357 SIVAL(buf
, 0, domain
->sequence_number
);
358 SIVAL(buf
, 4, domain
->last_seq_check
);
362 if ( tdb_store( wcache
->tdb
, key
, data
, TDB_REPLACE
) == -1 ) {
363 DEBUG(10,("store_cache_seqnum: tdb_store fail key [%s]\n", key_str
));
364 return NT_STATUS_UNSUCCESSFUL
;
367 DEBUG(10,("store_cache_seqnum: success [%s][%u @ %u]\n",
368 domain
->name
, domain
->sequence_number
,
369 (uint32
)domain
->last_seq_check
));
375 refresh the domain sequence number. If force is True
376 then always refresh it, no matter how recently we fetched it
379 static void refresh_sequence_number(struct winbindd_domain
*domain
, BOOL force
)
383 time_t t
= time(NULL
);
384 unsigned cache_time
= lp_winbind_cache_time();
388 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
389 /* trying to reconnect is expensive, don't do it too often */
390 if (domain
->sequence_number
== DOM_SEQUENCE_NONE
) {
395 time_diff
= t
- domain
->last_seq_check
;
397 /* see if we have to refetch the domain sequence number */
398 if (!force
&& (time_diff
< cache_time
)) {
399 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain
->name
));
403 /* try to get the sequence number from the tdb cache first */
404 /* this will update the timestamp as well */
406 status
= fetch_cache_seqnum( domain
, t
);
407 if ( NT_STATUS_IS_OK(status
) )
410 /* important! make sure that we know if this is a native
411 mode domain or not */
413 status
= domain
->backend
->sequence_number(domain
, &domain
->sequence_number
);
415 if (!NT_STATUS_IS_OK(status
)) {
416 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
419 domain
->last_status
= status
;
420 domain
->last_seq_check
= time(NULL
);
422 /* save the new sequence number ni the cache */
423 store_cache_seqnum( domain
);
426 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
427 domain
->name
, domain
->sequence_number
));
433 decide if a cache entry has expired
435 static BOOL
centry_expired(struct winbindd_domain
*domain
, const char *keystr
, struct cache_entry
*centry
)
437 /* If we've been told to be offline - stay in that state... */
438 if (lp_winbind_offline_logon() && global_winbindd_offline_state
) {
439 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
440 keystr
, domain
->name
));
444 /* when the domain is offline and we havent checked in the last 30
445 * seconds if it has become online again, return the cached entry.
446 * This deals with transient offline states... */
448 if (!domain
->online
&&
449 !NT_STATUS_IS_OK(check_negative_conn_cache(domain
->name
, domain
->dcname
))) {
450 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
451 keystr
, domain
->name
));
455 /* if the server is OK and our cache entry came from when it was down then
456 the entry is invalid */
457 if ((domain
->sequence_number
!= DOM_SEQUENCE_NONE
) &&
458 (centry
->sequence_number
== DOM_SEQUENCE_NONE
)) {
459 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
460 keystr
, domain
->name
));
464 /* if the server is down or the cache entry is not older than the
465 current sequence number then it is OK */
466 if (wcache_server_down(domain
) ||
467 centry
->sequence_number
== domain
->sequence_number
) {
468 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
469 keystr
, domain
->name
));
473 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
474 keystr
, domain
->name
));
480 static struct cache_entry
*wcache_fetch_raw(char *kstr
)
483 struct cache_entry
*centry
;
487 key
.dsize
= strlen(kstr
);
488 data
= tdb_fetch(wcache
->tdb
, key
);
494 centry
= SMB_XMALLOC_P(struct cache_entry
);
495 centry
->data
= (unsigned char *)data
.dptr
;
496 centry
->len
= data
.dsize
;
499 if (centry
->len
< 8) {
500 /* huh? corrupt cache? */
501 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr
));
506 centry
->status
= NT_STATUS(centry_uint32(centry
));
507 centry
->sequence_number
= centry_uint32(centry
);
513 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
514 number and return status
516 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
517 struct winbindd_domain
*domain
,
518 const char *format
, ...) PRINTF_ATTRIBUTE(3,4);
519 static struct cache_entry
*wcache_fetch(struct winbind_cache
*cache
,
520 struct winbindd_domain
*domain
,
521 const char *format
, ...)
525 struct cache_entry
*centry
;
527 extern BOOL opt_nocache
;
533 refresh_sequence_number(domain
, False
);
535 va_start(ap
, format
);
536 smb_xvasprintf(&kstr
, format
, ap
);
539 centry
= wcache_fetch_raw(kstr
);
540 if (centry
== NULL
) {
545 if (centry_expired(domain
, kstr
, centry
)) {
547 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
548 kstr
, domain
->name
));
555 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
556 kstr
, domain
->name
));
563 make sure we have at least len bytes available in a centry
565 static void centry_expand(struct cache_entry
*centry
, uint32 len
)
567 if (centry
->len
- centry
->ofs
>= len
)
570 centry
->data
= SMB_REALLOC(centry
->data
, centry
->len
);
572 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry
->len
));
573 smb_panic("out of memory in centry_expand");
578 push a uint32 into a centry
580 static void centry_put_uint32(struct cache_entry
*centry
, uint32 v
)
582 centry_expand(centry
, 4);
583 SIVAL(centry
->data
, centry
->ofs
, v
);
588 push a uint16 into a centry
590 static void centry_put_uint16(struct cache_entry
*centry
, uint16 v
)
592 centry_expand(centry
, 2);
593 SIVAL(centry
->data
, centry
->ofs
, v
);
598 push a uint8 into a centry
600 static void centry_put_uint8(struct cache_entry
*centry
, uint8 v
)
602 centry_expand(centry
, 1);
603 SCVAL(centry
->data
, centry
->ofs
, v
);
608 push a string into a centry
610 static void centry_put_string(struct cache_entry
*centry
, const char *s
)
615 /* null strings are marked as len 0xFFFF */
616 centry_put_uint8(centry
, 0xFF);
621 /* can't handle more than 254 char strings. Truncating is probably best */
623 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len
));
626 centry_put_uint8(centry
, len
);
627 centry_expand(centry
, len
);
628 memcpy(centry
->data
+ centry
->ofs
, s
, len
);
632 static void centry_put_sid(struct cache_entry
*centry
, const DOM_SID
*sid
)
635 centry_put_string(centry
, sid_to_string(sid_string
, sid
));
639 push a NTTIME into a centry
641 static void centry_put_nttime(struct cache_entry
*centry
, NTTIME nt
)
643 centry_expand(centry
, 8);
644 SIVAL(centry
->data
, centry
->ofs
, nt
.low
);
646 SIVAL(centry
->data
, centry
->ofs
, nt
.high
);
651 push a time_t into a centry
653 static void centry_put_time(struct cache_entry
*centry
, time_t t
)
655 centry_expand(centry
, sizeof(time_t));
656 SIVAL(centry
->data
, centry
->ofs
, t
); /* FIXME: is this correct ?? */
657 centry
->ofs
+= sizeof(time_t);
661 start a centry for output. When finished, call centry_end()
663 struct cache_entry
*centry_start(struct winbindd_domain
*domain
, NTSTATUS status
)
665 struct cache_entry
*centry
;
670 centry
= SMB_XMALLOC_P(struct cache_entry
);
672 centry
->len
= 8192; /* reasonable default */
673 centry
->data
= SMB_XMALLOC_ARRAY(uint8
, centry
->len
);
675 centry
->sequence_number
= domain
->sequence_number
;
676 centry_put_uint32(centry
, NT_STATUS_V(status
));
677 centry_put_uint32(centry
, centry
->sequence_number
);
682 finish a centry and write it to the tdb
684 static void centry_end(struct cache_entry
*centry
, const char *format
, ...) PRINTF_ATTRIBUTE(2,3);
685 static void centry_end(struct cache_entry
*centry
, const char *format
, ...)
691 va_start(ap
, format
);
692 smb_xvasprintf(&kstr
, format
, ap
);
696 key
.dsize
= strlen(kstr
);
697 data
.dptr
= (char *)centry
->data
;
698 data
.dsize
= centry
->ofs
;
700 tdb_store(wcache
->tdb
, key
, data
, TDB_REPLACE
);
704 static void wcache_save_name_to_sid(struct winbindd_domain
*domain
,
705 NTSTATUS status
, const char *domain_name
,
706 const char *name
, const DOM_SID
*sid
,
707 enum SID_NAME_USE type
)
709 struct cache_entry
*centry
;
712 centry
= centry_start(domain
, status
);
715 centry_put_uint32(centry
, type
);
716 centry_put_sid(centry
, sid
);
717 fstrcpy(uname
, name
);
719 centry_end(centry
, "NS/%s/%s", domain_name
, uname
);
720 DEBUG(10,("wcache_save_name_to_sid: %s -> %s\n", uname
,
721 sid_string_static(sid
)));
725 static void wcache_save_sid_to_name(struct winbindd_domain
*domain
, NTSTATUS status
,
726 const DOM_SID
*sid
, const char *domain_name
, const char *name
, enum SID_NAME_USE type
)
728 struct cache_entry
*centry
;
731 centry
= centry_start(domain
, status
);
734 if (NT_STATUS_IS_OK(status
)) {
735 centry_put_uint32(centry
, type
);
736 centry_put_string(centry
, domain_name
);
737 centry_put_string(centry
, name
);
739 centry_end(centry
, "SN/%s", sid_to_string(sid_string
, sid
));
740 DEBUG(10,("wcache_save_sid_to_name: %s -> %s\n", sid_string
, name
));
745 static void wcache_save_user(struct winbindd_domain
*domain
, NTSTATUS status
, WINBIND_USERINFO
*info
)
747 struct cache_entry
*centry
;
750 centry
= centry_start(domain
, status
);
753 centry_put_string(centry
, info
->acct_name
);
754 centry_put_string(centry
, info
->full_name
);
755 centry_put_string(centry
, info
->homedir
);
756 centry_put_string(centry
, info
->shell
);
757 centry_put_sid(centry
, &info
->user_sid
);
758 centry_put_sid(centry
, &info
->group_sid
);
759 centry_end(centry
, "U/%s", sid_to_string(sid_string
, &info
->user_sid
));
760 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string
, info
->acct_name
));
764 static void wcache_save_lockout_policy(struct winbindd_domain
*domain
, NTSTATUS status
, SAM_UNK_INFO_12
*lockout_policy
)
766 struct cache_entry
*centry
;
768 centry
= centry_start(domain
, status
);
772 centry_put_nttime(centry
, lockout_policy
->duration
);
773 centry_put_nttime(centry
, lockout_policy
->reset_count
);
774 centry_put_uint16(centry
, lockout_policy
->bad_attempt_lockout
);
776 centry_end(centry
, "LOC_POL/%s", domain
->name
);
778 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain
->name
));
783 static void wcache_save_password_policy(struct winbindd_domain
*domain
, NTSTATUS status
, SAM_UNK_INFO_1
*policy
)
785 struct cache_entry
*centry
;
787 centry
= centry_start(domain
, status
);
791 centry_put_uint16(centry
, policy
->min_length_password
);
792 centry_put_uint16(centry
, policy
->password_history
);
793 centry_put_uint32(centry
, policy
->password_properties
);
794 centry_put_nttime(centry
, policy
->expire
);
795 centry_put_nttime(centry
, policy
->min_passwordage
);
797 centry_end(centry
, "PWD_POL/%s", domain
->name
);
799 DEBUG(10,("wcache_save_password_policy: %s\n", domain
->name
));
804 NTSTATUS
wcache_cached_creds_exist(struct winbindd_domain
*domain
, const DOM_SID
*sid
)
806 struct winbind_cache
*cache
= get_cache(domain
);
812 return NT_STATUS_INTERNAL_DB_ERROR
;
815 if (is_null_sid(sid
)) {
816 return NT_STATUS_INVALID_SID
;
819 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
820 return NT_STATUS_INVALID_SID
;
823 fstr_sprintf(key_str
, "CRED/%s", sid_string_static(sid
));
825 data
= tdb_fetch(cache
->tdb
, make_tdb_data(key_str
, strlen(key_str
)));
827 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
833 /* Lookup creds for a SID */
834 NTSTATUS
wcache_get_creds(struct winbindd_domain
*domain
,
837 const uint8
**cached_nt_pass
)
839 struct winbind_cache
*cache
= get_cache(domain
);
840 struct cache_entry
*centry
= NULL
;
846 return NT_STATUS_INTERNAL_DB_ERROR
;
849 if (is_null_sid(sid
)) {
850 return NT_STATUS_INVALID_SID
;
853 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
854 return NT_STATUS_INVALID_SID
;
857 centry
= wcache_fetch(cache
, domain
, "CRED/%s", sid_string_static(sid
));
860 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
861 sid_string_static(sid
)));
862 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
865 t
= centry_time(centry
);
866 *cached_nt_pass
= (const uint8
*)centry_string(centry
, mem_ctx
);
869 dump_data(100, (const char *)cached_nt_pass
, NT_HASH_LEN
);
871 status
= centry
->status
;
873 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status %s\n",
874 sid_string_static(sid
), get_friendly_nt_error_msg(status
) ));
880 NTSTATUS
wcache_save_creds(struct winbindd_domain
*domain
,
883 const uint8 nt_pass
[NT_HASH_LEN
])
885 struct cache_entry
*centry
;
889 if (is_null_sid(sid
)) {
890 return NT_STATUS_INVALID_SID
;
893 if (!(sid_peek_rid(sid
, &rid
)) || (rid
== 0)) {
894 return NT_STATUS_INVALID_SID
;
897 centry
= centry_start(domain
, NT_STATUS_OK
);
899 return NT_STATUS_INTERNAL_DB_ERROR
;
903 dump_data(100, (const char *)nt_pass
, NT_HASH_LEN
);
906 centry_put_time(centry
, time(NULL
));
907 centry_put_string(centry
, (const char *)nt_pass
);
908 centry_end(centry
, "CRED/%s", sid_to_string(sid_string
, sid
));
910 DEBUG(10,("wcache_save_creds: %s\n", sid_string
));
918 /* Query display info. This is the basic user list fn */
919 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
922 WINBIND_USERINFO
**info
)
924 struct winbind_cache
*cache
= get_cache(domain
);
925 struct cache_entry
*centry
= NULL
;
927 unsigned int i
, retry
;
932 centry
= wcache_fetch(cache
, domain
, "UL/%s", domain
->name
);
936 *num_entries
= centry_uint32(centry
);
938 if (*num_entries
== 0)
941 (*info
) = TALLOC_ARRAY(mem_ctx
, WINBIND_USERINFO
, *num_entries
);
943 smb_panic("query_user_list out of memory");
944 for (i
=0; i
<(*num_entries
); i
++) {
945 (*info
)[i
].acct_name
= centry_string(centry
, mem_ctx
);
946 (*info
)[i
].full_name
= centry_string(centry
, mem_ctx
);
947 (*info
)[i
].homedir
= centry_string(centry
, mem_ctx
);
948 (*info
)[i
].shell
= centry_string(centry
, mem_ctx
);
949 centry_sid(centry
, mem_ctx
, &(*info
)[i
].user_sid
);
950 centry_sid(centry
, mem_ctx
, &(*info
)[i
].group_sid
);
954 status
= centry
->status
;
956 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status %s\n",
957 domain
->name
, get_friendly_nt_error_msg(status
) ));
966 /* Return status value returned by seq number check */
968 if (!NT_STATUS_IS_OK(domain
->last_status
))
969 return domain
->last_status
;
971 /* Put the query_user_list() in a retry loop. There appears to be
972 * some bug either with Windows 2000 or Samba's handling of large
973 * rpc replies. This manifests itself as sudden disconnection
974 * at a random point in the enumeration of a large (60k) user list.
975 * The retry loop simply tries the operation again. )-: It's not
976 * pretty but an acceptable workaround until we work out what the
977 * real problem is. */
982 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
985 status
= domain
->backend
->query_user_list(domain
, mem_ctx
, num_entries
, info
);
986 if (!NT_STATUS_IS_OK(status
))
987 DEBUG(3, ("query_user_list: returned 0x%08x, "
988 "retrying\n", NT_STATUS_V(status
)));
989 if (NT_STATUS_EQUAL(status
, NT_STATUS_UNSUCCESSFUL
)) {
990 DEBUG(3, ("query_user_list: flushing "
991 "connection cache\n"));
992 invalidate_cm_connection(&domain
->conn
);
995 } while (NT_STATUS_V(status
) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL
) &&
999 refresh_sequence_number(domain
, False
);
1000 centry
= centry_start(domain
, status
);
1003 centry_put_uint32(centry
, *num_entries
);
1004 for (i
=0; i
<(*num_entries
); i
++) {
1005 centry_put_string(centry
, (*info
)[i
].acct_name
);
1006 centry_put_string(centry
, (*info
)[i
].full_name
);
1007 centry_put_string(centry
, (*info
)[i
].homedir
);
1008 centry_put_string(centry
, (*info
)[i
].shell
);
1009 centry_put_sid(centry
, &(*info
)[i
].user_sid
);
1010 centry_put_sid(centry
, &(*info
)[i
].group_sid
);
1011 if (domain
->backend
->consistent
) {
1012 /* when the backend is consistent we can pre-prime some mappings */
1013 wcache_save_name_to_sid(domain
, NT_STATUS_OK
,
1015 (*info
)[i
].acct_name
,
1016 &(*info
)[i
].user_sid
,
1018 wcache_save_sid_to_name(domain
, NT_STATUS_OK
,
1019 &(*info
)[i
].user_sid
,
1021 (*info
)[i
].acct_name
,
1023 wcache_save_user(domain
, NT_STATUS_OK
, &(*info
)[i
]);
1026 centry_end(centry
, "UL/%s", domain
->name
);
1027 centry_free(centry
);
1033 /* list all domain groups */
1034 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
1035 TALLOC_CTX
*mem_ctx
,
1036 uint32
*num_entries
,
1037 struct acct_info
**info
)
1039 struct winbind_cache
*cache
= get_cache(domain
);
1040 struct cache_entry
*centry
= NULL
;
1047 centry
= wcache_fetch(cache
, domain
, "GL/%s/domain", domain
->name
);
1051 *num_entries
= centry_uint32(centry
);
1053 if (*num_entries
== 0)
1056 (*info
) = TALLOC_ARRAY(mem_ctx
, struct acct_info
, *num_entries
);
1058 smb_panic("enum_dom_groups out of memory");
1059 for (i
=0; i
<(*num_entries
); i
++) {
1060 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1061 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1062 (*info
)[i
].rid
= centry_uint32(centry
);
1066 status
= centry
->status
;
1068 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status %s\n",
1069 domain
->name
, get_friendly_nt_error_msg(status
) ));
1071 centry_free(centry
);
1078 /* Return status value returned by seq number check */
1080 if (!NT_STATUS_IS_OK(domain
->last_status
))
1081 return domain
->last_status
;
1083 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1086 status
= domain
->backend
->enum_dom_groups(domain
, mem_ctx
, num_entries
, info
);
1089 refresh_sequence_number(domain
, False
);
1090 centry
= centry_start(domain
, status
);
1093 centry_put_uint32(centry
, *num_entries
);
1094 for (i
=0; i
<(*num_entries
); i
++) {
1095 centry_put_string(centry
, (*info
)[i
].acct_name
);
1096 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1097 centry_put_uint32(centry
, (*info
)[i
].rid
);
1099 centry_end(centry
, "GL/%s/domain", domain
->name
);
1100 centry_free(centry
);
1106 /* list all domain groups */
1107 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
1108 TALLOC_CTX
*mem_ctx
,
1109 uint32
*num_entries
,
1110 struct acct_info
**info
)
1112 struct winbind_cache
*cache
= get_cache(domain
);
1113 struct cache_entry
*centry
= NULL
;
1120 centry
= wcache_fetch(cache
, domain
, "GL/%s/local", domain
->name
);
1124 *num_entries
= centry_uint32(centry
);
1126 if (*num_entries
== 0)
1129 (*info
) = TALLOC_ARRAY(mem_ctx
, struct acct_info
, *num_entries
);
1131 smb_panic("enum_dom_groups out of memory");
1132 for (i
=0; i
<(*num_entries
); i
++) {
1133 fstrcpy((*info
)[i
].acct_name
, centry_string(centry
, mem_ctx
));
1134 fstrcpy((*info
)[i
].acct_desc
, centry_string(centry
, mem_ctx
));
1135 (*info
)[i
].rid
= centry_uint32(centry
);
1140 /* If we are returning cached data and the domain controller
1141 is down then we don't know whether the data is up to date
1142 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1145 if (wcache_server_down(domain
)) {
1146 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1147 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1149 status
= centry
->status
;
1151 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status %s\n",
1152 domain
->name
, get_friendly_nt_error_msg(status
) ));
1154 centry_free(centry
);
1161 /* Return status value returned by seq number check */
1163 if (!NT_STATUS_IS_OK(domain
->last_status
))
1164 return domain
->last_status
;
1166 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1169 status
= domain
->backend
->enum_local_groups(domain
, mem_ctx
, num_entries
, info
);
1172 refresh_sequence_number(domain
, False
);
1173 centry
= centry_start(domain
, status
);
1176 centry_put_uint32(centry
, *num_entries
);
1177 for (i
=0; i
<(*num_entries
); i
++) {
1178 centry_put_string(centry
, (*info
)[i
].acct_name
);
1179 centry_put_string(centry
, (*info
)[i
].acct_desc
);
1180 centry_put_uint32(centry
, (*info
)[i
].rid
);
1182 centry_end(centry
, "GL/%s/local", domain
->name
);
1183 centry_free(centry
);
1189 /* convert a single name to a sid in a domain */
1190 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
1191 TALLOC_CTX
*mem_ctx
,
1192 const char *domain_name
,
1195 enum SID_NAME_USE
*type
)
1197 struct winbind_cache
*cache
= get_cache(domain
);
1198 struct cache_entry
*centry
= NULL
;
1205 fstrcpy(uname
, name
);
1207 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
1210 *type
= (enum SID_NAME_USE
)centry_uint32(centry
);
1211 status
= centry
->status
;
1212 if (NT_STATUS_IS_OK(status
)) {
1213 centry_sid(centry
, mem_ctx
, sid
);
1216 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status %s\n",
1217 domain
->name
, get_friendly_nt_error_msg(status
) ));
1219 centry_free(centry
);
1225 /* If the seq number check indicated that there is a problem
1226 * with this DC, then return that status... except for
1227 * access_denied. This is special because the dc may be in
1228 * "restrict anonymous = 1" mode, in which case it will deny
1229 * most unauthenticated operations, but *will* allow the LSA
1230 * name-to-sid that we try as a fallback. */
1232 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1233 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1234 return domain
->last_status
;
1236 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1239 status
= domain
->backend
->name_to_sid(domain
, mem_ctx
, domain_name
, name
, sid
, type
);
1242 if (domain
->online
|| !is_null_sid(sid
)) {
1243 wcache_save_name_to_sid(domain
, status
, domain_name
, name
, sid
, *type
);
1246 if (NT_STATUS_IS_OK(status
)) {
1247 strupper_m(CONST_DISCARD(char *,domain_name
));
1248 strlower_m(CONST_DISCARD(char *,name
));
1249 wcache_save_sid_to_name(domain
, status
, sid
, domain_name
, name
, *type
);
1255 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1257 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
1258 TALLOC_CTX
*mem_ctx
,
1262 enum SID_NAME_USE
*type
)
1264 struct winbind_cache
*cache
= get_cache(domain
);
1265 struct cache_entry
*centry
= NULL
;
1272 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_to_string(sid_string
, sid
));
1275 if (NT_STATUS_IS_OK(centry
->status
)) {
1276 *type
= (enum SID_NAME_USE
)centry_uint32(centry
);
1277 *domain_name
= centry_string(centry
, mem_ctx
);
1278 *name
= centry_string(centry
, mem_ctx
);
1280 status
= centry
->status
;
1282 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status %s\n",
1283 domain
->name
, get_friendly_nt_error_msg(status
) ));
1285 centry_free(centry
);
1290 *domain_name
= NULL
;
1292 /* If the seq number check indicated that there is a problem
1293 * with this DC, then return that status... except for
1294 * access_denied. This is special because the dc may be in
1295 * "restrict anonymous = 1" mode, in which case it will deny
1296 * most unauthenticated operations, but *will* allow the LSA
1297 * sid-to-name that we try as a fallback. */
1299 if (!(NT_STATUS_IS_OK(domain
->last_status
)
1300 || NT_STATUS_EQUAL(domain
->last_status
, NT_STATUS_ACCESS_DENIED
)))
1301 return domain
->last_status
;
1303 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1306 status
= domain
->backend
->sid_to_name(domain
, mem_ctx
, sid
, domain_name
, name
, type
);
1309 refresh_sequence_number(domain
, False
);
1310 wcache_save_sid_to_name(domain
, status
, sid
, *domain_name
, *name
, *type
);
1312 /* We can't save the name to sid mapping here, as with sid history a
1313 * later name2sid would give the wrong sid. */
1318 /* Lookup user information from a rid */
1319 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
1320 TALLOC_CTX
*mem_ctx
,
1321 const DOM_SID
*user_sid
,
1322 WINBIND_USERINFO
*info
)
1324 struct winbind_cache
*cache
= get_cache(domain
);
1325 struct cache_entry
*centry
= NULL
;
1331 centry
= wcache_fetch(cache
, domain
, "U/%s", sid_string_static(user_sid
));
1333 /* If we have an access denied cache entry and a cached info3 in the
1334 samlogon cache then do a query. This will force the rpc back end
1335 to return the info3 data. */
1337 if (NT_STATUS_V(domain
->last_status
) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED
) &&
1338 netsamlogon_cache_have(user_sid
)) {
1339 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1340 domain
->last_status
= NT_STATUS_OK
;
1341 centry_free(centry
);
1348 info
->acct_name
= centry_string(centry
, mem_ctx
);
1349 info
->full_name
= centry_string(centry
, mem_ctx
);
1350 info
->homedir
= centry_string(centry
, mem_ctx
);
1351 info
->shell
= centry_string(centry
, mem_ctx
);
1352 centry_sid(centry
, mem_ctx
, &info
->user_sid
);
1353 centry_sid(centry
, mem_ctx
, &info
->group_sid
);
1354 status
= centry
->status
;
1356 DEBUG(10,("query_user: [Cached] - cached info for domain %s status %s\n",
1357 domain
->name
, get_friendly_nt_error_msg(status
) ));
1359 centry_free(centry
);
1365 /* Return status value returned by seq number check */
1367 if (!NT_STATUS_IS_OK(domain
->last_status
))
1368 return domain
->last_status
;
1370 DEBUG(10,("sid_to_name: [Cached] - doing backend query for info for domain %s\n",
1373 status
= domain
->backend
->query_user(domain
, mem_ctx
, user_sid
, info
);
1376 refresh_sequence_number(domain
, False
);
1377 wcache_save_user(domain
, status
, info
);
1383 /* Lookup groups a user is a member of. */
1384 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
1385 TALLOC_CTX
*mem_ctx
,
1386 const DOM_SID
*user_sid
,
1387 uint32
*num_groups
, DOM_SID
**user_gids
)
1389 struct winbind_cache
*cache
= get_cache(domain
);
1390 struct cache_entry
*centry
= NULL
;
1398 centry
= wcache_fetch(cache
, domain
, "UG/%s", sid_to_string(sid_string
, user_sid
));
1400 /* If we have an access denied cache entry and a cached info3 in the
1401 samlogon cache then do a query. This will force the rpc back end
1402 to return the info3 data. */
1404 if (NT_STATUS_V(domain
->last_status
) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED
) &&
1405 netsamlogon_cache_have(user_sid
)) {
1406 DEBUG(10, ("lookup_usergroups: cached access denied and have cached info3\n"));
1407 domain
->last_status
= NT_STATUS_OK
;
1408 centry_free(centry
);
1415 *num_groups
= centry_uint32(centry
);
1417 if (*num_groups
== 0)
1420 (*user_gids
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_groups
);
1422 smb_panic("lookup_usergroups out of memory");
1423 for (i
=0; i
<(*num_groups
); i
++) {
1424 centry_sid(centry
, mem_ctx
, &(*user_gids
)[i
]);
1428 status
= centry
->status
;
1430 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status %s\n",
1431 domain
->name
, get_friendly_nt_error_msg(status
) ));
1433 centry_free(centry
);
1438 (*user_gids
) = NULL
;
1440 /* Return status value returned by seq number check */
1442 if (!NT_STATUS_IS_OK(domain
->last_status
))
1443 return domain
->last_status
;
1445 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
1448 status
= domain
->backend
->lookup_usergroups(domain
, mem_ctx
, user_sid
, num_groups
, user_gids
);
1451 refresh_sequence_number(domain
, False
);
1452 centry
= centry_start(domain
, status
);
1455 centry_put_uint32(centry
, *num_groups
);
1456 for (i
=0; i
<(*num_groups
); i
++) {
1457 centry_put_sid(centry
, &(*user_gids
)[i
]);
1459 centry_end(centry
, "UG/%s", sid_to_string(sid_string
, user_sid
));
1460 centry_free(centry
);
1466 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
1467 TALLOC_CTX
*mem_ctx
,
1468 uint32 num_sids
, const DOM_SID
*sids
,
1469 uint32
*num_aliases
, uint32
**alias_rids
)
1471 struct winbind_cache
*cache
= get_cache(domain
);
1472 struct cache_entry
*centry
= NULL
;
1474 char *sidlist
= talloc_strdup(mem_ctx
, "");
1480 if (num_sids
== 0) {
1483 return NT_STATUS_OK
;
1486 /* We need to cache indexed by the whole list of SIDs, the aliases
1487 * resulting might come from any of the SIDs. */
1489 for (i
=0; i
<num_sids
; i
++) {
1490 sidlist
= talloc_asprintf(mem_ctx
, "%s/%s", sidlist
,
1491 sid_string_static(&sids
[i
]));
1492 if (sidlist
== NULL
)
1493 return NT_STATUS_NO_MEMORY
;
1496 centry
= wcache_fetch(cache
, domain
, "UA%s", sidlist
);
1501 *num_aliases
= centry_uint32(centry
);
1504 (*alias_rids
) = TALLOC_ARRAY(mem_ctx
, uint32
, *num_aliases
);
1506 if ((*num_aliases
!= 0) && ((*alias_rids
) == NULL
)) {
1507 centry_free(centry
);
1508 return NT_STATUS_NO_MEMORY
;
1511 for (i
=0; i
<(*num_aliases
); i
++)
1512 (*alias_rids
)[i
] = centry_uint32(centry
);
1514 status
= centry
->status
;
1516 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain %s "
1517 "status %s\n", domain
->name
,
1518 get_friendly_nt_error_msg(status
)));
1520 centry_free(centry
);
1525 (*alias_rids
) = NULL
;
1527 if (!NT_STATUS_IS_OK(domain
->last_status
))
1528 return domain
->last_status
;
1530 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
1531 "for domain %s\n", domain
->name
));
1533 status
= domain
->backend
->lookup_useraliases(domain
, mem_ctx
,
1535 num_aliases
, alias_rids
);
1538 refresh_sequence_number(domain
, False
);
1539 centry
= centry_start(domain
, status
);
1542 centry_put_uint32(centry
, *num_aliases
);
1543 for (i
=0; i
<(*num_aliases
); i
++)
1544 centry_put_uint32(centry
, (*alias_rids
)[i
]);
1545 centry_end(centry
, "UA%s", sidlist
);
1546 centry_free(centry
);
1553 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
1554 TALLOC_CTX
*mem_ctx
,
1555 const DOM_SID
*group_sid
, uint32
*num_names
,
1556 DOM_SID
**sid_mem
, char ***names
,
1557 uint32
**name_types
)
1559 struct winbind_cache
*cache
= get_cache(domain
);
1560 struct cache_entry
*centry
= NULL
;
1568 centry
= wcache_fetch(cache
, domain
, "GM/%s", sid_to_string(sid_string
, group_sid
));
1572 *num_names
= centry_uint32(centry
);
1574 if (*num_names
== 0)
1577 (*sid_mem
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_names
);
1578 (*names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_names
);
1579 (*name_types
) = TALLOC_ARRAY(mem_ctx
, uint32
, *num_names
);
1581 if (! (*sid_mem
) || ! (*names
) || ! (*name_types
)) {
1582 smb_panic("lookup_groupmem out of memory");
1585 for (i
=0; i
<(*num_names
); i
++) {
1586 centry_sid(centry
, mem_ctx
, &(*sid_mem
)[i
]);
1587 (*names
)[i
] = centry_string(centry
, mem_ctx
);
1588 (*name_types
)[i
] = centry_uint32(centry
);
1592 status
= centry
->status
;
1594 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status %s\n",
1595 domain
->name
, get_friendly_nt_error_msg(status
) ));
1597 centry_free(centry
);
1604 (*name_types
) = NULL
;
1606 /* Return status value returned by seq number check */
1608 if (!NT_STATUS_IS_OK(domain
->last_status
))
1609 return domain
->last_status
;
1611 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
1614 status
= domain
->backend
->lookup_groupmem(domain
, mem_ctx
, group_sid
, num_names
,
1615 sid_mem
, names
, name_types
);
1618 refresh_sequence_number(domain
, False
);
1619 centry
= centry_start(domain
, status
);
1622 centry_put_uint32(centry
, *num_names
);
1623 for (i
=0; i
<(*num_names
); i
++) {
1624 centry_put_sid(centry
, &(*sid_mem
)[i
]);
1625 centry_put_string(centry
, (*names
)[i
]);
1626 centry_put_uint32(centry
, (*name_types
)[i
]);
1628 centry_end(centry
, "GM/%s", sid_to_string(sid_string
, group_sid
));
1629 centry_free(centry
);
1635 /* find the sequence number for a domain */
1636 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
1638 refresh_sequence_number(domain
, False
);
1640 *seq
= domain
->sequence_number
;
1642 return NT_STATUS_OK
;
1645 /* enumerate trusted domains
1646 * (we need to have the list of trustdoms in the cache when we go offline) -
1648 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
1649 TALLOC_CTX
*mem_ctx
,
1650 uint32
*num_domains
,
1655 struct winbind_cache
*cache
= get_cache(domain
);
1656 struct cache_entry
*centry
= NULL
;
1663 centry
= wcache_fetch(cache
, domain
, "TRUSTDOMS/%s", domain
->name
);
1669 *num_domains
= centry_uint32(centry
);
1671 (*names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
1672 (*alt_names
) = TALLOC_ARRAY(mem_ctx
, char *, *num_domains
);
1673 (*dom_sids
) = TALLOC_ARRAY(mem_ctx
, DOM_SID
, *num_domains
);
1675 if (! (*dom_sids
) || ! (*names
) || ! (*alt_names
)) {
1676 smb_panic("trusted_domains out of memory");
1679 for (i
=0; i
<(*num_domains
); i
++) {
1680 (*names
)[i
] = centry_string(centry
, mem_ctx
);
1681 (*alt_names
)[i
] = centry_string(centry
, mem_ctx
);
1682 centry_sid(centry
, mem_ctx
, &(*dom_sids
)[i
]);
1685 status
= centry
->status
;
1687 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status %s\n",
1688 domain
->name
, *num_domains
, get_friendly_nt_error_msg(status
) ));
1690 centry_free(centry
);
1697 (*alt_names
) = NULL
;
1699 /* Return status value returned by seq number check */
1701 if (!NT_STATUS_IS_OK(domain
->last_status
))
1702 return domain
->last_status
;
1704 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
1707 status
= domain
->backend
->trusted_domains(domain
, mem_ctx
, num_domains
,
1708 names
, alt_names
, dom_sids
);
1710 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
1711 * so that the generic centry handling still applies correctly -
1714 if (!NT_STATUS_IS_ERR(status
)) {
1715 status
= NT_STATUS_OK
;
1719 refresh_sequence_number(domain
, False
);
1721 centry
= centry_start(domain
, status
);
1725 centry_put_uint32(centry
, *num_domains
);
1727 for (i
=0; i
<(*num_domains
); i
++) {
1728 centry_put_string(centry
, (*names
)[i
]);
1729 centry_put_string(centry
, (*alt_names
)[i
]);
1730 centry_put_sid(centry
, &(*dom_sids
)[i
]);
1733 centry_end(centry
, "TRUSTDOMS/%s", domain
->name
);
1735 centry_free(centry
);
1741 /* get lockout policy */
1742 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
1743 TALLOC_CTX
*mem_ctx
,
1744 SAM_UNK_INFO_12
*policy
){
1745 struct winbind_cache
*cache
= get_cache(domain
);
1746 struct cache_entry
*centry
= NULL
;
1752 centry
= wcache_fetch(cache
, domain
, "LOC_POL/%s", domain
->name
);
1757 policy
->duration
= centry_nttime(centry
);
1758 policy
->reset_count
= centry_nttime(centry
);
1759 policy
->bad_attempt_lockout
= centry_uint16(centry
);
1761 status
= centry
->status
;
1763 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status %s\n",
1764 domain
->name
, get_friendly_nt_error_msg(status
) ));
1766 centry_free(centry
);
1770 ZERO_STRUCTP(policy
);
1772 /* Return status value returned by seq number check */
1774 if (!NT_STATUS_IS_OK(domain
->last_status
))
1775 return domain
->last_status
;
1777 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
1780 status
= domain
->backend
->lockout_policy(domain
, mem_ctx
, policy
);
1783 refresh_sequence_number(domain
, False
);
1784 wcache_save_lockout_policy(domain
, status
, policy
);
1789 /* get password policy */
1790 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
1791 TALLOC_CTX
*mem_ctx
,
1792 SAM_UNK_INFO_1
*policy
)
1794 struct winbind_cache
*cache
= get_cache(domain
);
1795 struct cache_entry
*centry
= NULL
;
1801 centry
= wcache_fetch(cache
, domain
, "PWD_POL/%s", domain
->name
);
1806 policy
->min_length_password
= centry_uint16(centry
);
1807 policy
->password_history
= centry_uint16(centry
);
1808 policy
->password_properties
= centry_uint32(centry
);
1809 policy
->expire
= centry_nttime(centry
);
1810 policy
->min_passwordage
= centry_nttime(centry
);
1812 status
= centry
->status
;
1814 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status %s\n",
1815 domain
->name
, get_friendly_nt_error_msg(status
) ));
1817 centry_free(centry
);
1821 ZERO_STRUCTP(policy
);
1823 /* Return status value returned by seq number check */
1825 if (!NT_STATUS_IS_OK(domain
->last_status
))
1826 return domain
->last_status
;
1828 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
1831 status
= domain
->backend
->password_policy(domain
, mem_ctx
, policy
);
1834 refresh_sequence_number(domain
, False
);
1835 wcache_save_password_policy(domain
, status
, policy
);
1841 /* Invalidate cached user and group lists coherently */
1843 static int traverse_fn(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
1846 if (strncmp(kbuf
.dptr
, "UL/", 3) == 0 ||
1847 strncmp(kbuf
.dptr
, "GL/", 3) == 0)
1848 tdb_delete(the_tdb
, kbuf
);
1853 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
1855 void wcache_invalidate_samlogon(struct winbindd_domain
*domain
,
1856 NET_USER_INFO_3
*info3
)
1858 struct winbind_cache
*cache
;
1863 cache
= get_cache(domain
);
1864 netsamlogon_clear_cached_user(cache
->tdb
, info3
);
1867 void wcache_invalidate_cache(void)
1869 struct winbindd_domain
*domain
;
1871 for (domain
= domain_list(); domain
; domain
= domain
->next
) {
1872 struct winbind_cache
*cache
= get_cache(domain
);
1874 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
1875 "entries for %s\n", domain
->name
));
1877 tdb_traverse(cache
->tdb
, traverse_fn
, NULL
);
1881 static BOOL
init_wcache(void)
1883 if (wcache
== NULL
) {
1884 wcache
= SMB_XMALLOC_P(struct winbind_cache
);
1885 ZERO_STRUCTP(wcache
);
1888 if (wcache
->tdb
!= NULL
)
1891 /* when working offline we must not clear the cache on restart */
1892 wcache
->tdb
= tdb_open_log(lock_path("winbindd_cache.tdb"),
1893 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
1894 TDB_DEFAULT
/*TDB_CLEAR_IF_FIRST*/, O_RDWR
|O_CREAT
, 0600);
1896 if (wcache
->tdb
== NULL
) {
1897 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
1904 void cache_store_response(pid_t pid
, struct winbindd_response
*response
)
1911 DEBUG(10, ("Storing response for pid %d, len %d\n",
1912 pid
, response
->length
));
1914 fstr_sprintf(key_str
, "DR/%d", pid
);
1915 if (tdb_store(wcache
->tdb
, string_tdb_data(key_str
),
1916 make_tdb_data((void *)response
, sizeof(*response
)),
1920 if (response
->length
== sizeof(*response
))
1923 /* There's extra data */
1925 DEBUG(10, ("Storing extra data: len=%d\n",
1926 (int)(response
->length
- sizeof(*response
))));
1928 fstr_sprintf(key_str
, "DE/%d", pid
);
1929 if (tdb_store(wcache
->tdb
, string_tdb_data(key_str
),
1930 make_tdb_data(response
->extra_data
.data
,
1931 response
->length
- sizeof(*response
)),
1935 /* We could not store the extra data, make sure the tdb does not
1936 * contain a main record with wrong dangling extra data */
1938 fstr_sprintf(key_str
, "DR/%d", pid
);
1939 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
1944 BOOL
cache_retrieve_response(pid_t pid
, struct winbindd_response
* response
)
1952 DEBUG(10, ("Retrieving response for pid %d\n", pid
));
1954 fstr_sprintf(key_str
, "DR/%d", pid
);
1955 data
= tdb_fetch(wcache
->tdb
, string_tdb_data(key_str
));
1957 if (data
.dptr
== NULL
)
1960 if (data
.dsize
!= sizeof(*response
))
1963 memcpy(response
, data
.dptr
, data
.dsize
);
1964 SAFE_FREE(data
.dptr
);
1966 if (response
->length
== sizeof(*response
)) {
1967 response
->extra_data
.data
= NULL
;
1971 /* There's extra data */
1973 DEBUG(10, ("Retrieving extra data length=%d\n",
1974 (int)(response
->length
- sizeof(*response
))));
1976 fstr_sprintf(key_str
, "DE/%d", pid
);
1977 data
= tdb_fetch(wcache
->tdb
, string_tdb_data(key_str
));
1979 if (data
.dptr
== NULL
) {
1980 DEBUG(0, ("Did not find extra data\n"));
1984 if (data
.dsize
!= (response
->length
- sizeof(*response
))) {
1985 DEBUG(0, ("Invalid extra data length: %d\n", (int)data
.dsize
));
1986 SAFE_FREE(data
.dptr
);
1990 dump_data(11, data
.dptr
, data
.dsize
);
1992 response
->extra_data
.data
= data
.dptr
;
1996 void cache_cleanup_response(pid_t pid
)
2003 fstr_sprintf(key_str
, "DR/%d", pid
);
2004 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2006 fstr_sprintf(key_str
, "DE/%d", pid
);
2007 tdb_delete(wcache
->tdb
, string_tdb_data(key_str
));
2013 BOOL
lookup_cached_sid(TALLOC_CTX
*mem_ctx
, const DOM_SID
*sid
,
2014 const char **domain_name
, const char **name
,
2015 enum SID_NAME_USE
*type
)
2017 struct winbindd_domain
*domain
;
2018 struct winbind_cache
*cache
;
2019 struct cache_entry
*centry
= NULL
;
2022 domain
= find_lookup_domain_from_sid(sid
);
2023 if (domain
== NULL
) {
2027 cache
= get_cache(domain
);
2029 if (cache
->tdb
== NULL
) {
2033 centry
= wcache_fetch(cache
, domain
, "SN/%s", sid_string_static(sid
));
2034 if (centry
== NULL
) {
2038 if (NT_STATUS_IS_OK(centry
->status
)) {
2039 *type
= (enum SID_NAME_USE
)centry_uint32(centry
);
2040 *domain_name
= centry_string(centry
, mem_ctx
);
2041 *name
= centry_string(centry
, mem_ctx
);
2044 status
= centry
->status
;
2045 centry_free(centry
);
2046 return NT_STATUS_IS_OK(status
);
2049 BOOL
lookup_cached_name(TALLOC_CTX
*mem_ctx
,
2050 const char *domain_name
,
2053 enum SID_NAME_USE
*type
)
2055 struct winbindd_domain
*domain
;
2056 struct winbind_cache
*cache
;
2057 struct cache_entry
*centry
= NULL
;
2061 domain
= find_lookup_domain_from_name(domain_name
);
2062 if (domain
== NULL
) {
2066 cache
= get_cache(domain
);
2068 if (cache
->tdb
== NULL
) {
2072 fstrcpy(uname
, name
);
2075 centry
= wcache_fetch(cache
, domain
, "NS/%s/%s", domain_name
, uname
);
2076 if (centry
== NULL
) {
2080 if (NT_STATUS_IS_OK(centry
->status
)) {
2081 *type
= (enum SID_NAME_USE
)centry_uint32(centry
);
2082 centry_sid(centry
, mem_ctx
, sid
);
2085 status
= centry
->status
;
2086 centry_free(centry
);
2088 return NT_STATUS_IS_OK(status
);
2091 void cache_name2sid(struct winbindd_domain
*domain
,
2092 const char *domain_name
, const char *name
,
2093 enum SID_NAME_USE type
, const DOM_SID
*sid
)
2095 wcache_save_name_to_sid(domain
, NT_STATUS_OK
, domain_name
, name
,
2099 /* delete all centries that don't have NT_STATUS_OK set */
2100 static int traverse_fn_cleanup(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
,
2101 TDB_DATA dbuf
, void *state
)
2103 struct cache_entry
*centry
;
2105 centry
= wcache_fetch_raw(kbuf
.dptr
);
2110 if (!NT_STATUS_IS_OK(centry
->status
)) {
2111 DEBUG(10,("deleting centry %s\n", kbuf
.dptr
));
2112 tdb_delete(the_tdb
, kbuf
);
2115 centry_free(centry
);
2119 /* flush the cache */
2120 void wcache_flush_cache(void)
2122 extern BOOL opt_nocache
;
2127 tdb_close(wcache
->tdb
);
2133 /* when working offline we must not clear the cache on restart */
2134 wcache
->tdb
= tdb_open_log(lock_path("winbindd_cache.tdb"),
2135 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE
,
2136 TDB_DEFAULT
/* TDB_CLEAR_IF_FIRST */, O_RDWR
|O_CREAT
, 0600);
2139 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2142 tdb_traverse(wcache
->tdb
, traverse_fn_cleanup
, NULL
);
2144 DEBUG(10,("wcache_flush_cache success\n"));
2147 /* Count cached creds */
2149 static int traverse_fn_cached_creds(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2152 int *cred_count
= (int*)state
;
2154 if (strncmp(kbuf
.dptr
, "CRED/", 5) == 0) {
2160 NTSTATUS
wcache_count_cached_creds(struct winbindd_domain
*domain
, int *count
)
2162 struct winbind_cache
*cache
= get_cache(domain
);
2167 return NT_STATUS_INTERNAL_DB_ERROR
;
2170 tdb_traverse(cache
->tdb
, traverse_fn_cached_creds
, (void *)count
);
2172 return NT_STATUS_OK
;
2176 struct cred_list
*prev
, *next
;
2181 static struct cred_list
*wcache_cred_list
;
2183 static int traverse_fn_get_credlist(TDB_CONTEXT
*the_tdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
2186 struct cred_list
*cred
;
2188 if (strncmp(kbuf
.dptr
, "CRED/", 5) == 0) {
2190 cred
= SMB_MALLOC_P(struct cred_list
);
2192 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2198 /* save a copy of the key */
2200 fstrcpy(cred
->name
, kbuf
.dptr
);
2201 DLIST_ADD(wcache_cred_list
, cred
);
2207 NTSTATUS
wcache_remove_oldest_cached_creds(struct winbindd_domain
*domain
, const DOM_SID
*sid
)
2209 struct winbind_cache
*cache
= get_cache(domain
);
2212 struct cred_list
*cred
, *oldest
= NULL
;
2215 return NT_STATUS_INTERNAL_DB_ERROR
;
2218 /* we possibly already have an entry */
2219 if (sid
&& NT_STATUS_IS_OK(wcache_cached_creds_exist(domain
, sid
))) {
2223 DEBUG(11,("we already have an entry, deleting that\n"));
2225 fstr_sprintf(key_str
, "CRED/%s", sid_string_static(sid
));
2227 tdb_delete(cache
->tdb
, string_tdb_data(key_str
));
2229 return NT_STATUS_OK
;
2232 ret
= tdb_traverse(cache
->tdb
, traverse_fn_get_credlist
, NULL
);
2234 return NT_STATUS_OK
;
2235 } else if (ret
== -1) {
2236 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2239 ZERO_STRUCTP(oldest
);
2241 for (cred
= wcache_cred_list
; cred
; cred
= cred
->next
) {
2246 data
= tdb_fetch(cache
->tdb
, make_tdb_data(cred
->name
, strlen(cred
->name
)));
2248 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
2250 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
2254 t
= IVAL(data
.dptr
, 0);
2255 SAFE_FREE(data
.dptr
);
2258 oldest
= SMB_MALLOC_P(struct cred_list
);
2259 if (oldest
== NULL
) {
2260 status
= NT_STATUS_NO_MEMORY
;
2264 fstrcpy(oldest
->name
, cred
->name
);
2265 oldest
->created
= t
;
2269 if (t
< oldest
->created
) {
2270 fstrcpy(oldest
->name
, cred
->name
);
2271 oldest
->created
= t
;
2275 if (tdb_delete(cache
->tdb
, string_tdb_data(oldest
->name
)) == 0) {
2276 status
= NT_STATUS_OK
;
2278 status
= NT_STATUS_UNSUCCESSFUL
;
2281 SAFE_FREE(wcache_cred_list
);
2287 /* Change the global online/offline state. */
2288 BOOL
set_global_winbindd_state_offline(void)
2293 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
2295 /* Only go offline if someone has created
2296 the key "WINBINDD_OFFLINE" in the cache tdb. */
2298 if (wcache
== NULL
|| wcache
->tdb
== NULL
) {
2299 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
2303 if (!lp_winbind_offline_logon()) {
2304 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
2308 if (global_winbindd_offline_state
) {
2309 /* Already offline. */
2313 wcache
->tdb
->ecode
= 0;
2315 data
= tdb_fetch_bystring( wcache
->tdb
, "WINBINDD_OFFLINE" );
2317 /* As this is a key with no data we don't need to free, we
2318 check for existence by looking at tdb_err. */
2320 err
= tdb_error(wcache
->tdb
);
2322 if (err
== TDB_ERR_NOEXIST
) {
2323 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
2326 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
2327 global_winbindd_offline_state
= True
;
2332 void set_global_winbindd_state_online(void)
2334 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
2336 if (!lp_winbind_offline_logon()) {
2337 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
2341 if (!global_winbindd_offline_state
) {
2342 /* Already online. */
2345 global_winbindd_offline_state
= False
;
2351 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
2352 tdb_delete_bystring(wcache
->tdb
, "WINBINDD_OFFLINE");
2355 BOOL
get_global_winbindd_state_online(void)
2357 return global_winbindd_offline_state
;
2360 /* the cache backend methods are exposed via this structure */
2361 struct winbindd_methods cache_methods
= {