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",
288 if (centry->len - centry->ofs < 16) {
289 DEBUG(0,("centry corruption? needed 16 bytes, have %d\n",
290 centry->len - centry->ofs));
294 ret = TALLOC_ARRAY(mem_ctx, char, 16);
296 smb_panic("centry_hash out of memory\n");
298 memcpy(ret,centry->data + centry->ofs, 16);
303 /* pull a sid from a cache entry, using the supplied
306 static BOOL centry_sid(struct cache_entry *centry, TALLOC_CTX *mem_ctx, DOM_SID *sid)
309 sid_string = centry_string(centry, mem_ctx);
310 if ((sid_string == NULL) || (!string_to_sid(sid, sid_string))) {
316 /* the server is considered down if it can't give us a sequence number */
317 static BOOL wcache_server_down(struct winbindd_domain *domain)
324 ret = (domain->sequence_number == DOM_SEQUENCE_NONE);
327 DEBUG(10,("wcache_server_down: server for Domain %s down\n",
332 static NTSTATUS fetch_cache_seqnum( struct winbindd_domain *domain, time_t now )
339 DEBUG(10,("fetch_cache_seqnum: tdb == NULL\n"));
340 return NT_STATUS_UNSUCCESSFUL;
343 fstr_sprintf( key, "SEQNUM/%s", domain->name );
345 data = tdb_fetch_bystring( wcache->tdb, key );
346 if ( !data.dptr || data.dsize!=8 ) {
347 DEBUG(10,("fetch_cache_seqnum: invalid data size key [%s]\n", key ));
348 return NT_STATUS_UNSUCCESSFUL;
351 domain->sequence_number = IVAL(data.dptr, 0);
352 domain->last_seq_check = IVAL(data.dptr, 4);
354 SAFE_FREE(data.dptr);
356 /* have we expired? */
358 time_diff = now - domain->last_seq_check;
359 if ( time_diff > lp_winbind_cache_time() ) {
360 DEBUG(10,("fetch_cache_seqnum: timeout [%s][%u @ %u]\n",
361 domain->name, domain->sequence_number,
362 (uint32)domain->last_seq_check));
363 return NT_STATUS_UNSUCCESSFUL;
366 DEBUG(10,("fetch_cache_seqnum: success [%s][%u @ %u]\n",
367 domain->name, domain->sequence_number,
368 (uint32)domain->last_seq_check));
373 static NTSTATUS store_cache_seqnum( struct winbindd_domain *domain )
380 DEBUG(10,("store_cache_seqnum: tdb == NULL\n"));
381 return NT_STATUS_UNSUCCESSFUL;
384 fstr_sprintf( key_str, "SEQNUM/%s", domain->name );
386 key.dsize = strlen(key_str)+1;
388 SIVAL(buf, 0, domain->sequence_number);
389 SIVAL(buf, 4, domain->last_seq_check);
393 if ( tdb_store( wcache->tdb, key, data, TDB_REPLACE) == -1 ) {
394 DEBUG(10,("store_cache_seqnum: tdb_store fail key [%s]\n", key_str ));
395 return NT_STATUS_UNSUCCESSFUL;
398 DEBUG(10,("store_cache_seqnum: success [%s][%u @ %u]\n",
399 domain->name, domain->sequence_number,
400 (uint32)domain->last_seq_check));
406 refresh the domain sequence number. If force is True
407 then always refresh it, no matter how recently we fetched it
410 static void refresh_sequence_number(struct winbindd_domain *domain, BOOL force)
414 time_t t = time(NULL);
415 unsigned cache_time = lp_winbind_cache_time();
419 #if 0 /* JERRY -- disable as the default cache time is now 5 minutes */
420 /* trying to reconnect is expensive, don't do it too often */
421 if (domain->sequence_number == DOM_SEQUENCE_NONE) {
426 time_diff = t - domain->last_seq_check;
428 /* see if we have to refetch the domain sequence number */
429 if (!force && (time_diff < cache_time)) {
430 DEBUG(10, ("refresh_sequence_number: %s time ok\n", domain->name));
434 /* try to get the sequence number from the tdb cache first */
435 /* this will update the timestamp as well */
437 status = fetch_cache_seqnum( domain, t );
438 if ( NT_STATUS_IS_OK(status) )
441 /* important! make sure that we know if this is a native
442 mode domain or not */
444 status = domain->backend->sequence_number(domain, &domain->sequence_number);
446 if (!NT_STATUS_IS_OK(status)) {
447 DEBUG(10,("refresh_sequence_number: failed with %s\n", nt_errstr(status)));
448 domain->sequence_number = DOM_SEQUENCE_NONE;
451 domain->last_status = status;
452 domain->last_seq_check = time(NULL);
454 /* save the new sequence number ni the cache */
455 store_cache_seqnum( domain );
458 DEBUG(10, ("refresh_sequence_number: %s seq number is now %d\n",
459 domain->name, domain->sequence_number));
465 decide if a cache entry has expired
467 static BOOL centry_expired(struct winbindd_domain *domain, const char *keystr, struct cache_entry *centry)
469 /* If we've been told to be offline - stay in that state... */
470 if (lp_winbind_offline_logon() && global_winbindd_offline_state) {
471 DEBUG(10,("centry_expired: Key %s for domain %s valid as winbindd is globally offline.\n",
472 keystr, domain->name ));
476 /* when the domain is offline return the cached entry.
477 * This deals with transient offline states... */
479 if (!domain->online) {
480 DEBUG(10,("centry_expired: Key %s for domain %s valid as domain is offline.\n",
481 keystr, domain->name ));
485 /* if the server is OK and our cache entry came from when it was down then
486 the entry is invalid */
487 if ((domain->sequence_number != DOM_SEQUENCE_NONE) &&
488 (centry->sequence_number == DOM_SEQUENCE_NONE)) {
489 DEBUG(10,("centry_expired: Key %s for domain %s invalid sequence.\n",
490 keystr, domain->name ));
494 /* if the server is down or the cache entry is not older than the
495 current sequence number then it is OK */
496 if (wcache_server_down(domain) ||
497 centry->sequence_number == domain->sequence_number) {
498 DEBUG(10,("centry_expired: Key %s for domain %s is good.\n",
499 keystr, domain->name ));
503 DEBUG(10,("centry_expired: Key %s for domain %s expired\n",
504 keystr, domain->name ));
510 static struct cache_entry *wcache_fetch_raw(char *kstr)
513 struct cache_entry *centry;
517 key.dsize = strlen(kstr);
518 data = tdb_fetch(wcache->tdb, key);
524 centry = SMB_XMALLOC_P(struct cache_entry);
525 centry->data = (unsigned char *)data.dptr;
526 centry->len = data.dsize;
529 if (centry->len < 8) {
530 /* huh? corrupt cache? */
531 DEBUG(10,("wcache_fetch_raw: Corrupt cache for key %s (len < 8) ?\n", kstr));
536 centry->status = NT_STATUS(centry_uint32(centry));
537 centry->sequence_number = centry_uint32(centry);
543 fetch an entry from the cache, with a varargs key. auto-fetch the sequence
544 number and return status
546 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
547 struct winbindd_domain *domain,
548 const char *format, ...) PRINTF_ATTRIBUTE(3,4);
549 static struct cache_entry *wcache_fetch(struct winbind_cache *cache,
550 struct winbindd_domain *domain,
551 const char *format, ...)
555 struct cache_entry *centry;
557 extern BOOL opt_nocache;
563 refresh_sequence_number(domain, False);
565 va_start(ap, format);
566 smb_xvasprintf(&kstr, format, ap);
569 centry = wcache_fetch_raw(kstr);
570 if (centry == NULL) {
575 if (centry_expired(domain, kstr, centry)) {
577 DEBUG(10,("wcache_fetch: entry %s expired for domain %s\n",
578 kstr, domain->name ));
585 DEBUG(10,("wcache_fetch: returning entry %s for domain %s\n",
586 kstr, domain->name ));
592 static void wcache_delete(const char *format, ...) PRINTF_ATTRIBUTE(1,2);
593 static void wcache_delete(const char *format, ...)
599 va_start(ap, format);
600 smb_xvasprintf(&kstr, format, ap);
604 key.dsize = strlen(kstr);
606 tdb_delete(wcache->tdb, key);
611 make sure we have at least len bytes available in a centry
613 static void centry_expand(struct cache_entry *centry, uint32 len)
615 if (centry->len - centry->ofs >= len)
618 centry->data = SMB_REALLOC_ARRAY(centry->data, unsigned char,
621 DEBUG(0,("out of memory: needed %d bytes in centry_expand\n", centry->len));
622 smb_panic("out of memory in centry_expand");
627 push a uint32 into a centry
629 static void centry_put_uint32(struct cache_entry *centry, uint32 v)
631 centry_expand(centry, 4);
632 SIVAL(centry->data, centry->ofs, v);
637 push a uint16 into a centry
639 static void centry_put_uint16(struct cache_entry *centry, uint16 v)
641 centry_expand(centry, 2);
642 SIVAL(centry->data, centry->ofs, v);
647 push a uint8 into a centry
649 static void centry_put_uint8(struct cache_entry *centry, uint8 v)
651 centry_expand(centry, 1);
652 SCVAL(centry->data, centry->ofs, v);
657 push a string into a centry
659 static void centry_put_string(struct cache_entry *centry, const char *s)
664 /* null strings are marked as len 0xFFFF */
665 centry_put_uint8(centry, 0xFF);
670 /* can't handle more than 254 char strings. Truncating is probably best */
672 DEBUG(10,("centry_put_string: truncating len (%d) to: 254\n", len));
675 centry_put_uint8(centry, len);
676 centry_expand(centry, len);
677 memcpy(centry->data + centry->ofs, s, len);
682 push a 16 byte hash into a centry - treat as 16 byte string.
684 static void centry_put_hash16(struct cache_entry *centry, const uint8 val[16])
686 centry_put_uint8(centry, 16);
687 centry_expand(centry, 16);
688 memcpy(centry->data + centry->ofs, val, 16);
692 static void centry_put_sid(struct cache_entry *centry, const DOM_SID *sid)
695 centry_put_string(centry, sid_to_string(sid_string, sid));
699 push a NTTIME into a centry
701 static void centry_put_nttime(struct cache_entry *centry, NTTIME nt)
703 centry_expand(centry, 8);
704 SIVAL(centry->data, centry->ofs, nt & 0xFFFFFFFF);
706 SIVAL(centry->data, centry->ofs, nt >> 32);
711 push a time_t into a centry
713 static void centry_put_time(struct cache_entry *centry, time_t t)
715 centry_expand(centry, sizeof(time_t));
716 SIVAL(centry->data, centry->ofs, t); /* FIXME: is this correct ?? */
717 centry->ofs += sizeof(time_t);
721 start a centry for output. When finished, call centry_end()
723 struct cache_entry *centry_start(struct winbindd_domain *domain, NTSTATUS status)
725 struct cache_entry *centry;
730 centry = SMB_XMALLOC_P(struct cache_entry);
732 centry->len = 8192; /* reasonable default */
733 centry->data = SMB_XMALLOC_ARRAY(uint8, centry->len);
735 centry->sequence_number = domain->sequence_number;
736 centry_put_uint32(centry, NT_STATUS_V(status));
737 centry_put_uint32(centry, centry->sequence_number);
742 finish a centry and write it to the tdb
744 static void centry_end(struct cache_entry *centry, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
745 static void centry_end(struct cache_entry *centry, const char *format, ...)
751 va_start(ap, format);
752 smb_xvasprintf(&kstr, format, ap);
756 key.dsize = strlen(kstr);
757 data.dptr = (char *)centry->data;
758 data.dsize = centry->ofs;
760 tdb_store(wcache->tdb, key, data, TDB_REPLACE);
764 static void wcache_save_name_to_sid(struct winbindd_domain *domain,
765 NTSTATUS status, const char *domain_name,
766 const char *name, const DOM_SID *sid,
767 enum lsa_SidType type)
769 struct cache_entry *centry;
772 centry = centry_start(domain, status);
775 centry_put_uint32(centry, type);
776 centry_put_sid(centry, sid);
777 fstrcpy(uname, name);
779 centry_end(centry, "NS/%s/%s", domain_name, uname);
780 DEBUG(10,("wcache_save_name_to_sid: %s\\%s -> %s\n", domain_name, uname,
781 sid_string_static(sid)));
785 static void wcache_save_sid_to_name(struct winbindd_domain *domain, NTSTATUS status,
786 const DOM_SID *sid, const char *domain_name, const char *name, enum lsa_SidType type)
788 struct cache_entry *centry;
791 centry = centry_start(domain, status);
794 if (NT_STATUS_IS_OK(status)) {
795 centry_put_uint32(centry, type);
796 centry_put_string(centry, domain_name);
797 centry_put_string(centry, name);
799 centry_end(centry, "SN/%s", sid_to_string(sid_string, sid));
800 DEBUG(10,("wcache_save_sid_to_name: %s -> %s\n", sid_string, name));
805 static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status, WINBIND_USERINFO *info)
807 struct cache_entry *centry;
810 centry = centry_start(domain, status);
813 centry_put_string(centry, info->acct_name);
814 centry_put_string(centry, info->full_name);
815 centry_put_string(centry, info->homedir);
816 centry_put_string(centry, info->shell);
817 centry_put_sid(centry, &info->user_sid);
818 centry_put_sid(centry, &info->group_sid);
819 centry_end(centry, "U/%s", sid_to_string(sid_string, &info->user_sid));
820 DEBUG(10,("wcache_save_user: %s (acct_name %s)\n", sid_string, info->acct_name));
824 static void wcache_save_lockout_policy(struct winbindd_domain *domain, NTSTATUS status, SAM_UNK_INFO_12 *lockout_policy)
826 struct cache_entry *centry;
828 centry = centry_start(domain, status);
832 centry_put_nttime(centry, lockout_policy->duration);
833 centry_put_nttime(centry, lockout_policy->reset_count);
834 centry_put_uint16(centry, lockout_policy->bad_attempt_lockout);
836 centry_end(centry, "LOC_POL/%s", domain->name);
838 DEBUG(10,("wcache_save_lockout_policy: %s\n", domain->name));
843 static void wcache_save_password_policy(struct winbindd_domain *domain, NTSTATUS status, SAM_UNK_INFO_1 *policy)
845 struct cache_entry *centry;
847 centry = centry_start(domain, status);
851 centry_put_uint16(centry, policy->min_length_password);
852 centry_put_uint16(centry, policy->password_history);
853 centry_put_uint32(centry, policy->password_properties);
854 centry_put_nttime(centry, policy->expire);
855 centry_put_nttime(centry, policy->min_passwordage);
857 centry_end(centry, "PWD_POL/%s", domain->name);
859 DEBUG(10,("wcache_save_password_policy: %s\n", domain->name));
864 NTSTATUS wcache_cached_creds_exist(struct winbindd_domain *domain, const DOM_SID *sid)
866 struct winbind_cache *cache = get_cache(domain);
872 return NT_STATUS_INTERNAL_DB_ERROR;
875 if (is_null_sid(sid)) {
876 return NT_STATUS_INVALID_SID;
879 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
880 return NT_STATUS_INVALID_SID;
883 fstr_sprintf(key_str, "CRED/%s", sid_string_static(sid));
885 data = tdb_fetch(cache->tdb, make_tdb_data(key_str, strlen(key_str)));
887 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
890 SAFE_FREE(data.dptr);
894 /* Lookup creds for a SID - copes with old (unsalted) creds as well
895 as new salted ones. */
897 NTSTATUS wcache_get_creds(struct winbindd_domain *domain,
900 const uint8 **cached_nt_pass,
901 const uint8 **cached_salt)
903 struct winbind_cache *cache = get_cache(domain);
904 struct cache_entry *centry = NULL;
910 return NT_STATUS_INTERNAL_DB_ERROR;
913 if (is_null_sid(sid)) {
914 return NT_STATUS_INVALID_SID;
917 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
918 return NT_STATUS_INVALID_SID;
921 /* Try and get a salted cred first. If we can't
922 fall back to an unsalted cred. */
924 centry = wcache_fetch(cache, domain, "CRED/%s", sid_string_static(sid));
926 DEBUG(10,("wcache_get_creds: entry for [CRED/%s] not found\n",
927 sid_string_static(sid)));
928 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
931 t = centry_time(centry);
933 /* In the salted case this isn't actually the nt_hash itself,
934 but the MD5 of the salt + nt_hash. Let the caller
935 sort this out. It can tell as we only return the cached_salt
936 if we are returning a salted cred. */
938 *cached_nt_pass = (const uint8 *)centry_hash16(centry, mem_ctx);
939 if (*cached_nt_pass == NULL) {
940 const char *sidstr = sid_string_static(sid);
942 /* Bad (old) cred cache. Delete and pretend we
944 DEBUG(0,("wcache_get_creds: bad entry for [CRED/%s] - deleting\n",
946 wcache_delete("CRED/%s", sidstr);
947 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
950 /* We only have 17 bytes more data in the salted cred case. */
951 if (centry->len - centry->ofs == 17) {
952 *cached_salt = (const uint8 *)centry_hash16(centry, mem_ctx);
958 dump_data(100, (const char *)*cached_nt_pass, NT_HASH_LEN);
960 dump_data(100, (const char *)*cached_salt, NT_HASH_LEN);
963 status = centry->status;
965 DEBUG(10,("wcache_get_creds: [Cached] - cached creds for user %s status: %s\n",
966 sid_string_static(sid), nt_errstr(status) ));
972 /* Store creds for a SID - only writes out new salted ones. */
974 NTSTATUS wcache_save_creds(struct winbindd_domain *domain,
977 const uint8 nt_pass[NT_HASH_LEN])
979 struct cache_entry *centry;
982 uint8 cred_salt[NT_HASH_LEN];
983 uint8 salted_hash[NT_HASH_LEN];
985 if (is_null_sid(sid)) {
986 return NT_STATUS_INVALID_SID;
989 if (!(sid_peek_rid(sid, &rid)) || (rid == 0)) {
990 return NT_STATUS_INVALID_SID;
993 centry = centry_start(domain, NT_STATUS_OK);
995 return NT_STATUS_INTERNAL_DB_ERROR;
999 dump_data(100, (const char *)nt_pass, NT_HASH_LEN);
1002 centry_put_time(centry, time(NULL));
1004 /* Create a salt and then salt the hash. */
1005 generate_random_buffer(cred_salt, NT_HASH_LEN);
1006 E_md5hash(cred_salt, nt_pass, salted_hash);
1008 centry_put_hash16(centry, salted_hash);
1009 centry_put_hash16(centry, cred_salt);
1010 centry_end(centry, "CRED/%s", sid_to_string(sid_string, sid));
1012 DEBUG(10,("wcache_save_creds: %s\n", sid_string));
1014 centry_free(centry);
1016 return NT_STATUS_OK;
1020 /* Query display info. This is the basic user list fn */
1021 static NTSTATUS query_user_list(struct winbindd_domain *domain,
1022 TALLOC_CTX *mem_ctx,
1023 uint32 *num_entries,
1024 WINBIND_USERINFO **info)
1026 struct winbind_cache *cache = get_cache(domain);
1027 struct cache_entry *centry = NULL;
1029 unsigned int i, retry;
1034 centry = wcache_fetch(cache, domain, "UL/%s", domain->name);
1038 *num_entries = centry_uint32(centry);
1040 if (*num_entries == 0)
1043 (*info) = TALLOC_ARRAY(mem_ctx, WINBIND_USERINFO, *num_entries);
1045 smb_panic("query_user_list out of memory");
1046 for (i=0; i<(*num_entries); i++) {
1047 (*info)[i].acct_name = centry_string(centry, mem_ctx);
1048 (*info)[i].full_name = centry_string(centry, mem_ctx);
1049 (*info)[i].homedir = centry_string(centry, mem_ctx);
1050 (*info)[i].shell = centry_string(centry, mem_ctx);
1051 centry_sid(centry, mem_ctx, &(*info)[i].user_sid);
1052 centry_sid(centry, mem_ctx, &(*info)[i].group_sid);
1056 status = centry->status;
1058 DEBUG(10,("query_user_list: [Cached] - cached list for domain %s status: %s\n",
1059 domain->name, nt_errstr(status) ));
1061 centry_free(centry);
1068 /* Return status value returned by seq number check */
1070 if (!NT_STATUS_IS_OK(domain->last_status))
1071 return domain->last_status;
1073 /* Put the query_user_list() in a retry loop. There appears to be
1074 * some bug either with Windows 2000 or Samba's handling of large
1075 * rpc replies. This manifests itself as sudden disconnection
1076 * at a random point in the enumeration of a large (60k) user list.
1077 * The retry loop simply tries the operation again. )-: It's not
1078 * pretty but an acceptable workaround until we work out what the
1079 * real problem is. */
1084 DEBUG(10,("query_user_list: [Cached] - doing backend query for list for domain %s\n",
1087 status = domain->backend->query_user_list(domain, mem_ctx, num_entries, info);
1088 if (!NT_STATUS_IS_OK(status))
1089 DEBUG(3, ("query_user_list: returned 0x%08x, "
1090 "retrying\n", NT_STATUS_V(status)));
1091 if (NT_STATUS_EQUAL(status, NT_STATUS_UNSUCCESSFUL)) {
1092 DEBUG(3, ("query_user_list: flushing "
1093 "connection cache\n"));
1094 invalidate_cm_connection(&domain->conn);
1097 } while (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) &&
1101 refresh_sequence_number(domain, False);
1102 centry = centry_start(domain, status);
1105 centry_put_uint32(centry, *num_entries);
1106 for (i=0; i<(*num_entries); i++) {
1107 centry_put_string(centry, (*info)[i].acct_name);
1108 centry_put_string(centry, (*info)[i].full_name);
1109 centry_put_string(centry, (*info)[i].homedir);
1110 centry_put_string(centry, (*info)[i].shell);
1111 centry_put_sid(centry, &(*info)[i].user_sid);
1112 centry_put_sid(centry, &(*info)[i].group_sid);
1113 if (domain->backend->consistent) {
1114 /* when the backend is consistent we can pre-prime some mappings */
1115 wcache_save_name_to_sid(domain, NT_STATUS_OK,
1117 (*info)[i].acct_name,
1118 &(*info)[i].user_sid,
1120 wcache_save_sid_to_name(domain, NT_STATUS_OK,
1121 &(*info)[i].user_sid,
1123 (*info)[i].acct_name,
1125 wcache_save_user(domain, NT_STATUS_OK, &(*info)[i]);
1128 centry_end(centry, "UL/%s", domain->name);
1129 centry_free(centry);
1135 /* list all domain groups */
1136 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
1137 TALLOC_CTX *mem_ctx,
1138 uint32 *num_entries,
1139 struct acct_info **info)
1141 struct winbind_cache *cache = get_cache(domain);
1142 struct cache_entry *centry = NULL;
1149 centry = wcache_fetch(cache, domain, "GL/%s/domain", domain->name);
1153 *num_entries = centry_uint32(centry);
1155 if (*num_entries == 0)
1158 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1160 smb_panic("enum_dom_groups out of memory");
1161 for (i=0; i<(*num_entries); i++) {
1162 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1163 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1164 (*info)[i].rid = centry_uint32(centry);
1168 status = centry->status;
1170 DEBUG(10,("enum_dom_groups: [Cached] - cached list for domain %s status: %s\n",
1171 domain->name, nt_errstr(status) ));
1173 centry_free(centry);
1180 /* Return status value returned by seq number check */
1182 if (!NT_STATUS_IS_OK(domain->last_status))
1183 return domain->last_status;
1185 DEBUG(10,("enum_dom_groups: [Cached] - doing backend query for list for domain %s\n",
1188 status = domain->backend->enum_dom_groups(domain, mem_ctx, num_entries, info);
1191 refresh_sequence_number(domain, False);
1192 centry = centry_start(domain, status);
1195 centry_put_uint32(centry, *num_entries);
1196 for (i=0; i<(*num_entries); i++) {
1197 centry_put_string(centry, (*info)[i].acct_name);
1198 centry_put_string(centry, (*info)[i].acct_desc);
1199 centry_put_uint32(centry, (*info)[i].rid);
1201 centry_end(centry, "GL/%s/domain", domain->name);
1202 centry_free(centry);
1208 /* list all domain groups */
1209 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
1210 TALLOC_CTX *mem_ctx,
1211 uint32 *num_entries,
1212 struct acct_info **info)
1214 struct winbind_cache *cache = get_cache(domain);
1215 struct cache_entry *centry = NULL;
1222 centry = wcache_fetch(cache, domain, "GL/%s/local", domain->name);
1226 *num_entries = centry_uint32(centry);
1228 if (*num_entries == 0)
1231 (*info) = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
1233 smb_panic("enum_dom_groups out of memory");
1234 for (i=0; i<(*num_entries); i++) {
1235 fstrcpy((*info)[i].acct_name, centry_string(centry, mem_ctx));
1236 fstrcpy((*info)[i].acct_desc, centry_string(centry, mem_ctx));
1237 (*info)[i].rid = centry_uint32(centry);
1242 /* If we are returning cached data and the domain controller
1243 is down then we don't know whether the data is up to date
1244 or not. Return NT_STATUS_MORE_PROCESSING_REQUIRED to
1247 if (wcache_server_down(domain)) {
1248 DEBUG(10, ("enum_local_groups: returning cached user list and server was down\n"));
1249 status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1251 status = centry->status;
1253 DEBUG(10,("enum_local_groups: [Cached] - cached list for domain %s status: %s\n",
1254 domain->name, nt_errstr(status) ));
1256 centry_free(centry);
1263 /* Return status value returned by seq number check */
1265 if (!NT_STATUS_IS_OK(domain->last_status))
1266 return domain->last_status;
1268 DEBUG(10,("enum_local_groups: [Cached] - doing backend query for list for domain %s\n",
1271 status = domain->backend->enum_local_groups(domain, mem_ctx, num_entries, info);
1274 refresh_sequence_number(domain, False);
1275 centry = centry_start(domain, status);
1278 centry_put_uint32(centry, *num_entries);
1279 for (i=0; i<(*num_entries); i++) {
1280 centry_put_string(centry, (*info)[i].acct_name);
1281 centry_put_string(centry, (*info)[i].acct_desc);
1282 centry_put_uint32(centry, (*info)[i].rid);
1284 centry_end(centry, "GL/%s/local", domain->name);
1285 centry_free(centry);
1291 /* convert a single name to a sid in a domain */
1292 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
1293 TALLOC_CTX *mem_ctx,
1294 const char *domain_name,
1297 enum lsa_SidType *type)
1299 struct winbind_cache *cache = get_cache(domain);
1300 struct cache_entry *centry = NULL;
1307 fstrcpy(uname, name);
1309 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
1312 *type = (enum lsa_SidType)centry_uint32(centry);
1313 status = centry->status;
1314 if (NT_STATUS_IS_OK(status)) {
1315 centry_sid(centry, mem_ctx, sid);
1318 DEBUG(10,("name_to_sid: [Cached] - cached name for domain %s status: %s\n",
1319 domain->name, nt_errstr(status) ));
1321 centry_free(centry);
1327 /* If the seq number check indicated that there is a problem
1328 * with this DC, then return that status... except for
1329 * access_denied. This is special because the dc may be in
1330 * "restrict anonymous = 1" mode, in which case it will deny
1331 * most unauthenticated operations, but *will* allow the LSA
1332 * name-to-sid that we try as a fallback. */
1334 if (!(NT_STATUS_IS_OK(domain->last_status)
1335 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1336 return domain->last_status;
1338 DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
1341 status = domain->backend->name_to_sid(domain, mem_ctx, domain_name, name, sid, type);
1344 if (domain->online && !is_null_sid(sid)) {
1345 wcache_save_name_to_sid(domain, status, domain_name, name, sid, *type);
1348 if (NT_STATUS_IS_OK(status)) {
1349 strupper_m(CONST_DISCARD(char *,domain_name));
1350 strlower_m(CONST_DISCARD(char *,name));
1351 wcache_save_sid_to_name(domain, status, sid, domain_name, name, *type);
1357 /* convert a sid to a user or group name. The sid is guaranteed to be in the domain
1359 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
1360 TALLOC_CTX *mem_ctx,
1364 enum lsa_SidType *type)
1366 struct winbind_cache *cache = get_cache(domain);
1367 struct cache_entry *centry = NULL;
1374 centry = wcache_fetch(cache, domain, "SN/%s", sid_to_string(sid_string, sid));
1377 if (NT_STATUS_IS_OK(centry->status)) {
1378 *type = (enum lsa_SidType)centry_uint32(centry);
1379 *domain_name = centry_string(centry, mem_ctx);
1380 *name = centry_string(centry, mem_ctx);
1382 status = centry->status;
1384 DEBUG(10,("sid_to_name: [Cached] - cached name for domain %s status: %s\n",
1385 domain->name, nt_errstr(status) ));
1387 centry_free(centry);
1392 *domain_name = NULL;
1394 /* If the seq number check indicated that there is a problem
1395 * with this DC, then return that status... except for
1396 * access_denied. This is special because the dc may be in
1397 * "restrict anonymous = 1" mode, in which case it will deny
1398 * most unauthenticated operations, but *will* allow the LSA
1399 * sid-to-name that we try as a fallback. */
1401 if (!(NT_STATUS_IS_OK(domain->last_status)
1402 || NT_STATUS_EQUAL(domain->last_status, NT_STATUS_ACCESS_DENIED)))
1403 return domain->last_status;
1405 DEBUG(10,("sid_to_name: [Cached] - doing backend query for name for domain %s\n",
1408 status = domain->backend->sid_to_name(domain, mem_ctx, sid, domain_name, name, type);
1411 refresh_sequence_number(domain, False);
1412 wcache_save_sid_to_name(domain, status, sid, *domain_name, *name, *type);
1414 /* We can't save the name to sid mapping here, as with sid history a
1415 * later name2sid would give the wrong sid. */
1420 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
1421 TALLOC_CTX *mem_ctx,
1422 const DOM_SID *domain_sid,
1427 enum lsa_SidType **types)
1429 struct winbind_cache *cache = get_cache(domain);
1431 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1435 *domain_name = NULL;
1443 if (num_rids == 0) {
1444 return NT_STATUS_OK;
1447 *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
1448 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
1450 if ((*names == NULL) || (*types == NULL)) {
1451 result = NT_STATUS_NO_MEMORY;
1455 have_mapped = have_unmapped = False;
1457 for (i=0; i<num_rids; i++) {
1459 struct cache_entry *centry;
1461 if (!sid_compose(&sid, domain_sid, rids[i])) {
1462 result = NT_STATUS_INTERNAL_ERROR;
1466 centry = wcache_fetch(cache, domain, "SN/%s",
1467 sid_string_static(&sid));
1472 (*types)[i] = SID_NAME_UNKNOWN;
1473 (*names)[i] = talloc_strdup(*names, "");
1475 if (NT_STATUS_IS_OK(centry->status)) {
1478 (*types)[i] = (enum lsa_SidType)centry_uint32(centry);
1479 dom = centry_string(centry, mem_ctx);
1480 if (*domain_name == NULL) {
1485 (*names)[i] = centry_string(centry, *names);
1487 have_unmapped = True;
1490 centry_free(centry);
1494 return NT_STATUS_NONE_MAPPED;
1496 if (!have_unmapped) {
1497 return NT_STATUS_OK;
1499 return STATUS_SOME_UNMAPPED;
1503 TALLOC_FREE(*names);
1504 TALLOC_FREE(*types);
1506 result = domain->backend->rids_to_names(domain, mem_ctx, domain_sid,
1507 rids, num_rids, domain_name,
1510 if (!NT_STATUS_IS_OK(result) &&
1511 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
1515 refresh_sequence_number(domain, False);
1517 for (i=0; i<num_rids; i++) {
1521 if (!sid_compose(&sid, domain_sid, rids[i])) {
1522 result = NT_STATUS_INTERNAL_ERROR;
1526 status = (*types)[i] == SID_NAME_UNKNOWN ?
1527 NT_STATUS_NONE_MAPPED : NT_STATUS_OK;
1529 wcache_save_sid_to_name(domain, status, &sid, *domain_name,
1530 (*names)[i], (*types)[i]);
1537 TALLOC_FREE(*names);
1538 TALLOC_FREE(*types);
1542 /* Lookup user information from a rid */
1543 static NTSTATUS query_user(struct winbindd_domain *domain,
1544 TALLOC_CTX *mem_ctx,
1545 const DOM_SID *user_sid,
1546 WINBIND_USERINFO *info)
1548 struct winbind_cache *cache = get_cache(domain);
1549 struct cache_entry *centry = NULL;
1555 centry = wcache_fetch(cache, domain, "U/%s", sid_string_static(user_sid));
1557 /* If we have an access denied cache entry and a cached info3 in the
1558 samlogon cache then do a query. This will force the rpc back end
1559 to return the info3 data. */
1561 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1562 netsamlogon_cache_have(user_sid)) {
1563 DEBUG(10, ("query_user: cached access denied and have cached info3\n"));
1564 domain->last_status = NT_STATUS_OK;
1565 centry_free(centry);
1572 info->acct_name = centry_string(centry, mem_ctx);
1573 info->full_name = centry_string(centry, mem_ctx);
1574 info->homedir = centry_string(centry, mem_ctx);
1575 info->shell = centry_string(centry, mem_ctx);
1576 centry_sid(centry, mem_ctx, &info->user_sid);
1577 centry_sid(centry, mem_ctx, &info->group_sid);
1578 status = centry->status;
1580 DEBUG(10,("query_user: [Cached] - cached info for domain %s status: %s\n",
1581 domain->name, nt_errstr(status) ));
1583 centry_free(centry);
1589 /* Return status value returned by seq number check */
1591 if (!NT_STATUS_IS_OK(domain->last_status))
1592 return domain->last_status;
1594 DEBUG(10,("sid_to_name: [Cached] - doing backend query for info for domain %s\n",
1597 status = domain->backend->query_user(domain, mem_ctx, user_sid, info);
1600 refresh_sequence_number(domain, False);
1601 wcache_save_user(domain, status, info);
1607 /* Lookup groups a user is a member of. */
1608 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
1609 TALLOC_CTX *mem_ctx,
1610 const DOM_SID *user_sid,
1611 uint32 *num_groups, DOM_SID **user_gids)
1613 struct winbind_cache *cache = get_cache(domain);
1614 struct cache_entry *centry = NULL;
1622 centry = wcache_fetch(cache, domain, "UG/%s", sid_to_string(sid_string, user_sid));
1624 /* If we have an access denied cache entry and a cached info3 in the
1625 samlogon cache then do a query. This will force the rpc back end
1626 to return the info3 data. */
1628 if (NT_STATUS_V(domain->last_status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED) &&
1629 netsamlogon_cache_have(user_sid)) {
1630 DEBUG(10, ("lookup_usergroups: cached access denied and have cached info3\n"));
1631 domain->last_status = NT_STATUS_OK;
1632 centry_free(centry);
1639 *num_groups = centry_uint32(centry);
1641 if (*num_groups == 0)
1644 (*user_gids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
1646 smb_panic("lookup_usergroups out of memory");
1647 for (i=0; i<(*num_groups); i++) {
1648 centry_sid(centry, mem_ctx, &(*user_gids)[i]);
1652 status = centry->status;
1654 DEBUG(10,("lookup_usergroups: [Cached] - cached info for domain %s status: %s\n",
1655 domain->name, nt_errstr(status) ));
1657 centry_free(centry);
1662 (*user_gids) = NULL;
1664 /* Return status value returned by seq number check */
1666 if (!NT_STATUS_IS_OK(domain->last_status))
1667 return domain->last_status;
1669 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info for domain %s\n",
1672 status = domain->backend->lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids);
1675 refresh_sequence_number(domain, False);
1676 centry = centry_start(domain, status);
1679 centry_put_uint32(centry, *num_groups);
1680 for (i=0; i<(*num_groups); i++) {
1681 centry_put_sid(centry, &(*user_gids)[i]);
1683 centry_end(centry, "UG/%s", sid_to_string(sid_string, user_sid));
1684 centry_free(centry);
1690 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
1691 TALLOC_CTX *mem_ctx,
1692 uint32 num_sids, const DOM_SID *sids,
1693 uint32 *num_aliases, uint32 **alias_rids)
1695 struct winbind_cache *cache = get_cache(domain);
1696 struct cache_entry *centry = NULL;
1698 char *sidlist = talloc_strdup(mem_ctx, "");
1704 if (num_sids == 0) {
1707 return NT_STATUS_OK;
1710 /* We need to cache indexed by the whole list of SIDs, the aliases
1711 * resulting might come from any of the SIDs. */
1713 for (i=0; i<num_sids; i++) {
1714 sidlist = talloc_asprintf(mem_ctx, "%s/%s", sidlist,
1715 sid_string_static(&sids[i]));
1716 if (sidlist == NULL)
1717 return NT_STATUS_NO_MEMORY;
1720 centry = wcache_fetch(cache, domain, "UA%s", sidlist);
1725 *num_aliases = centry_uint32(centry);
1728 (*alias_rids) = TALLOC_ARRAY(mem_ctx, uint32, *num_aliases);
1730 if ((*num_aliases != 0) && ((*alias_rids) == NULL)) {
1731 centry_free(centry);
1732 return NT_STATUS_NO_MEMORY;
1735 for (i=0; i<(*num_aliases); i++)
1736 (*alias_rids)[i] = centry_uint32(centry);
1738 status = centry->status;
1740 DEBUG(10,("lookup_useraliases: [Cached] - cached info for domain: %s "
1741 "status %s\n", domain->name, nt_errstr(status)));
1743 centry_free(centry);
1748 (*alias_rids) = NULL;
1750 if (!NT_STATUS_IS_OK(domain->last_status))
1751 return domain->last_status;
1753 DEBUG(10,("lookup_usergroups: [Cached] - doing backend query for info "
1754 "for domain %s\n", domain->name ));
1756 status = domain->backend->lookup_useraliases(domain, mem_ctx,
1758 num_aliases, alias_rids);
1761 refresh_sequence_number(domain, False);
1762 centry = centry_start(domain, status);
1765 centry_put_uint32(centry, *num_aliases);
1766 for (i=0; i<(*num_aliases); i++)
1767 centry_put_uint32(centry, (*alias_rids)[i]);
1768 centry_end(centry, "UA%s", sidlist);
1769 centry_free(centry);
1776 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1777 TALLOC_CTX *mem_ctx,
1778 const DOM_SID *group_sid, uint32 *num_names,
1779 DOM_SID **sid_mem, char ***names,
1780 uint32 **name_types)
1782 struct winbind_cache *cache = get_cache(domain);
1783 struct cache_entry *centry = NULL;
1791 centry = wcache_fetch(cache, domain, "GM/%s", sid_to_string(sid_string, group_sid));
1795 *num_names = centry_uint32(centry);
1797 if (*num_names == 0)
1800 (*sid_mem) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_names);
1801 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_names);
1802 (*name_types) = TALLOC_ARRAY(mem_ctx, uint32, *num_names);
1804 if (! (*sid_mem) || ! (*names) || ! (*name_types)) {
1805 smb_panic("lookup_groupmem out of memory");
1808 for (i=0; i<(*num_names); i++) {
1809 centry_sid(centry, mem_ctx, &(*sid_mem)[i]);
1810 (*names)[i] = centry_string(centry, mem_ctx);
1811 (*name_types)[i] = centry_uint32(centry);
1815 status = centry->status;
1817 DEBUG(10,("lookup_groupmem: [Cached] - cached info for domain %s status: %s\n",
1818 domain->name, nt_errstr(status)));
1820 centry_free(centry);
1827 (*name_types) = NULL;
1829 /* Return status value returned by seq number check */
1831 if (!NT_STATUS_IS_OK(domain->last_status))
1832 return domain->last_status;
1834 DEBUG(10,("lookup_groupmem: [Cached] - doing backend query for info for domain %s\n",
1837 status = domain->backend->lookup_groupmem(domain, mem_ctx, group_sid, num_names,
1838 sid_mem, names, name_types);
1841 refresh_sequence_number(domain, False);
1842 centry = centry_start(domain, status);
1845 centry_put_uint32(centry, *num_names);
1846 for (i=0; i<(*num_names); i++) {
1847 centry_put_sid(centry, &(*sid_mem)[i]);
1848 centry_put_string(centry, (*names)[i]);
1849 centry_put_uint32(centry, (*name_types)[i]);
1851 centry_end(centry, "GM/%s", sid_to_string(sid_string, group_sid));
1852 centry_free(centry);
1858 /* find the sequence number for a domain */
1859 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
1861 refresh_sequence_number(domain, False);
1863 *seq = domain->sequence_number;
1865 return NT_STATUS_OK;
1868 /* enumerate trusted domains
1869 * (we need to have the list of trustdoms in the cache when we go offline) -
1871 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1872 TALLOC_CTX *mem_ctx,
1873 uint32 *num_domains,
1878 struct winbind_cache *cache = get_cache(domain);
1879 struct cache_entry *centry = NULL;
1886 centry = wcache_fetch(cache, domain, "TRUSTDOMS/%s", domain->name);
1892 *num_domains = centry_uint32(centry);
1894 (*names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
1895 (*alt_names) = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
1896 (*dom_sids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
1898 if (! (*dom_sids) || ! (*names) || ! (*alt_names)) {
1899 smb_panic("trusted_domains out of memory");
1902 for (i=0; i<(*num_domains); i++) {
1903 (*names)[i] = centry_string(centry, mem_ctx);
1904 (*alt_names)[i] = centry_string(centry, mem_ctx);
1905 centry_sid(centry, mem_ctx, &(*dom_sids)[i]);
1908 status = centry->status;
1910 DEBUG(10,("trusted_domains: [Cached] - cached info for domain %s (%d trusts) status: %s\n",
1911 domain->name, *num_domains, nt_errstr(status) ));
1913 centry_free(centry);
1920 (*alt_names) = NULL;
1922 /* Return status value returned by seq number check */
1924 if (!NT_STATUS_IS_OK(domain->last_status))
1925 return domain->last_status;
1927 DEBUG(10,("trusted_domains: [Cached] - doing backend query for info for domain %s\n",
1930 status = domain->backend->trusted_domains(domain, mem_ctx, num_domains,
1931 names, alt_names, dom_sids);
1933 /* no trusts gives NT_STATUS_NO_MORE_ENTRIES resetting to NT_STATUS_OK
1934 * so that the generic centry handling still applies correctly -
1937 if (!NT_STATUS_IS_ERR(status)) {
1938 status = NT_STATUS_OK;
1942 refresh_sequence_number(domain, False);
1944 centry = centry_start(domain, status);
1948 centry_put_uint32(centry, *num_domains);
1950 for (i=0; i<(*num_domains); i++) {
1951 centry_put_string(centry, (*names)[i]);
1952 centry_put_string(centry, (*alt_names)[i]);
1953 centry_put_sid(centry, &(*dom_sids)[i]);
1956 centry_end(centry, "TRUSTDOMS/%s", domain->name);
1958 centry_free(centry);
1964 /* get lockout policy */
1965 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
1966 TALLOC_CTX *mem_ctx,
1967 SAM_UNK_INFO_12 *policy){
1968 struct winbind_cache *cache = get_cache(domain);
1969 struct cache_entry *centry = NULL;
1975 centry = wcache_fetch(cache, domain, "LOC_POL/%s", domain->name);
1980 policy->duration = centry_nttime(centry);
1981 policy->reset_count = centry_nttime(centry);
1982 policy->bad_attempt_lockout = centry_uint16(centry);
1984 status = centry->status;
1986 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
1987 domain->name, nt_errstr(status) ));
1989 centry_free(centry);
1993 ZERO_STRUCTP(policy);
1995 /* Return status value returned by seq number check */
1997 if (!NT_STATUS_IS_OK(domain->last_status))
1998 return domain->last_status;
2000 DEBUG(10,("lockout_policy: [Cached] - doing backend query for info for domain %s\n",
2003 status = domain->backend->lockout_policy(domain, mem_ctx, policy);
2006 refresh_sequence_number(domain, False);
2007 wcache_save_lockout_policy(domain, status, policy);
2012 /* get password policy */
2013 static NTSTATUS password_policy(struct winbindd_domain *domain,
2014 TALLOC_CTX *mem_ctx,
2015 SAM_UNK_INFO_1 *policy)
2017 struct winbind_cache *cache = get_cache(domain);
2018 struct cache_entry *centry = NULL;
2024 centry = wcache_fetch(cache, domain, "PWD_POL/%s", domain->name);
2029 policy->min_length_password = centry_uint16(centry);
2030 policy->password_history = centry_uint16(centry);
2031 policy->password_properties = centry_uint32(centry);
2032 policy->expire = centry_nttime(centry);
2033 policy->min_passwordage = centry_nttime(centry);
2035 status = centry->status;
2037 DEBUG(10,("lockout_policy: [Cached] - cached info for domain %s status: %s\n",
2038 domain->name, nt_errstr(status) ));
2040 centry_free(centry);
2044 ZERO_STRUCTP(policy);
2046 /* Return status value returned by seq number check */
2048 if (!NT_STATUS_IS_OK(domain->last_status))
2049 return domain->last_status;
2051 DEBUG(10,("password_policy: [Cached] - doing backend query for info for domain %s\n",
2054 status = domain->backend->password_policy(domain, mem_ctx, policy);
2057 refresh_sequence_number(domain, False);
2058 wcache_save_password_policy(domain, status, policy);
2064 /* Invalidate cached user and group lists coherently */
2066 static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2069 if (strncmp(kbuf.dptr, "UL/", 3) == 0 ||
2070 strncmp(kbuf.dptr, "GL/", 3) == 0)
2071 tdb_delete(the_tdb, kbuf);
2076 /* Invalidate the getpwnam and getgroups entries for a winbindd domain */
2078 void wcache_invalidate_samlogon(struct winbindd_domain *domain,
2079 NET_USER_INFO_3 *info3)
2081 struct winbind_cache *cache;
2086 cache = get_cache(domain);
2087 netsamlogon_clear_cached_user(cache->tdb, info3);
2090 void wcache_invalidate_cache(void)
2092 struct winbindd_domain *domain;
2094 for (domain = domain_list(); domain; domain = domain->next) {
2095 struct winbind_cache *cache = get_cache(domain);
2097 DEBUG(10, ("wcache_invalidate_cache: invalidating cache "
2098 "entries for %s\n", domain->name));
2100 tdb_traverse(cache->tdb, traverse_fn, NULL);
2104 static BOOL init_wcache(void)
2106 if (wcache == NULL) {
2107 wcache = SMB_XMALLOC_P(struct winbind_cache);
2108 ZERO_STRUCTP(wcache);
2111 if (wcache->tdb != NULL)
2114 /* when working offline we must not clear the cache on restart */
2115 wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
2116 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2117 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
2118 O_RDWR|O_CREAT, 0600);
2120 if (wcache->tdb == NULL) {
2121 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2128 void cache_store_response(pid_t pid, struct winbindd_response *response)
2135 DEBUG(10, ("Storing response for pid %d, len %d\n",
2136 pid, response->length));
2138 fstr_sprintf(key_str, "DR/%d", pid);
2139 if (tdb_store(wcache->tdb, string_tdb_data(key_str),
2140 make_tdb_data((const char *)response, sizeof(*response)),
2144 if (response->length == sizeof(*response))
2147 /* There's extra data */
2149 DEBUG(10, ("Storing extra data: len=%d\n",
2150 (int)(response->length - sizeof(*response))));
2152 fstr_sprintf(key_str, "DE/%d", pid);
2153 if (tdb_store(wcache->tdb, string_tdb_data(key_str),
2154 make_tdb_data((const char *)response->extra_data.data,
2155 response->length - sizeof(*response)),
2159 /* We could not store the extra data, make sure the tdb does not
2160 * contain a main record with wrong dangling extra data */
2162 fstr_sprintf(key_str, "DR/%d", pid);
2163 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2168 BOOL cache_retrieve_response(pid_t pid, struct winbindd_response * response)
2176 DEBUG(10, ("Retrieving response for pid %d\n", pid));
2178 fstr_sprintf(key_str, "DR/%d", pid);
2179 data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
2181 if (data.dptr == NULL)
2184 if (data.dsize != sizeof(*response))
2187 memcpy(response, data.dptr, data.dsize);
2188 SAFE_FREE(data.dptr);
2190 if (response->length == sizeof(*response)) {
2191 response->extra_data.data = NULL;
2195 /* There's extra data */
2197 DEBUG(10, ("Retrieving extra data length=%d\n",
2198 (int)(response->length - sizeof(*response))));
2200 fstr_sprintf(key_str, "DE/%d", pid);
2201 data = tdb_fetch(wcache->tdb, string_tdb_data(key_str));
2203 if (data.dptr == NULL) {
2204 DEBUG(0, ("Did not find extra data\n"));
2208 if (data.dsize != (response->length - sizeof(*response))) {
2209 DEBUG(0, ("Invalid extra data length: %d\n", (int)data.dsize));
2210 SAFE_FREE(data.dptr);
2214 dump_data(11, data.dptr, data.dsize);
2216 response->extra_data.data = data.dptr;
2220 void cache_cleanup_response(pid_t pid)
2227 fstr_sprintf(key_str, "DR/%d", pid);
2228 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2230 fstr_sprintf(key_str, "DE/%d", pid);
2231 tdb_delete(wcache->tdb, string_tdb_data(key_str));
2237 BOOL lookup_cached_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
2238 const char **domain_name, const char **name,
2239 enum lsa_SidType *type)
2241 struct winbindd_domain *domain;
2242 struct winbind_cache *cache;
2243 struct cache_entry *centry = NULL;
2246 domain = find_lookup_domain_from_sid(sid);
2247 if (domain == NULL) {
2251 cache = get_cache(domain);
2253 if (cache->tdb == NULL) {
2257 centry = wcache_fetch(cache, domain, "SN/%s", sid_string_static(sid));
2258 if (centry == NULL) {
2262 if (NT_STATUS_IS_OK(centry->status)) {
2263 *type = (enum lsa_SidType)centry_uint32(centry);
2264 *domain_name = centry_string(centry, mem_ctx);
2265 *name = centry_string(centry, mem_ctx);
2268 status = centry->status;
2269 centry_free(centry);
2270 return NT_STATUS_IS_OK(status);
2273 BOOL lookup_cached_name(TALLOC_CTX *mem_ctx,
2274 const char *domain_name,
2277 enum lsa_SidType *type)
2279 struct winbindd_domain *domain;
2280 struct winbind_cache *cache;
2281 struct cache_entry *centry = NULL;
2285 domain = find_lookup_domain_from_name(domain_name);
2286 if (domain == NULL) {
2290 cache = get_cache(domain);
2292 if (cache->tdb == NULL) {
2296 fstrcpy(uname, name);
2299 centry = wcache_fetch(cache, domain, "NS/%s/%s", domain_name, uname);
2300 if (centry == NULL) {
2304 if (NT_STATUS_IS_OK(centry->status)) {
2305 *type = (enum lsa_SidType)centry_uint32(centry);
2306 centry_sid(centry, mem_ctx, sid);
2309 status = centry->status;
2310 centry_free(centry);
2312 return NT_STATUS_IS_OK(status);
2315 void cache_name2sid(struct winbindd_domain *domain,
2316 const char *domain_name, const char *name,
2317 enum lsa_SidType type, const DOM_SID *sid)
2319 wcache_save_name_to_sid(domain, NT_STATUS_OK, domain_name, name,
2323 /* delete all centries that don't have NT_STATUS_OK set */
2324 static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf,
2325 TDB_DATA dbuf, void *state)
2327 struct cache_entry *centry;
2329 centry = wcache_fetch_raw(kbuf.dptr);
2334 if (!NT_STATUS_IS_OK(centry->status)) {
2335 DEBUG(10,("deleting centry %s\n", kbuf.dptr));
2336 tdb_delete(the_tdb, kbuf);
2339 centry_free(centry);
2343 /* flush the cache */
2344 void wcache_flush_cache(void)
2346 extern BOOL opt_nocache;
2351 tdb_close(wcache->tdb);
2357 /* when working offline we must not clear the cache on restart */
2358 wcache->tdb = tdb_open_log(lock_path("winbindd_cache.tdb"),
2359 WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
2360 lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
2361 O_RDWR|O_CREAT, 0600);
2364 DEBUG(0,("Failed to open winbindd_cache.tdb!\n"));
2368 tdb_traverse(wcache->tdb, traverse_fn_cleanup, NULL);
2370 DEBUG(10,("wcache_flush_cache success\n"));
2373 /* Count cached creds */
2375 static int traverse_fn_cached_creds(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2378 int *cred_count = (int*)state;
2380 if (strncmp(kbuf.dptr, "CRED/", 5) == 0) {
2386 NTSTATUS wcache_count_cached_creds(struct winbindd_domain *domain, int *count)
2388 struct winbind_cache *cache = get_cache(domain);
2393 return NT_STATUS_INTERNAL_DB_ERROR;
2396 tdb_traverse(cache->tdb, traverse_fn_cached_creds, (void *)count);
2398 return NT_STATUS_OK;
2402 struct cred_list *prev, *next;
2407 static struct cred_list *wcache_cred_list;
2409 static int traverse_fn_get_credlist(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
2412 struct cred_list *cred;
2414 if (strncmp(kbuf.dptr, "CRED/", 5) == 0) {
2416 cred = SMB_MALLOC_P(struct cred_list);
2418 DEBUG(0,("traverse_fn_remove_first_creds: failed to malloc new entry for list\n"));
2424 /* save a copy of the key */
2426 fstrcpy(cred->name, kbuf.dptr);
2427 DLIST_ADD(wcache_cred_list, cred);
2433 NTSTATUS wcache_remove_oldest_cached_creds(struct winbindd_domain *domain, const DOM_SID *sid)
2435 struct winbind_cache *cache = get_cache(domain);
2438 struct cred_list *cred, *oldest = NULL;
2441 return NT_STATUS_INTERNAL_DB_ERROR;
2444 /* we possibly already have an entry */
2445 if (sid && NT_STATUS_IS_OK(wcache_cached_creds_exist(domain, sid))) {
2449 DEBUG(11,("we already have an entry, deleting that\n"));
2451 fstr_sprintf(key_str, "CRED/%s", sid_string_static(sid));
2453 tdb_delete(cache->tdb, string_tdb_data(key_str));
2455 return NT_STATUS_OK;
2458 ret = tdb_traverse(cache->tdb, traverse_fn_get_credlist, NULL);
2460 return NT_STATUS_OK;
2461 } else if ((ret == -1) || (wcache_cred_list == NULL)) {
2462 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2465 ZERO_STRUCTP(oldest);
2467 for (cred = wcache_cred_list; cred; cred = cred->next) {
2472 data = tdb_fetch(cache->tdb, make_tdb_data(cred->name, strlen(cred->name)));
2474 DEBUG(10,("wcache_remove_oldest_cached_creds: entry for [%s] not found\n",
2476 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
2480 t = IVAL(data.dptr, 0);
2481 SAFE_FREE(data.dptr);
2484 oldest = SMB_MALLOC_P(struct cred_list);
2485 if (oldest == NULL) {
2486 status = NT_STATUS_NO_MEMORY;
2490 fstrcpy(oldest->name, cred->name);
2491 oldest->created = t;
2495 if (t < oldest->created) {
2496 fstrcpy(oldest->name, cred->name);
2497 oldest->created = t;
2501 if (tdb_delete(cache->tdb, string_tdb_data(oldest->name)) == 0) {
2502 status = NT_STATUS_OK;
2504 status = NT_STATUS_UNSUCCESSFUL;
2507 SAFE_FREE(wcache_cred_list);
2513 /* Change the global online/offline state. */
2514 BOOL set_global_winbindd_state_offline(void)
2519 DEBUG(10,("set_global_winbindd_state_offline: offline requested.\n"));
2521 /* Only go offline if someone has created
2522 the key "WINBINDD_OFFLINE" in the cache tdb. */
2524 if (wcache == NULL || wcache->tdb == NULL) {
2525 DEBUG(10,("set_global_winbindd_state_offline: wcache not open yet.\n"));
2529 if (!lp_winbind_offline_logon()) {
2530 DEBUG(10,("set_global_winbindd_state_offline: rejecting.\n"));
2534 if (global_winbindd_offline_state) {
2535 /* Already offline. */
2539 /* wcache->tdb->ecode = 0; */
2541 data = tdb_fetch_bystring( wcache->tdb, "WINBINDD_OFFLINE" );
2543 /* As this is a key with no data we don't need to free, we
2544 check for existence by looking at tdb_err. */
2546 err = tdb_error(wcache->tdb);
2548 if (err == TDB_ERR_NOEXIST) {
2549 DEBUG(10,("set_global_winbindd_state_offline: offline state not set.\n"));
2552 DEBUG(10,("set_global_winbindd_state_offline: offline state set.\n"));
2553 global_winbindd_offline_state = True;
2558 void set_global_winbindd_state_online(void)
2560 DEBUG(10,("set_global_winbindd_state_online: online requested.\n"));
2562 if (!lp_winbind_offline_logon()) {
2563 DEBUG(10,("set_global_winbindd_state_online: rejecting.\n"));
2567 if (!global_winbindd_offline_state) {
2568 /* Already online. */
2571 global_winbindd_offline_state = False;
2577 /* Ensure there is no key "WINBINDD_OFFLINE" in the cache tdb. */
2578 tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE");
2581 BOOL get_global_winbindd_state_offline(void)
2583 return global_winbindd_offline_state;
2586 /* the cache backend methods are exposed via this structure */
2587 struct winbindd_methods cache_methods = {