2 Unix SMB/CIFS implementation.
4 Winbind cache backend functions
6 Copyright (C) Andrew Tridgell 2001
7 Copyright (C) Gerald Carter 2003
8 Copyright (C) Volker Lendecke 2005
9 Copyright (C) Guenther Deschner 2005
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30 #define DBGC_CLASS DBGC_WINBIND
32 /* Global online/offline state - False when online. winbindd starts up online
33 and sets this to true if the first query fails and there's an entry in
34 the cache tdb telling us to stay offline. */
36 static BOOL global_winbindd_offline_state;
38 struct winbind_cache {
44 uint32 sequence_number;
49 #define WINBINDD_MAX_CACHE_SIZE (50*1024*1024)
51 static struct winbind_cache *wcache;
53 void winbindd_check_cache_size(time_t t)
55 static time_t last_check_time;
58 if (last_check_time == (time_t)0)
61 if (t - last_check_time < 60 && t - last_check_time > 0)
64 if (wcache == NULL || wcache->tdb == NULL) {
65 DEBUG(0, ("Unable to check size of tdb cache - cache not open !\n"));
69 if (fstat(tdb_fd(wcache->tdb), &st) == -1) {
70 DEBUG(0, ("Unable to check size of tdb cache %s!\n", strerror(errno) ));
74 if (st.st_size > WINBINDD_MAX_CACHE_SIZE) {
75 DEBUG(10,("flushing cache due to size (%lu) > (%lu)\n",
76 (unsigned long)st.st_size,
77 (unsigned long)WINBINDD_MAX_CACHE_SIZE));
82 /* get the winbind_cache structure */
83 static struct winbind_cache *get_cache(struct winbindd_domain *domain)
85 struct winbind_cache *ret = wcache;
87 struct winbindd_domain *our_domain = domain;
90 /* we have to know what type of domain we are dealing with first */
92 if ( !domain->initialized )
93 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 = IVAL(centry->data, centry->ofs);
220 ret += (uint64_t)IVAL(centry->data, centry->ofs) << 32;
226 pull a time_t from a cache entry
228 static time_t centry_time(struct cache_entry *centry)
231 if (centry->len - centry->ofs < sizeof(time_t)) {
232 DEBUG(0,("centry corruption? needed %u bytes, have %u\n",
233 (unsigned int)sizeof(time_t), (unsigned int)(centry->len - centry->ofs)));
234 smb_panic("centry_time");
236 ret = IVAL(centry->data, centry->ofs); /* FIXME: correct ? */
237 centry->ofs += sizeof(time_t);
241 /* pull a string from a cache entry, using the supplied
244 static char *centry_string(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
249 len = centry_uint8(centry);
252 /* a deliberate NULL string */
256 if (centry->len - centry->ofs < len) {
257 DEBUG(0,("centry corruption? needed %d bytes, have %d\n",
258 len, centry->len - centry->ofs));
259 smb_panic("centry_string");
262 ret = TALLOC_ARRAY(mem_ctx, char, len+1);
264 smb_panic("centry_string out of memory\n");
266 memcpy(ret,centry->data + centry->ofs, len);
272 /* pull a hash16 from a cache entry, using the supplied
275 static char *centry_hash16(struct cache_entry *centry, TALLOC_CTX *mem_ctx)
280 len = centry_uint8(centry);
283 DEBUG(0,("centry corruption? hash len (%u) != 16\n",
285 smb_panic("centry_hash16");
288 if (centry->len - centry->ofs < 16) {
289 DEBUG(0,("centry corruption? needed 16 bytes, have %d\n",
290 centry->len - centry->ofs));
291 smb_panic("centry_hash16");
294 ret = TALLOC_ARRAY(mem_ctx, char, 16);
296 smb_panic("centry_hash out of memory\n");
298 memcpy(ret,centry->data + centry->ofs, 16);
303 /* pull a sid from a cache entry, using the supplied
306 static BOOL centry_sid(struct cache_entry *centry, TALLOC_CTX *mem_ctx, DOM_SID *sid)
309 sid_string = centry_string(centry, mem_ctx);
310 if ((sid_string == NULL) || (!string_to_sid(sid, sid_string))) {
316 /* the server is considered down if it can't give us a sequence number */
317 static BOOL wcache_server_down(struct winbindd_domain *domain)
324 ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
327 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
332 static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
339 DEBUG(10,("fetch_cache_seqnum: tdb == NULL\n"));
340 return NT_STATUS_UNSUCCESSFUL;
343 fstr_sprintf( key, "SEQNUM/%s", domain->name );
345 data = tdb_fetch_bystring( wcache->tdb, key );
346 if ( !data.dptr || data.dsize!=8 ) {
347 DEBUG(10,("fetch_cache_seqnum: invalid data size key [%s]\n", key ));
348 return NT_STATUS_UNSUCCESSFUL;
351 domain->sequence_number = IVAL(data.dptr, 0);
352 domain->last_seq_check = IVAL(data.dptr, 4);
354 SAFE_FREE(data.dptr);
356 /* have we expired? */
358 time_diff = now - domain->last_seq_check;
359 if ( time_diff > lp_winbind_cache_time() ) {
360 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
361 domain->name, domain->sequence_number,
362 (uint32)domain->last_seq_check));
363 return NT_STATUS_UNSUCCESSFUL;
366 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
367 domain->name, domain->sequence_number,
368 (uint32)domain->last_seq_check));
373 static NTSTATUS store_cache_seqnum( struct winbindd_domain *domain )
380 DEBUG(10,("store_cache_seqnum: tdb == NULL\n"));
381 return NT_STATUS_UNSUCCESSFUL;
384 fstr_sprintf( key_str, "SEQNUM/%s", domain->name );
386 key.dsize = strlen(key_str)+1;
388 SIVAL(buf, 0, domain->sequence_number);
389 SIVAL(buf, 4, domain->last_seq_check);
393 if ( tdb_store( wcache->tdb, key, data, TDB_REPLACE) == -1 ) {
394 DEBUG(10,("store_cache_seqnum: tdb_store fail key [%s]\n", key_str ));
395 return NT_STATUS_UNSUCCESSFUL;
398 DEBUG(10,("store_cache_seqnum: success [%s][%u @ %u]\n",
399 domain->name, domain->sequence_number,
400 (uint32)domain->last_seq_check));
406 refresh the domain sequence number. If force is True
407 then always refresh it, no matter how recently we fetched it
410 static void refresh_sequence_number(struct winbindd_domain *domain, BOOL force)
414 time_t t = time(NULL);
415 unsigned cache_time = lp_winbind_cache_time();
419 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
420 /* trying to reconnect is expensive, don't do it too often */
421 if (domain->sequence_number == DOM_SEQUENCE_NONE) {
426 time_diff = t - domain->last_seq_check;
428 /* see if we have to refetch the domain sequence number */
429 if (!force && (time_diff < cache_time)) {
430 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
434 /* try to get the sequence number from the tdb cache first */
435 /* this will update the timestamp as well */
437 status = fetch_cache_seqnum( domain, t );
438 if ( NT_STATUS_IS_OK(status) )
441 /* important! make sure that we know if this is a native
442 mode domain or not */
444 status = domain->backend->sequence_number(domain, &domain->sequence_number);
446 if (!NT_STATUS_IS_OK(status)) {
447 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status)));
448 domain->sequence_number = DOM_SEQUENCE_NONE;
451 domain->last_status = status;
452 domain->last_seq_check = time(NULL);
454 /* save the new sequence number ni the cache */
455 store_cache_seqnum( domain );
458 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
459 domain->name, domain->sequence_number));
465 decide if a cache entry has expired
467 static BOOL centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
469 /* If we've been told to be offline - stay in that state... */
470 if (lp_winbind_offline_logon() && global_winbindd_offline_state) {
471 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
472 keystr, domain->name ));
476 /* when the domain is offline return the cached entry.
477 * This deals with transient offline states... */
479 if (!domain->online) {
480 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
481 keystr, domain->name ));
485 /* if the server is OK and our cache entry came from when it was down then
486 the entry is invalid */
487 if ((domain->sequence_number != DOM_SEQUENCE_NONE) &&
488 (centry->sequence_number == DOM_SEQUENCE_NONE)) {
489 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
490 keystr, domain->name ));
494 /* if the server is down or the cache entry is not older than the
495 current sequence number then it is OK */
496 if (wcache_server_down(domain) ||
497 centry->sequence_number == domain->sequence_number) {
498 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
499 keystr, domain->name ));
503 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
504 keystr, domain->name ));
510 static struct cache_entry *wcache_fetch_raw(char *kstr)
513 struct cache_entry *centry;
517 key.dsize = strlen(kstr);
518 data = tdb_fetch(wcache->tdb, key);
524 centry = SMB_XMALLOC_P(struct cache_entry);
525 centry->data = (unsigned char *)data.dptr;
526 centry->len = data.dsize;
529 if (centry->len < 8) {
530 /* huh? corrupt cache? */
531 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr));
536 centry->status = NT_STATUS(centry_uint32(centry));
537 centry->sequence_number = centry_uint32(centry);
543 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
544 number and return status
546 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
547 struct winbindd_domain *domain,
548 const char *format, ...) PRINTF_ATTRIBUTE(3,4);
549 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
550 struct winbindd_domain *domain,
551 const char *format, ...)
555 struct cache_entry *centry;
557 extern BOOL opt_nocache;
563 refresh_sequence_number(domain, False);
565 va_start(ap, format);
566 smb_xvasprintf(&kstr, format, ap);
569 centry = wcache_fetch_raw(kstr);
570 if (centry == NULL) {
575 if (centry_expired(domain, kstr, centry)) {
577 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
578 kstr, domain->name ));
585 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
586 kstr, domain->name ));
593 make sure we have at least len bytes available in a centry
595 static void centry_expand(struct cache_entry *centry, uint32 len)
597 if (centry->len - centry->ofs >= len)
600 centry->data = SMB_REALLOC_ARRAY(centry->data, unsigned char,
603 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
604 smb_panic("out of memory in centry_expand");
609 push a uint32 into a centry
611 static void centry_put_uint32(struct cache_entry *centry, uint32 v)
613 centry_expand(centry, 4);
614 SIVAL(centry->data, centry->ofs, v);
619 push a uint16 into a centry
621 static void centry_put_uint16(struct cache_entry *centry, uint16 v)
623 centry_expand(centry, 2);
624 SIVAL(centry->data, centry->ofs, v);
629 push a uint8 into a centry
631 static void centry_put_uint8(struct cache_entry *centry, uint8 v)
633 centry_expand(centry, 1);
634 SCVAL(centry->data, centry->ofs, v);
639 push a string into a centry
641 static void centry_put_string(struct cache_entry *centry, const char *s)
646 /* null strings are marked as len 0xFFFF */
647 centry_put_uint8(centry, 0xFF);
652 /* can't handle more than 254 char strings. Truncating is probably best */
654 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len));
657 centry_put_uint8(centry, len);
658 centry_expand(centry, len);
659 memcpy(centry->data + centry->ofs, s, len);
664 push a 16 byte hash into a centry - treat as 16 byte string.
666 static void centry_put_hash16(struct cache_entry *centry, const uint8 val[16])
668 centry_put_uint8(centry, 16);
669 centry_expand(centry, 16);
670 memcpy(centry->data + centry->ofs, val, 16);
674 static void centry_put_sid(struct cache_entry *centry, const DOM_SID *sid)
677 centry_put_string(centry, sid_to_string(sid_string, sid));
681 push a NTTIME into a centry
683 static void centry_put_nttime(struct cache_entry *centry, NTTIME nt)
685 centry_expand(centry, 8);
686 SIVAL(centry->data, centry->ofs, nt & 0xFFFFFFFF);
688 SIVAL(centry->data, centry->ofs, nt >> 32);
693 push a time_t into a centry
695 static void centry_put_time(struct cache_entry *centry, time_t t)
697 centry_expand(centry, sizeof(time_t));
698 SIVAL(centry->data, centry->ofs, t); /* FIXME: is this correct ?? */
699 centry->ofs += sizeof(time_t);
703 start a centry for output. When finished, call centry_end()
705 struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status)
707 struct cache_entry *centry;
712 centry = SMB_XMALLOC_P(struct cache_entry);
714 centry->len = 8192; /* reasonable default */
715 centry->data = SMB_XMALLOC_ARRAY(uint8, centry->len);
717 centry->sequence_number = domain->sequence_number;
718 centry_put_uint32(centry, NT_STATUS_V(status));
719 centry_put_uint32(centry, centry->sequence_number);
724 finish a centry and write it to the tdb
726 static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
727 static void centry_end(struct cache_entry *centry, const char *format, ...)
733 va_start(ap, format);
734 smb_xvasprintf(&kstr, format, ap);
738 key.dsize = strlen(kstr);
739 data.dptr = (char *)centry->data;
740 data.dsize = centry->ofs;
742 tdb_store(wcache->tdb, key, data, TDB_REPLACE);
746 static void wcache_save_name_to_sid(struct winbindd_domain *domain,
747 NTSTATUS status, const char *domain_name,
748 const char *name, const DOM_SID *sid,
749 enum SID_NAME_USE type)
751 struct cache_entry *centry;
754 centry = centry_start(domain, status);
757 centry_put_uint32(centry, type);
758 centry_put_sid(centry, sid);
759 fstrcpy(uname, name);
761 centry_end(centry, "NS/%s/%s", domain_name, uname);
762 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s\n", domain_name, uname,
763 sid_string_static(sid)));
767 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
768 const DOM_SID *sid, const char *domain_name, const char *name, enum SID_NAME_USE type)
770 struct cache_entry *centry;
773 centry = centry_start(domain, status);
776 if (NT_STATUS_IS_OK(status)) {
777 centry_put_uint32(centry, type);
778 centry_put_string(centry, domain_name);
779 centry_put_string(centry, name);
781 centry_end(centry, "SN/%s", sid_to_string(sid_string, sid));
782 DEBUG(10,("wcache_save_sid_to_name: %s -> %s\n", sid_string, name));
787 static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status, WINBIND_USERINFO *info)
789 struct cache_entry *centry;
792 centry = centry_start(domain, status);
795 centry_put_string(centry, info->acct_name);
796 centry_put_string(centry, info->full_name);
797 centry_put_string(centry, info->homedir);
798 centry_put_string(centry, info->shell);
799 centry_put_sid(centry, &info->user_sid);
800 centry_put_sid(centry, &info->group_sid);
801 centry_end(centry, "U/%s", sid_to_string(sid_string, &info->user_sid));
802 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
806 static void wcache_save_lockout_policy(struct winbindd_domain *domain, NTSTATUS status, SAM_UNK_INFO_12 *lockout_policy)
808 struct cache_entry *centry;
810 centry = centry_start(domain, status);
814 centry_put_nttime(centry, lockout_policy->duration);
815 centry_put_nttime(centry, lockout_policy->reset_count);
816 centry_put_uint16(centry, lockout_policy->bad_attempt_lockout);
818 centry_end(centry, "LOC_POL/%s", domain->name);
820 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
825 static void wcache_save_password_policy(struct winbindd_domain *domain, NTSTATUS status, SAM_UNK_INFO_1 *policy)
827 struct cache_entry *centry;
829 centry = centry_start(domain, status);
833 centry_put_uint16(centry, policy->min_length_password);
834 centry_put_uint16(centry, policy->password_history);
835 centry_put_uint32(centry, policy->password_properties);
836 centry_put_nttime(centry, policy->expire);
837 centry_put_nttime(centry, policy->min_passwordage);
839 centry_end(centry, "PWD_POL/%s", domain->name);
841 DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
846 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const DOM_SID *sid)
848 struct winbind_cache *cache = get_cache(domain);
854 return NT_STATUS_INTERNAL_DB_ERROR;
857 if (is_null_sid(sid)) {
858 return NT_STATUS_INVALID_SID;
861 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
862 return NT_STATUS_INVALID_SID;
865 fstr_sprintf(key_str, "CRED/%s", sid_string_static(sid));
867 data = tdb_fetch(cache->tdb, make_tdb_data(key_str, strlen(key_str)));
869 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
872 SAFE_FREE(data.dptr);
876 /* Lookup creds for a SID - copes with old (unsalted) creds as well
877 as new salted ones. */
879 NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
882 const uint8 **cached_nt_pass,
883 const uint8 **cached_salt)
885 struct winbind_cache *cache = get_cache(domain);
886 struct cache_entry *centry = NULL;
892 return NT_STATUS_INTERNAL_DB_ERROR;
895 if (is_null_sid(sid)) {
896 return NT_STATUS_INVALID_SID;
899 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
900 return NT_STATUS_INVALID_SID;
903 /* Try and get a salted cred first. If we can't
904 fall back to an unsalted cred. */
906 centry = wcache_fetch(cache, domain, "CRED/%s", sid_string_static(sid));
908 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
909 sid_string_static(sid)));
910 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
913 t = centry_time(centry);
915 /* In the salted case this isn't actually the nt_hash itself,
916 but the MD5 of the salt + nt_hash. Let the caller
917 sort this out. It can tell as we only return the cached_salt
918 if we are returning a salted cred. */
920 *cached_nt_pass = (const uint8 *)centry_hash16(centry, mem_ctx);
922 /* We only have 17 bytes more data in the salted cred case. */
923 if (centry->len - centry->ofs == 17) {
924 *cached_salt = (const uint8 *)centry_hash16(centry, mem_ctx);
930 dump_data(100, (const char *)*cached_nt_pass, NT_HASH_LEN);
932 dump_data(100, (const char *)*cached_salt, NT_HASH_LEN);
935 status = centry->status;
937 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
938 sid_string_static(sid), nt_errstr(status) ));
944 /* Store creds for a SID - only writes out new salted ones. */
946 NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
949 const uint8 nt_pass[NT_HASH_LEN])
951 struct cache_entry *centry;
954 uint8 cred_salt[NT_HASH_LEN];
955 uint8 salted_hash[NT_HASH_LEN];
957 if (is_null_sid(sid)) {
958 return NT_STATUS_INVALID_SID;
961 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
962 return NT_STATUS_INVALID_SID;
965 centry = centry_start(domain, NT_STATUS_OK);
967 return NT_STATUS_INTERNAL_DB_ERROR;
971 dump_data(100, (const char *)nt_pass, NT_HASH_LEN);
974 centry_put_time(centry, time(NULL));
976 /* Create a salt and then salt the hash. */
977 generate_random_buffer(cred_salt, NT_HASH_LEN);
978 E_md5hash(cred_salt, nt_pass, salted_hash);
980 centry_put_hash16(centry, salted_hash);
981 centry_put_hash16(centry, cred_salt);
982 centry_end(centry, "CRED/%s", sid_to_string(sid_string, sid));
984 DEBUG(10,("wcache_save_creds: %s\n", sid_string));
992 /* Query display info. This is the basic user list fn */
993 static NTSTATUS query_user_list(struct winbindd_domain *domain,
996 WINBIND_USERINFO **info)
998 struct winbind_cache *cache = get_cache(domain);
999 struct cache_entry *centry = NULL;
1001 unsigned int i, retry;
1006 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1010 *num_entries = centry_uint32(centry);
1012 if (*num_entries == 0)
1015 (*info) = TALLOC_ARRAY(mem_ctx, WINBIND_USERINFO, *num_entries);
1017 smb_panic("query_user_list out of memory");
1018 for (i=0; i<(*num_entries); i++) {
1019 (*info)[i].acct_name = centry_string(centry, mem_ctx);
1020 (*info)[i].full_name = centry_string(centry, mem_ctx);
1021 (*info)[i].homedir = centry_string(centry, mem_ctx);
1022 (*info)[i].shell = centry_string(centry, mem_ctx);
1023 centry_sid(centry, mem_ctx, &(*info)[i].user_sid);
1024 centry_sid(centry, mem_ctx, &(*info)[i].group_sid);
1028 status = centry->status;
1030 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1031 domain->name, nt_errstr(status) ));
1033 centry_free(centry);
1040 /* Return status value returned by seq number check */
1042 if (!NT_STATUS_IS_OK(domain->last_status))
1043 return domain->last_status;
1045 /* Put the query_user_list() in a retry loop. There appears to be
1046 * some bug either with Windows 2000 or Samba's handling of large
1047 * rpc replies. This manifests itself as sudden disconnection
1048 * at a random point in the enumeration of a large (60k) user list.
1049 * The retry loop simply tries the operation again. )-: It's not
1050 * pretty but an acceptable workaround until we work out what the
1051 * real problem is. */
1056 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1059 status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
1060 if (!NT_STATUS_IS_OK(status))
1061 DEBUG(3, ("query_user_list: returned 0x%08x, "
1062 "retrying\n", NT_STATUS_V(status)));
1063 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1064 DEBUG(3, ("query_user_list: flushing "
1065 "connection cache\n"));
1066 invalidate_cm_connection(&domain->conn);
1069 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
1073 refresh_sequence_number(domain, False);
1074 centry = centry_start(domain, status);
1077 centry_put_uint32(centry, *num_entries);
1078 for (i=0; i<(*num_entries); i++) {
1079 centry_put_string(centry, (*info)[i].acct_name);
1080 centry_put_string(centry, (*info)[i].full_name);
1081 centry_put_string(centry, (*info)[i].homedir);
1082 centry_put_string(centry, (*info)[i].shell);
1083 centry_put_sid(centry, &(*info)[i].user_sid);
1084 centry_put_sid(centry, &(*info)[i].group_sid);
1085 if (domain->backend->consistent) {
1086 /* when the backend is consistent we can pre-prime some mappings */
1087 wcache_save_name_to_sid(domain, NT_STATUS_OK,
1089 (*info)[i].acct_name,
1090 &(*info)[i].user_sid,
1092 wcache_save_sid_to_name(domain, NT_STATUS_OK,
1093 &(*info)[i].user_sid,
1095 (*info)[i].acct_name,
1097 wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
1100 centry_end(centry, "UL/%s", domain->name);
1101 centry_free(centry);
1107 /* list all domain groups */
1108 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
1109 TALLOC_CTX *mem_ctx,
1110 uint32 *num_entries,
1111 struct acct_info **info)
1113 struct winbind_cache *cache = get_cache(domain);
1114 struct cache_entry *centry = NULL;
1121 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1125 *num_entries = centry_uint32(centry);
1127 if (*num_entries == 0)
1130 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1132 smb_panic("enum_dom_groups out of memory");
1133 for (i=0; i<(*num_entries); i++) {
1134 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1135 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1136 (*info)[i].rid = centry_uint32(centry);
1140 status = centry->status;
1142 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1143 domain->name, nt_errstr(status) ));
1145 centry_free(centry);
1152 /* Return status value returned by seq number check */
1154 if (!NT_STATUS_IS_OK(domain->last_status))
1155 return domain->last_status;
1157 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1160 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1163 refresh_sequence_number(domain, False);
1164 centry = centry_start(domain, status);
1167 centry_put_uint32(centry, *num_entries);
1168 for (i=0; i<(*num_entries); i++) {
1169 centry_put_string(centry, (*info)[i].acct_name);
1170 centry_put_string(centry, (*info)[i].acct_desc);
1171 centry_put_uint32(centry, (*info)[i].rid);
1173 centry_end(centry, "GL/%s/domain", domain->name);
1174 centry_free(centry);
1180 /* list all domain groups */
1181 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
1182 TALLOC_CTX *mem_ctx,
1183 uint32 *num_entries,
1184 struct acct_info **info)
1186 struct winbind_cache *cache = get_cache(domain);
1187 struct cache_entry *centry = NULL;
1194 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1198 *num_entries = centry_uint32(centry);
1200 if (*num_entries == 0)
1203 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1205 smb_panic("enum_dom_groups out of memory");
1206 for (i=0; i<(*num_entries); i++) {
1207 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1208 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1209 (*info)[i].rid = centry_uint32(centry);
1214 /* If we are returning cached data and the domain controller
1215 is down then we don't know whether the data is up to date
1216 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1219 if (wcache_server_down(domain)) {
1220 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1221 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1223 status = centry->status;
1225 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1226 domain->name, nt_errstr(status) ));
1228 centry_free(centry);
1235 /* Return status value returned by seq number check */
1237 if (!NT_STATUS_IS_OK(domain->last_status))
1238 return domain->last_status;
1240 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1243 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1246 refresh_sequence_number(domain, False);
1247 centry = centry_start(domain, status);
1250 centry_put_uint32(centry, *num_entries);
1251 for (i=0; i<(*num_entries); i++) {
1252 centry_put_string(centry, (*info)[i].acct_name);
1253 centry_put_string(centry, (*info)[i].acct_desc);
1254 centry_put_uint32(centry, (*info)[i].rid);
1256 centry_end(centry, "GL/%s/local", domain->name);
1257 centry_free(centry);
1263 /* convert a single name to a sid in a domain */
1264 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
1265 TALLOC_CTX *mem_ctx,
1266 const char *domain_name,
1269 enum SID_NAME_USE *type)
1271 struct winbind_cache *cache = get_cache(domain);
1272 struct cache_entry *centry = NULL;
1279 fstrcpy(uname, name);
1281 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1284 *type = (enum SID_NAME_USE)centry_uint32(centry);
1285 status = centry->status;
1286 if (NT_STATUS_IS_OK(status)) {
1287 centry_sid(centry, mem_ctx, sid);
1290 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: %s\n",
1291 domain->name, nt_errstr(status) ));
1293 centry_free(centry);
1299 /* If the seq number check indicated that there is a problem
1300 * with this DC, then return that status... except for
1301 * access_denied. This is special because the dc may be in
1302 * "restrict anonymous = 1" mode, in which case it will deny
1303 * most unauthenticated operations, but *will* allow the LSA
1304 * name-to-sid that we try as a fallback. */
1306 if (!(NT_STATUS_IS_OK(domain->last_status)
1307 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1308 return domain->last_status;
1310 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1313 status = domain->backend->name_to_sid(domain, mem_ctx, domain_name, name, sid, type);
1316 if (domain->online && !is_null_sid(sid)) {
1317 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1320 if (NT_STATUS_IS_OK(status)) {
1321 strupper_m(CONST_DISCARD(char *,domain_name));
1322 strlower_m(CONST_DISCARD(char *,name));
1323 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1329 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1331 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
1332 TALLOC_CTX *mem_ctx,
1336 enum SID_NAME_USE *type)
1338 struct winbind_cache *cache = get_cache(domain);
1339 struct cache_entry *centry = NULL;
1346 centry = wcache_fetch(cache, domain, "SN/%s", sid_to_string(sid_string, sid));
1349 if (NT_STATUS_IS_OK(centry->status)) {
1350 *type = (enum SID_NAME_USE)centry_uint32(centry);
1351 *domain_name = centry_string(centry, mem_ctx);
1352 *name = centry_string(centry, mem_ctx);
1354 status = centry->status;
1356 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: %s\n",
1357 domain->name, nt_errstr(status) ));
1359 centry_free(centry);
1364 *domain_name = NULL;
1366 /* If the seq number check indicated that there is a problem
1367 * with this DC, then return that status... except for
1368 * access_denied. This is special because the dc may be in
1369 * "restrict anonymous = 1" mode, in which case it will deny
1370 * most unauthenticated operations, but *will* allow the LSA
1371 * sid-to-name that we try as a fallback. */
1373 if (!(NT_STATUS_IS_OK(domain->last_status)
1374 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1375 return domain->last_status;
1377 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1380 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1383 refresh_sequence_number(domain, False);
1384 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1386 /* We can't save the name to sid mapping here, as with sid history a
1387 * later name2sid would give the wrong sid. */
1392 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
1393 TALLOC_CTX *mem_ctx,
1394 const DOM_SID *domain_sid,
1399 enum SID_NAME_USE **types)
1401 struct winbind_cache *cache = get_cache(domain);
1403 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1407 *domain_name = NULL;
1415 if (num_rids == 0) {
1416 return NT_STATUS_OK;
1419 *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
1420 *types = TALLOC_ARRAY(mem_ctx, enum SID_NAME_USE, num_rids);
1422 if ((*names == NULL) || (*types == NULL)) {
1423 result = NT_STATUS_NO_MEMORY;
1427 have_mapped = have_unmapped = False;
1429 for (i=0; i<num_rids; i++) {
1431 struct cache_entry *centry;
1433 if (!sid_compose(&sid, domain_sid, rids[i])) {
1434 result = NT_STATUS_INTERNAL_ERROR;
1438 centry = wcache_fetch(cache, domain, "SN/%s",
1439 sid_string_static(&sid));
1444 (*types)[i] = SID_NAME_UNKNOWN;
1445 (*names)[i] = talloc_strdup(*names, "");
1447 if (NT_STATUS_IS_OK(centry->status)) {
1450 (*types)[i] = (enum SID_NAME_USE)centry_uint32(centry);
1451 dom = centry_string(centry, mem_ctx);
1452 if (*domain_name == NULL) {
1457 (*names)[i] = centry_string(centry, *names);
1459 have_unmapped = True;
1462 centry_free(centry);
1466 return NT_STATUS_NONE_MAPPED;
1468 if (!have_unmapped) {
1469 return NT_STATUS_OK;
1471 return STATUS_SOME_UNMAPPED;
1475 TALLOC_FREE(*names);
1476 TALLOC_FREE(*types);
1478 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
1479 rids, num_rids, domain_name,
1482 if (!NT_STATUS_IS_OK(result) &&
1483 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
1487 refresh_sequence_number(domain, False);
1489 for (i=0; i<num_rids; i++) {
1493 if (!sid_compose(&sid, domain_sid, rids[i])) {
1494 result = NT_STATUS_INTERNAL_ERROR;
1498 status = (*types)[i] == SID_NAME_UNKNOWN ?
1499 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
1501 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
1502 (*names)[i], (*types)[i]);
1509 TALLOC_FREE(*names);
1510 TALLOC_FREE(*types);
1514 /* Lookup user information from a rid */
1515 static NTSTATUS query_user(struct winbindd_domain *domain,
1516 TALLOC_CTX *mem_ctx,
1517 const DOM_SID *user_sid,
1518 WINBIND_USERINFO *info)
1520 struct winbind_cache *cache = get_cache(domain);
1521 struct cache_entry *centry = NULL;
1527 centry = wcache_fetch(cache, domain, "U/%s", sid_string_static(user_sid));
1529 /* If we have an access denied cache entry and a cached info3 in the
1530 samlogon cache then do a query. This will force the rpc back end
1531 to return the info3 data. */
1533 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1534 netsamlogon_cache_have(user_sid)) {
1535 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1536 domain->last_status = NT_STATUS_OK;
1537 centry_free(centry);
1544 info->acct_name = centry_string(centry, mem_ctx);
1545 info->full_name = centry_string(centry, mem_ctx);
1546 info->homedir = centry_string(centry, mem_ctx);
1547 info->shell = centry_string(centry, mem_ctx);
1548 centry_sid(centry, mem_ctx, &info->user_sid);
1549 centry_sid(centry, mem_ctx, &info->group_sid);
1550 status = centry->status;
1552 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: %s\n",
1553 domain->name, nt_errstr(status) ));
1555 centry_free(centry);
1561 /* Return status value returned by seq number check */
1563 if (!NT_STATUS_IS_OK(domain->last_status))
1564 return domain->last_status;
1566 DEBUG(10,("sid_to_name: [Cached] - doing backend query for info for domain %s\n",
1569 status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
1572 refresh_sequence_number(domain, False);
1573 wcache_save_user(domain, status, info);
1579 /* Lookup groups a user is a member of. */
1580 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
1581 TALLOC_CTX *mem_ctx,
1582 const DOM_SID *user_sid,
1583 uint32 *num_groups, DOM_SID **user_gids)
1585 struct winbind_cache *cache = get_cache(domain);
1586 struct cache_entry *centry = NULL;
1594 centry = wcache_fetch(cache, domain, "UG/%s", sid_to_string(sid_string, user_sid));
1596 /* If we have an access denied cache entry and a cached info3 in the
1597 samlogon cache then do a query. This will force the rpc back end
1598 to return the info3 data. */
1600 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1601 netsamlogon_cache_have(user_sid)) {
1602 DEBUG(10, ("lookup_usergroups: cached access denied and have cached info3\n"));
1603 domain->last_status = NT_STATUS_OK;
1604 centry_free(centry);
1611 *num_groups = centry_uint32(centry);
1613 if (*num_groups == 0)
1616 (*user_gids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
1618 smb_panic("lookup_usergroups out of memory");
1619 for (i=0; i<(*num_groups); i++) {
1620 centry_sid(centry, mem_ctx, &(*user_gids)[i]);
1624 status = centry->status;
1626 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status: %s\n",
1627 domain->name, nt_errstr(status) ));
1629 centry_free(centry);
1634 (*user_gids) = NULL;
1636 /* Return status value returned by seq number check */
1638 if (!NT_STATUS_IS_OK(domain->last_status))
1639 return domain->last_status;
1641 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
1644 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
1647 refresh_sequence_number(domain, False);
1648 centry = centry_start(domain, status);
1651 centry_put_uint32(centry, *num_groups);
1652 for (i=0; i<(*num_groups); i++) {
1653 centry_put_sid(centry, &(*user_gids)[i]);
1655 centry_end(centry, "UG/%s", sid_to_string(sid_string, user_sid));
1656 centry_free(centry);
1662 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
1663 TALLOC_CTX *mem_ctx,
1664 uint32 num_sids, const DOM_SID *sids,
1665 uint32 *num_aliases, uint32 **alias_rids)
1667 struct winbind_cache *cache = get_cache(domain);
1668 struct cache_entry *centry = NULL;
1670 char *sidlist = talloc_strdup(mem_ctx, "");
1676 if (num_sids == 0) {
1679 return NT_STATUS_OK;
1682 /* We need to cache indexed by the whole list of SIDs, the aliases
1683 * resulting might come from any of the SIDs. */
1685 for (i=0; i<num_sids; i++) {
1686 sidlist = talloc_asprintf(mem_ctx, "%s/%s", sidlist,
1687 sid_string_static(&sids[i]));
1688 if (sidlist == NULL)
1689 return NT_STATUS_NO_MEMORY;
1692 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
1697 *num_aliases = centry_uint32(centry);
1700 (*alias_rids) = TALLOC_ARRAY(mem_ctx, uint32, *num_aliases);
1702 if ((*num_aliases != 0) && ((*alias_rids) == NULL)) {
1703 centry_free(centry);
1704 return NT_STATUS_NO_MEMORY;
1707 for (i=0; i<(*num_aliases); i++)
1708 (*alias_rids)[i] = centry_uint32(centry);
1710 status = centry->status;
1712 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
1713 "status %s\n", domain->name, nt_errstr(status)));
1715 centry_free(centry);
1720 (*alias_rids) = NULL;
1722 if (!NT_STATUS_IS_OK(domain->last_status))
1723 return domain->last_status;
1725 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
1726 "for domain %s\n", domain->name ));
1728 status = domain->backend->lookup_useraliases(domain, mem_ctx,
1730 num_aliases, alias_rids);
1733 refresh_sequence_number(domain, False);
1734 centry = centry_start(domain, status);
1737 centry_put_uint32(centry, *num_aliases);
1738 for (i=0; i<(*num_aliases); i++)
1739 centry_put_uint32(centry, (*alias_rids)[i]);
1740 centry_end(centry, "UA%s", sidlist);
1741 centry_free(centry);
1748 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1749 TALLOC_CTX *mem_ctx,
1750 const DOM_SID *group_sid, uint32 *num_names,
1751 DOM_SID **sid_mem, char ***names,
1752 uint32 **name_types)
1754 struct winbind_cache *cache = get_cache(domain);
1755 struct cache_entry *centry = NULL;
1763 centry = wcache_fetch(cache, domain, "GM/%s", sid_to_string(sid_string, group_sid));
1767 *num_names = centry_uint32(centry);
1769 if (*num_names == 0)
1772 (*sid_mem) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_names);
1773 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_names);
1774 (*name_types) = TALLOC_ARRAY(mem_ctx, uint32, *num_names);
1776 if (! (*sid_mem) || ! (*names) || ! (*name_types)) {
1777 smb_panic("lookup_groupmem out of memory");
1780 for (i=0; i<(*num_names); i++) {
1781 centry_sid(centry, mem_ctx, &(*sid_mem)[i]);
1782 (*names)[i] = centry_string(centry, mem_ctx);
1783 (*name_types)[i] = centry_uint32(centry);
1787 status = centry->status;
1789 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status: %s\n",
1790 domain->name, nt_errstr(status)));
1792 centry_free(centry);
1799 (*name_types) = NULL;
1801 /* Return status value returned by seq number check */
1803 if (!NT_STATUS_IS_OK(domain->last_status))
1804 return domain->last_status;
1806 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
1809 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid, num_names,
1810 sid_mem, names, name_types);
1813 refresh_sequence_number(domain, False);
1814 centry = centry_start(domain, status);
1817 centry_put_uint32(centry, *num_names);
1818 for (i=0; i<(*num_names); i++) {
1819 centry_put_sid(centry, &(*sid_mem)[i]);
1820 centry_put_string(centry, (*names)[i]);
1821 centry_put_uint32(centry, (*name_types)[i]);
1823 centry_end(centry, "GM/%s", sid_to_string(sid_string, group_sid));
1824 centry_free(centry);
1830 /* find the sequence number for a domain */
1831 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
1833 refresh_sequence_number(domain, False);
1835 *seq = domain->sequence_number;
1837 return NT_STATUS_OK;
1840 /* enumerate trusted domains
1841 * (we need to have the list of trustdoms in the cache when we go offline) -
1843 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1844 TALLOC_CTX *mem_ctx,
1845 uint32 *num_domains,
1850 struct winbind_cache *cache = get_cache(domain);
1851 struct cache_entry *centry = NULL;
1858 centry = wcache_fetch(cache, domain, "TRUSTDOMS/%s", domain->name);
1864 *num_domains = centry_uint32(centry);
1866 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
1867 (*alt_names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
1868 (*dom_sids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
1870 if (! (*dom_sids) || ! (*names) || ! (*alt_names)) {
1871 smb_panic("trusted_domains out of memory");
1874 for (i=0; i<(*num_domains); i++) {
1875 (*names)[i] = centry_string(centry, mem_ctx);
1876 (*alt_names)[i] = centry_string(centry, mem_ctx);
1877 centry_sid(centry, mem_ctx, &(*dom_sids)[i]);
1880 status = centry->status;
1882 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
1883 domain->name, *num_domains, nt_errstr(status) ));
1885 centry_free(centry);
1892 (*alt_names) = NULL;
1894 /* Return status value returned by seq number check */
1896 if (!NT_STATUS_IS_OK(domain->last_status))
1897 return domain->last_status;
1899 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
1902 status = domain->backend->trusted_domains(domain, mem_ctx, num_domains,
1903 names, alt_names, dom_sids);
1905 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
1906 * so that the generic centry handling still applies correctly -
1909 if (!NT_STATUS_IS_ERR(status)) {
1910 status = NT_STATUS_OK;
1914 refresh_sequence_number(domain, False);
1916 centry = centry_start(domain, status);
1920 centry_put_uint32(centry, *num_domains);
1922 for (i=0; i<(*num_domains); i++) {
1923 centry_put_string(centry, (*names)[i]);
1924 centry_put_string(centry, (*alt_names)[i]);
1925 centry_put_sid(centry, &(*dom_sids)[i]);
1928 centry_end(centry, "TRUSTDOMS/%s", domain->name);
1930 centry_free(centry);
1936 /* get lockout policy */
1937 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
1938 TALLOC_CTX *mem_ctx,
1939 SAM_UNK_INFO_12 *policy){
1940 struct winbind_cache *cache = get_cache(domain);
1941 struct cache_entry *centry = NULL;
1947 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
1952 policy->duration = centry_nttime(centry);
1953 policy->reset_count = centry_nttime(centry);
1954 policy->bad_attempt_lockout = centry_uint16(centry);
1956 status = centry->status;
1958 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
1959 domain->name, nt_errstr(status) ));
1961 centry_free(centry);
1965 ZERO_STRUCTP(policy);
1967 /* Return status value returned by seq number check */
1969 if (!NT_STATUS_IS_OK(domain->last_status))
1970 return domain->last_status;
1972 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
1975 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
1978 refresh_sequence_number(domain, False);
1979 wcache_save_lockout_policy(domain, status, policy);
1984 /* get password policy */
1985 static NTSTATUS password_policy(struct winbindd_domain *domain,
1986 TALLOC_CTX *mem_ctx,
1987 SAM_UNK_INFO_1 *policy)
1989 struct winbind_cache *cache = get_cache(domain);
1990 struct cache_entry *centry = NULL;
1996 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2001 policy->min_length_password = centry_uint16(centry);
2002 policy->password_history = centry_uint16(centry);
2003 policy->password_properties = centry_uint32(centry);
2004 policy->expire = centry_nttime(centry);
2005 policy->min_passwordage = centry_nttime(centry);
2007 status = centry->status;
2009 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2010 domain->name, nt_errstr(status) ));
2012 centry_free(centry);
2016 ZERO_STRUCTP(policy);
2018 /* Return status value returned by seq number check */
2020 if (!NT_STATUS_IS_OK(domain->last_status))
2021 return domain->last_status;
2023 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2026 status = domain->backend->password_policy(domain, mem_ctx, policy);
2029 refresh_sequence_number(domain, False);
2030 wcache_save_password_policy(domain, status, policy);
2036 /* Invalidate cached user and group lists coherently */
2038 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2041 if (strncmp(kbuf.dptr, "UL/", 3) == 0 ||
2042 strncmp(kbuf.dptr, "GL/", 3) == 0)
2043 tdb_delete(the_tdb, kbuf);
2048 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2050 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
2051 NET_USER_INFO_3 *info3)
2053 struct winbind_cache *cache;
2058 cache = get_cache(domain);
2059 netsamlogon_clear_cached_user(cache->tdb, info3);
2062 void wcache_invalidate_cache(void)
2064 struct winbindd_domain *domain;
2066 for (domain = domain_list(); domain; domain = domain->next) {
2067 struct winbind_cache *cache = get_cache(domain);
2069 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2070 "entries for %s\n", domain->name));
2072 tdb_traverse(cache->tdb, traverse_fn, NULL);
2076 static BOOL init_wcache(void)
2078 if (wcache == NULL) {
2079 wcache = SMB_XMALLOC_P(struct winbind_cache);
2080 ZERO_STRUCTP(wcache);
2083 if (wcache->tdb != NULL)
2086 /* when working offline we must not clear the cache on restart */
2087 wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
2088 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2089 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
2090 O_RDWR|O_CREAT, 0600);
2092 if (wcache->tdb == NULL) {
2093 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2100 void cache_store_response(pid_t pid, struct winbindd_response *response)
2107 DEBUG(10, ("Storing response for pid %d, len %d\n",
2108 pid, response->length));
2110 fstr_sprintf(key_str, "DR/%d", pid);
2111 if (tdb_store(wcache->tdb, string_tdb_data(key_str),
2112 make_tdb_data((const char *)response, sizeof(*response)),
2116 if (response->length == sizeof(*response))
2119 /* There's extra data */
2121 DEBUG(10, ("Storing extra data: len=%d\n",
2122 (int)(response->length - sizeof(*response))));
2124 fstr_sprintf(key_str, "DE/%d", pid);
2125 if (tdb_store(wcache->tdb, string_tdb_data(key_str),
2126 make_tdb_data((const char *)response->extra_data.data,
2127 response->length - sizeof(*response)),
2131 /* We could not store the extra data, make sure the tdb does not
2132 * contain a main record with wrong dangling extra data */
2134 fstr_sprintf(key_str, "DR/%d", pid);
2135 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2140 BOOL cache_retrieve_response(pid_t pid, struct winbindd_response * response)
2148 DEBUG(10, ("Retrieving response for pid %d\n", pid));
2150 fstr_sprintf(key_str, "DR/%d", pid);
2151 data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
2153 if (data.dptr == NULL)
2156 if (data.dsize != sizeof(*response))
2159 memcpy(response, data.dptr, data.dsize);
2160 SAFE_FREE(data.dptr);
2162 if (response->length == sizeof(*response)) {
2163 response->extra_data.data = NULL;
2167 /* There's extra data */
2169 DEBUG(10, ("Retrieving extra data length=%d\n",
2170 (int)(response->length - sizeof(*response))));
2172 fstr_sprintf(key_str, "DE/%d", pid);
2173 data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
2175 if (data.dptr == NULL) {
2176 DEBUG(0, ("Did not find extra data\n"));
2180 if (data.dsize != (response->length - sizeof(*response))) {
2181 DEBUG(0, ("Invalid extra data length: %d\n", (int)data.dsize));
2182 SAFE_FREE(data.dptr);
2186 dump_data(11, data.dptr, data.dsize);
2188 response->extra_data.data = data.dptr;
2192 void cache_cleanup_response(pid_t pid)
2199 fstr_sprintf(key_str, "DR/%d", pid);
2200 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2202 fstr_sprintf(key_str, "DE/%d", pid);
2203 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2209 BOOL lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
2210 const char **domain_name, const char **name,
2211 enum SID_NAME_USE *type)
2213 struct winbindd_domain *domain;
2214 struct winbind_cache *cache;
2215 struct cache_entry *centry = NULL;
2218 domain = find_lookup_domain_from_sid(sid);
2219 if (domain == NULL) {
2223 cache = get_cache(domain);
2225 if (cache->tdb == NULL) {
2229 centry = wcache_fetch(cache, domain, "SN/%s", sid_string_static(sid));
2230 if (centry == NULL) {
2234 if (NT_STATUS_IS_OK(centry->status)) {
2235 *type = (enum SID_NAME_USE)centry_uint32(centry);
2236 *domain_name = centry_string(centry, mem_ctx);
2237 *name = centry_string(centry, mem_ctx);
2240 status = centry->status;
2241 centry_free(centry);
2242 return NT_STATUS_IS_OK(status);
2245 BOOL lookup_cached_name(TALLOC_CTX *mem_ctx,
2246 const char *domain_name,
2249 enum SID_NAME_USE *type)
2251 struct winbindd_domain *domain;
2252 struct winbind_cache *cache;
2253 struct cache_entry *centry = NULL;
2257 domain = find_lookup_domain_from_name(domain_name);
2258 if (domain == NULL) {
2262 cache = get_cache(domain);
2264 if (cache->tdb == NULL) {
2268 fstrcpy(uname, name);
2271 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
2272 if (centry == NULL) {
2276 if (NT_STATUS_IS_OK(centry->status)) {
2277 *type = (enum SID_NAME_USE)centry_uint32(centry);
2278 centry_sid(centry, mem_ctx, sid);
2281 status = centry->status;
2282 centry_free(centry);
2284 return NT_STATUS_IS_OK(status);
2287 void cache_name2sid(struct winbindd_domain *domain,
2288 const char *domain_name, const char *name,
2289 enum SID_NAME_USE type, const DOM_SID *sid)
2291 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
2295 /* delete all centries that don't have NT_STATUS_OK set */
2296 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
2297 TDB_DATA dbuf, void *state)
2299 struct cache_entry *centry;
2301 centry = wcache_fetch_raw(kbuf.dptr);
2306 if (!NT_STATUS_IS_OK(centry->status)) {
2307 DEBUG(10,("deleting centry %s\n", kbuf.dptr));
2308 tdb_delete(the_tdb, kbuf);
2311 centry_free(centry);
2315 /* flush the cache */
2316 void wcache_flush_cache(void)
2318 extern BOOL opt_nocache;
2323 tdb_close(wcache->tdb);
2329 /* when working offline we must not clear the cache on restart */
2330 wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
2331 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2332 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
2333 O_RDWR|O_CREAT, 0600);
2336 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2340 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
2342 DEBUG(10,("wcache_flush_cache success\n"));
2345 /* Count cached creds */
2347 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2350 int *cred_count = (int*)state;
2352 if (strncmp(kbuf.dptr, "CRED/", 5) == 0) {
2358 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
2360 struct winbind_cache *cache = get_cache(domain);
2365 return NT_STATUS_INTERNAL_DB_ERROR;
2368 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
2370 return NT_STATUS_OK;
2374 struct cred_list *prev, *next;
2379 static struct cred_list *wcache_cred_list;
2381 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2384 struct cred_list *cred;
2386 if (strncmp(kbuf.dptr, "CRED/", 5) == 0) {
2388 cred = SMB_MALLOC_P(struct cred_list);
2390 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2396 /* save a copy of the key */
2398 fstrcpy(cred->name, kbuf.dptr);
2399 DLIST_ADD(wcache_cred_list, cred);
2405 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const DOM_SID *sid)
2407 struct winbind_cache *cache = get_cache(domain);
2410 struct cred_list *cred, *oldest = NULL;
2413 return NT_STATUS_INTERNAL_DB_ERROR;
2416 /* we possibly already have an entry */
2417 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
2421 DEBUG(11,("we already have an entry, deleting that\n"));
2423 fstr_sprintf(key_str, "CRED/%s", sid_string_static(sid));
2425 tdb_delete(cache->tdb, string_tdb_data(key_str));
2427 return NT_STATUS_OK;
2430 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
2432 return NT_STATUS_OK;
2433 } else if ((ret == -1) || (wcache_cred_list == NULL)) {
2434 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2437 ZERO_STRUCTP(oldest);
2439 for (cred = wcache_cred_list; cred; cred = cred->next) {
2444 data = tdb_fetch(cache->tdb, make_tdb_data(cred->name, strlen(cred->name)));
2446 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
2448 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
2452 t = IVAL(data.dptr, 0);
2453 SAFE_FREE(data.dptr);
2456 oldest = SMB_MALLOC_P(struct cred_list);
2457 if (oldest == NULL) {
2458 status = NT_STATUS_NO_MEMORY;
2462 fstrcpy(oldest->name, cred->name);
2463 oldest->created = t;
2467 if (t < oldest->created) {
2468 fstrcpy(oldest->name, cred->name);
2469 oldest->created = t;
2473 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
2474 status = NT_STATUS_OK;
2476 status = NT_STATUS_UNSUCCESSFUL;
2479 SAFE_FREE(wcache_cred_list);
2485 /* Change the global online/offline state. */
2486 BOOL set_global_winbindd_state_offline(void)
2491 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
2493 /* Only go offline if someone has created
2494 the key "WINBINDD_OFFLINE" in the cache tdb. */
2496 if (wcache == NULL || wcache->tdb == NULL) {
2497 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
2501 if (!lp_winbind_offline_logon()) {
2502 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
2506 if (global_winbindd_offline_state) {
2507 /* Already offline. */
2511 /* wcache->tdb->ecode = 0; */
2513 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
2515 /* As this is a key with no data we don't need to free, we
2516 check for existence by looking at tdb_err. */
2518 err = tdb_error(wcache->tdb);
2520 if (err == TDB_ERR_NOEXIST) {
2521 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
2524 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
2525 global_winbindd_offline_state = True;
2530 void set_global_winbindd_state_online(void)
2532 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
2534 if (!lp_winbind_offline_logon()) {
2535 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
2539 if (!global_winbindd_offline_state) {
2540 /* Already online. */
2543 global_winbindd_offline_state = False;
2549 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
2550 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
2553 BOOL get_global_winbindd_state_offline(void)
2555 return global_winbindd_offline_state;
2558 /* the cache backend methods are exposed via this structure */
2559 struct winbindd_methods cache_methods = {